[glib/wip/rancell/iso8601-2] REFACTOR



commit b470d1b457b63795a52dd4d575ccb213d21f64e0
Author: Robert Ancell <robert ancell canonical com>
Date:   Sat Jun 24 20:17:47 2017 +1200

    REFACTOR

 glib/gdatetime.c       |  136 +++++++++++++++++++++++++----------------------
 glib/tests/gdatetime.c |    5 ++-
 2 files changed, 76 insertions(+), 65 deletions(-)
---
diff --git a/glib/gdatetime.c b/glib/gdatetime.c
index b5aaa2e..481a057 100644
--- a/glib/gdatetime.c
+++ b/glib/gdatetime.c
@@ -952,100 +952,111 @@ get_iso8601_seconds (const gchar *text, gint length, gdouble *value)
   return TRUE;
 }
 
-static gboolean
-convert_from_iso8601_ordinal (gint year, gint ordinal_day, gint *month, gint *day)
+static GDateTime *
+g_date_time_new_ordinal (GTimeZone *tz, gint year, gint ordinal_day, gint hour, gint minute, gint seconds)
 {
-  gint m;
+  GDateTime *dt;
 
-  if (ordinal_day < 1)
-    return FALSE;
+  if (ordinal_day < 1 || ordinal_day > (GREGORIAN_LEAP (year) ? 366 : 365))
+    return NULL;
 
-  for (m = 1; m <= 12; m++)
-    {
-      if (ordinal_day <= days_in_year[GREGORIAN_LEAP (year)][m])
-        {
-          *month = m;
-          *day = ordinal_day - days_in_year[GREGORIAN_LEAP (year)][m - 1];
-          return TRUE;
-        }
-    }
+  dt = g_date_time_new (tz, year, 1, 1, hour, minute, seconds);
+  dt->days += ordinal_day - 1;
 
-  return FALSE;
+  return dt;
 }
 
-static gboolean
-convert_from_iso8601_week (gint year, gint week, gint week_day, gint *offset)
+static GDateTime *
+g_date_time_new_week (GTimeZone *tz, gint year, gint week, gint week_day, gint hour, gint minute, gint 
seconds)
 {
-  gint days, week_offset;
+  gint64 p;
+  gint max_week, jan4_week_day, ordinal_day;
+  GDateTime *dt;
 
-  if (week < 1 || week > 52 || week_day < 1 || week_day > 7)
-    return FALSE;
+  p = (year * 365 + (year / 4) - (year / 100) + (year / 400)) % 7;
+  max_week = p == 4 ? 53 : 52;
+
+  if (week < 1 || week > max_week || week_day < 1 || week_day > 7)
+    return NULL;
 
-  /* Work out the day week one starts on */
-  days = ymd_to_days (year, 1, 1);
-  week_offset = -(days % 7);
-  if (week_offset < -3)
-    week_offset += 7;
+  dt = g_date_time_new (tz, year, 1, 4, 0, 0, 0);
+  g_date_time_get_week_number (dt, NULL, &jan4_week_day, NULL);
+  ordinal_day = (week * 7) + week_day - (jan4_week_day + 3);
+  if (ordinal_day < 0)
+    {
+      year--;
+      ordinal_day += GREGORIAN_LEAP (year) ? 366 : 365;
+    }
+  else if (ordinal_day > (GREGORIAN_LEAP (year) ? 366 : 365))
+    {
+      ordinal_day -= (GREGORIAN_LEAP (year) ? 366 : 365);
+      year++;
+    }
 
-  *offset = week_offset + ((week - 1) * 7) + week_day;
-  return TRUE;
+  return g_date_time_new_ordinal (tz, year, ordinal_day, hour, minute, seconds);
 }
 
-static gboolean
+static GDateTime *
 parse_iso8601_date (const gchar *text, gint length,
-                    gint *year, gint *month, gint *day, gint *offset)
+                    gint hour, gint minute, gint seconds, GTimeZone *tz)
 {
   /* YYYY-MM-DD */
   if (length == 10 && text[4] == '-' && text[7] == '-')
     {
-      return get_iso8601_int (text, 4, year) &&
-             get_iso8601_int (text + 5, 2, month) &&
-             get_iso8601_int (text + 8, 2, day);
+      int year, month, day;
+      if (!get_iso8601_int (text, 4, &year) ||
+          !get_iso8601_int (text + 5, 2, &month) ||
+          !get_iso8601_int (text + 8, 2, &day))
+        return NULL;
+      return g_date_time_new (tz, year, month, day, hour, minute, seconds);
     }
   /* YYYY-DDD */
   else if (length == 8 && text[4] == '-')
     {
-      gint ordinal_day;
-      return get_iso8601_int (text, 4, year) &&
-             get_iso8601_int (text + 5, 3, &ordinal_day) &&
-             convert_from_iso8601_ordinal (*year, ordinal_day, month, day);
+      gint year, ordinal_day;
+      if (!get_iso8601_int (text, 4, &year) ||
+          !get_iso8601_int (text + 5, 3, &ordinal_day))
+        return NULL;
+      return g_date_time_new_ordinal (tz, year, ordinal_day, hour, minute, seconds);
     }
   /* YYYY-Www-D */
   else if (length == 10 && text[4] == '-' && text[5] == 'W' && text[8] == '-')
     {
-      gint week, week_day;
-      *month = 1;
-      *day = 1;
-      return get_iso8601_int (text, 4, year) &&
-             get_iso8601_int (text + 6, 2, &week) &&
-             get_iso8601_int (text + 9, 1, &week_day) &&
-             convert_from_iso8601_week (*year, week, week_day, offset);
+      gint year, week, week_day;
+      if (!get_iso8601_int (text, 4, &year) ||
+          !get_iso8601_int (text + 6, 2, &week) ||
+          !get_iso8601_int (text + 9, 1, &week_day))
+        return NULL;
+      return g_date_time_new_week (tz, year, week, week_day, hour, minute, seconds);
     }
   /* YYYYWwwD */
   else if (length == 8 && text[4] == 'W')
     {
-      gint week, week_day;
-      *month = 1;
-      *day = 1;
-      return get_iso8601_int (text, 4, year) &&
-             get_iso8601_int (text + 5, 2, &week) &&
-             get_iso8601_int (text + 7, 1, &week_day) &&
-             convert_from_iso8601_week (*year, week, week_day, offset);
+      gint year, week, week_day;
+      if (!get_iso8601_int (text, 4, &year) ||
+          !get_iso8601_int (text + 5, 2, &week) ||
+          !get_iso8601_int (text + 7, 1, &week_day))
+        return NULL;
+      return g_date_time_new_week (tz, year, week, week_day, hour, minute, seconds);
     }
   /* YYYYMMDD */
   else if (length == 8)
     {
-      return get_iso8601_int (text, 4, year) &&
-             get_iso8601_int (text + 4, 2, month) &&
-             get_iso8601_int (text + 6, 2, day);
+      int year, month, day;
+      if (!get_iso8601_int (text, 4, &year) ||
+          !get_iso8601_int (text + 4, 2, &month) ||
+          !get_iso8601_int (text + 6, 2, &day))
+        return NULL;
+      return g_date_time_new (tz, year, month, day, hour, minute, seconds);
     }
   /* YYYYDDD */
   else if (length == 7)
     {
-      gint ordinal_day;
-      return get_iso8601_int (text, 4, year) &&
-             get_iso8601_int (text + 4, 3, &ordinal_day) &&
-             convert_from_iso8601_ordinal (*year, ordinal_day, month, day);
+      gint year, ordinal_day;
+      if (!get_iso8601_int (text, 4, &year) ||
+          !get_iso8601_int (text + 4, 3, &ordinal_day))
+        return NULL;
+      return g_date_time_new_ordinal (tz, year, ordinal_day, hour, minute, seconds);
     }
   else
     return FALSE;
@@ -1166,7 +1177,7 @@ GDateTime *
 g_date_time_new_from_iso8601 (const gchar *text)
 {
   gint length, date_length = -1;
-  gint year = 0, month = 0, day = 0, offset = 0, hour = 0, minute = 0;
+  gint hour = 0, minute = 0;
   gdouble seconds = 0.0;
   GTimeZone *tz = NULL;
   GDateTime *datetime = NULL;
@@ -1183,16 +1194,13 @@ g_date_time_new_from_iso8601 (const gchar *text)
   if (date_length < 0)
     return NULL;
 
-  if (!parse_iso8601_date (text, date_length, &year, &month, &day, &offset) ||
-      !parse_iso8601_time (text + date_length + 1, length - (date_length + 1),
+  if (!parse_iso8601_time (text + date_length + 1, length - (date_length + 1),
                            &hour, &minute, &seconds, &tz))
     goto out;
-
   if (tz == NULL)
     tz = g_time_zone_new_local ();
-  datetime = g_date_time_new (tz, year, month, day, hour, minute, seconds);
-  if (datetime != NULL && offset != 0)
-    datetime->days += offset;
+
+  datetime = parse_iso8601_date (text, date_length, hour, minute, seconds, tz);
 
 out:
     if (tz != NULL)
diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c
index 6868734..cbbf64b 100644
--- a/glib/tests/gdatetime.c
+++ b/glib/tests/gdatetime.c
@@ -604,7 +604,10 @@ test_GDateTime_new_from_iso8601 (void)
   dt = g_date_time_new_from_iso8601 ("2016-W00-1T22:10:42");
   g_assert (dt == NULL);
 
-  /* Limited to number of weeks in the year */
+  /* Largest week is 53 (but only for some years) */
+  dt = g_date_time_new_from_iso8601 ("2015-W53-7T22:10:42");
+  ASSERT_DATE (dt, 2016, 1, 3);
+  g_date_time_unref (dt);
   dt = g_date_time_new_from_iso8601 ("2016-W53-1T22:10:42");
   g_assert (dt == NULL);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]