[glib/wip/rancell/iso8601-2] REFACTOR
- From: Robert Ancell <rancell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/rancell/iso8601-2] REFACTOR
- Date: Sat, 24 Jun 2017 08:18:06 +0000 (UTC)
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]