g_time_val_from_iso8601: handle timezoneless dates
authorDan Winship <danw@gnome.org>
Tue, 1 Sep 2009 13:37:48 +0000 (09:37 -0400)
committerDan Winship <danw@gnome.org>
Tue, 1 Sep 2009 13:40:03 +0000 (09:40 -0400)
per ISO 8601:2004 4.2.5.2

Based on a patch from Andy Shevchenko
http://bugzilla.gnome.org/show_bug.cgi?id=589491

glib/gtimer.c
tests/testglib.c

index c52eeb7..407ce85 100644 (file)
@@ -364,7 +364,6 @@ g_time_val_from_iso8601 (const gchar *iso_date,
       tm.tm_hour = val / 10000;
     }
 
-  time_->tv_sec = mktime_utc (&tm);
   time_->tv_usec = 0;
   
   if (*iso_date == ',' || *iso_date == '.')
@@ -378,7 +377,13 @@ g_time_val_from_iso8601 (const gchar *iso_date,
         }
     }
     
-  if (*iso_date == '+' || *iso_date == '-')
+  /* Now parse the offset and convert tm to a time_t */
+  if (*iso_date == 'Z')
+    {
+      iso_date++;
+      time_->tv_sec = mktime_utc (&tm);
+    }
+  else if (*iso_date == '+' || *iso_date == '-')
     {
       gint sign = (*iso_date == '+') ? -1 : 1;
       
@@ -389,10 +394,13 @@ g_time_val_from_iso8601 (const gchar *iso_date,
       else
         val = 60 * (val / 100) + (val % 100);
 
-      time_->tv_sec += (time_t) (60 * val * sign);
+      time_->tv_sec = mktime_utc (&tm) + (time_t) (60 * val * sign);
+    }
+  else
+    {
+      /* No "Z" or offset, so local time */
+      time_->tv_sec = mktime (&tm);
     }
-  else if (*iso_date++ != 'Z')
-    return FALSE;
 
   while (g_ascii_isspace (*iso_date))
     iso_date++;
index 2eeea1e..88b11ae 100644 (file)
@@ -1279,6 +1279,7 @@ various_string_tests (void)
   GTimeVal ref_date, date;
   gchar *tmp_string = NULL, *tmp_string_2, *string, *date_str;
   guint i;
+  gchar *tz;
 
   if (g_test_verbose())
     g_print ("checking string chunks...");
@@ -1308,6 +1309,7 @@ various_string_tests (void)
 #define REF_INVALID2      "1980-02-22T10:36:00Zulu"
 #define REF_SEC_UTC       320063760
 #define REF_STR_UTC       "1980-02-22T10:36:00Z"
+#define REF_STR_LOCAL     "1980-02-22T13:36:00"
 #define REF_STR_CEST      "1980-02-22T12:36:00+02:00"
 #define REF_STR_EST       "19800222T053600-0500"
 #define REF_STR_NST       "1980-02-22T07:06:00-03:30"
@@ -1330,6 +1332,25 @@ various_string_tests (void)
              date.tv_sec - ref_date.tv_sec, date.tv_usec - ref_date.tv_usec);
   g_assert (date.tv_sec == ref_date.tv_sec && date.tv_usec == ref_date.tv_usec);
 
+  /* predefine time zone */
+  tz = g_getenv("TZ");
+  g_setenv("TZ", "UTC-03:00", 1);
+  tzset();
+
+  g_assert (g_time_val_from_iso8601 (REF_STR_LOCAL, &date) != FALSE);
+  if (g_test_verbose())
+    g_print ("\t=> LOCAL stamp = %ld.%06ld (should be: %ld.%06ld) (%ld.%06ld off)\n",
+             date.tv_sec, date.tv_usec, ref_date.tv_sec, ref_date.tv_usec,
+             date.tv_sec - ref_date.tv_sec, date.tv_usec - ref_date.tv_usec);
+  g_assert (date.tv_sec == ref_date.tv_sec && date.tv_usec == ref_date.tv_usec);
+
+  /* revert back user defined time zone */
+  if (tz)
+    g_setenv("TZ", tz, TRUE);
+  else
+    g_unsetenv("TZ");
+  tzset();
+
   g_assert (g_time_val_from_iso8601 (REF_STR_CEST, &date) != FALSE);
   if (g_test_verbose())
     g_print ("\t=> CEST stamp = %ld.%06ld (should be: %ld.%06ld) (%ld.%06ld off)\n",