set tv_usec to 0 rather than 1 when a fraction of a second is not
authorMatthias Clasen <matthiasc@src.gnome.org>
Thu, 19 Jun 2008 04:14:25 +0000 (04:14 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Thu, 19 Jun 2008 04:14:25 +0000 (04:14 +0000)
        * glib/gtimer.c (g_time_val_from_iso8601): set tv_usec to 0 rather
        than 1 when a fraction of a second is not specified
        (g_time_val_from_iso8601): calculate a fraction of a second
        correctly even in case it does not happen to consist of exactly
        six digits; do not allow random data after the ISO 8601 string,
        only whitespace
        (make g_time_val_to_iso8601): support fractions of a second
        Patch by Peter Kjellerstedt

        * tests/testglib.c: Update to match

svn path=/trunk/; revision=7057

ChangeLog
glib/gtimer.c
tests/testglib.c

index 9d62e97..ebff72a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2008-06-18  Matthias Clasen  <mclasen@redhat.com>
+
+       Bug 537635 – Corrections and improvements to
+       g_time_val_from_iso8601()/g_time_val_to_iso8601()
+
+       * glib/gtimer.c (g_time_val_from_iso8601): set tv_usec to 0 rather 
+       than 1 when a fraction of a second is not specified
+       (g_time_val_from_iso8601): calculate a fraction of a second
+       correctly even in case it does not happen to consist of exactly 
+       six digits; do not allow random data after the ISO 8601 string,
+       only whitespace
+       (make g_time_val_to_iso8601): support fractions of a second
+       Patch by Peter Kjellerstedt
+
+       * tests/testglib.c: Update to match
+
 2008-06-16  Christian Persch  <chpe@gnome.org>
 
        * glib/gbookmarkfile.c
index a29e39d..b75730a 100644 (file)
@@ -287,7 +287,7 @@ mktime_utc (struct tm *tm)
 
 /**
  * g_time_val_from_iso8601:
- * @iso_date: a ISO 8601 encoded date string
+ * @iso_date: an ISO 8601 encoded date string
  * @time_: a #GTimeVal
  *
  * Converts a string containing an ISO 8601 encoded date and time
@@ -365,10 +365,18 @@ g_time_val_from_iso8601 (const gchar *iso_date,
     }
 
   time_->tv_sec = mktime_utc (&tm);
-  time_->tv_usec = 1;
+  time_->tv_usec = 0;
   
   if (*iso_date == '.')
-    time_->tv_usec = strtoul (iso_date + 1, (char **)&iso_date, 10);
+    {
+      glong mul = 100000;
+
+      while (g_ascii_isdigit (*++iso_date))
+        {
+          time_->tv_usec += (*iso_date - '0') * mul;
+          mul /= 10;
+        }
+    }
     
   if (*iso_date == '+' || *iso_date == '-')
     {
@@ -377,24 +385,29 @@ g_time_val_from_iso8601 (const gchar *iso_date,
       val = 60 * strtoul (iso_date + 1, (char **)&iso_date, 10);
       
       if (*iso_date == ':')
-       val = 60 * val + strtoul (iso_date + 1, NULL, 10);
+       val = 60 * val + strtoul (iso_date + 1, (char **)&iso_date, 10);
       else
         val = 60 * (val / 100) + (val % 100);
 
       time_->tv_sec += (time_t) (val * sign);
     }
+  else if (*iso_date++ != 'Z')
+    return FALSE;
 
-  return TRUE;
+  while (g_ascii_isspace (*iso_date))
+    iso_date++;
+
+  return *iso_date == '\0';
 }
 
 /**
  * g_time_val_to_iso8601:
  * @time_: a #GTimeVal
  * 
- * Converts @time_ into a ISO 8601 encoded string, relative to the
+ * Converts @time_ into an ISO 8601 encoded string, relative to the
  * Coordinated Universal Time (UTC).
  *
- * Return value: a newly allocated string containing a ISO 8601 date
+ * Return value: a newly allocated string containing an ISO 8601 date
  *
  * Since: 2.12
  */
@@ -402,24 +415,36 @@ gchar *
 g_time_val_to_iso8601 (GTimeVal *time_)
 {
   gchar *retval;
+  struct tm *tm;
 #ifdef HAVE_GMTIME_R
   struct tm tm_;
 #endif
   
   g_return_val_if_fail (time_->tv_usec >= 0 && time_->tv_usec < G_USEC_PER_SEC, NULL);
 
-#define ISO_8601_LEN   21
-#define ISO_8601_FORMAT "%Y-%m-%dT%H:%M:%SZ"
-  retval = g_new0 (gchar, ISO_8601_LEN + 1);
-
-  strftime (retval, ISO_8601_LEN,
-           ISO_8601_FORMAT,
 #ifdef HAVE_GMTIME_R
-           gmtime_r (&(time_->tv_sec), &tm_)
+  tm = gmtime_r (&time_->tv_sec, &tm_);
 #else
-           gmtime (&(time_->tv_sec))
+  tm = gmtime (&time_->tv_sec);
 #endif
-            );
+
+  if (time_->tv_usec != 0)
+    {
+#define ISO_8601_FRAC_LEN    28
+#define ISO_8601_FRAC_FORMAT "%%Y-%%m-%%dT%%H:%%M:%%S.%06ldZ"
+      gchar *format = g_strdup_printf (ISO_8601_FRAC_FORMAT, time_->tv_usec);
+
+      retval = g_new0 (gchar, ISO_8601_FRAC_LEN + 1);
+      strftime (retval, ISO_8601_FRAC_LEN, format, tm);
+      g_free (format);
+    }
+  else
+    {
+#define ISO_8601_LEN    21
+#define ISO_8601_FORMAT "%Y-%m-%dT%H:%M:%SZ"
+      retval = g_new0 (gchar, ISO_8601_LEN + 1);
+      strftime (retval, ISO_8601_LEN, ISO_8601_FORMAT, tm);
+    }
   
   return retval;
 }
index 4f84adc..f14158f 100644 (file)
@@ -1383,36 +1383,70 @@ various_string_tests (void)
   g_free (tmp_string);
   g_free (string);
 
-#define REF_INVALID  "Wed Dec 19 17:20:20 GMT 2007"
-#define REF_SEC_UTC  320063760
-#define REF_STR_UTC  "1980-02-22T10:36:00Z"
-#define REF_STR_CEST "1980-02-22T12:36:00+02:00"
-#define REF_STR_EST  "1980-02-22T05:36:00-05:00"
+#define REF_INVALID1      "Wed Dec 19 17:20:20 GMT 2007"
+#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_CEST      "1980-02-22T12:36:00+02:00"
+#define REF_STR_EST       "19800222T053600-0500"
+#define REF_USEC_UTC      50000
+#define REF_STR_USEC_UTC  "1980-02-22T10:36:00.050000Z"
+#define REF_STR_USEC_CEST "19800222T123600.050000000+0200"
+#define REF_STR_USEC_EST  "1980-02-22T05:36:00.05-05:00"
 
   if (g_test_verbose())
     g_print ("checking g_time_val_from_iso8601...\n");
   ref_date.tv_sec = REF_SEC_UTC;
   ref_date.tv_usec = 0;
-  g_assert (g_time_val_from_iso8601 (REF_INVALID, &date) == FALSE);
+  g_assert (g_time_val_from_iso8601 (REF_INVALID1, &date) == FALSE);
+  g_assert (g_time_val_from_iso8601 (REF_INVALID2, &date) == FALSE);
   g_assert (g_time_val_from_iso8601 (REF_STR_UTC, &date) != FALSE);
   if (g_test_verbose())
-    g_print ("\t=> UTC stamp = %ld (should be: %ld) (%ld off)\n", date.tv_sec, ref_date.tv_sec, date.tv_sec - ref_date.tv_sec);
-  g_assert (date.tv_sec == ref_date.tv_sec);
+    g_print ("\t=> UTC 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);
 
   g_assert (g_time_val_from_iso8601 (REF_STR_CEST, &date) != FALSE);
   if (g_test_verbose())
-    g_print ("\t=> CEST stamp = %ld (should be: %ld) (%ld off)\n", date.tv_sec, ref_date.tv_sec, date.tv_sec - ref_date.tv_sec);
-  g_assert (date.tv_sec == ref_date.tv_sec);
+    g_print ("\t=> CEST 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);
 
   g_assert (g_time_val_from_iso8601 (REF_STR_EST, &date) != FALSE);
   if (g_test_verbose())
-    g_print ("\t=> EST stamp = %ld (should be: %ld) (%ld off)\n", date.tv_sec, ref_date.tv_sec, date.tv_sec - ref_date.tv_sec);
-  g_assert (date.tv_sec == ref_date.tv_sec);
+    g_print ("\t=> EST 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);
+
+  ref_date.tv_usec = REF_USEC_UTC;
+  g_assert (g_time_val_from_iso8601 (REF_STR_USEC_UTC, &date) != FALSE);
+  if (g_test_verbose())
+    g_print ("\t=> UTC 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);
+
+  g_assert (g_time_val_from_iso8601 (REF_STR_USEC_CEST, &date) != FALSE);
+  if (g_test_verbose())
+    g_print ("\t=> CEST 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);
+
+  g_assert (g_time_val_from_iso8601 (REF_STR_USEC_EST, &date) != FALSE);
+  if (g_test_verbose())
+    g_print ("\t=> EST 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);
 
   if (g_test_verbose())
     g_print ("checking g_time_val_to_iso8601...\n");
   ref_date.tv_sec = REF_SEC_UTC;
-  ref_date.tv_usec = 1;
+  ref_date.tv_usec = 0;
   date_str = g_time_val_to_iso8601 (&ref_date);
   g_assert (date_str != NULL);
   if (g_test_verbose())
@@ -1420,6 +1454,14 @@ various_string_tests (void)
   g_assert (strcmp (date_str, REF_STR_UTC) == 0);
   g_free (date_str);
 
+  ref_date.tv_usec = REF_USEC_UTC;
+  date_str = g_time_val_to_iso8601 (&ref_date);
+  g_assert (date_str != NULL);
+  if (g_test_verbose())
+    g_print ("\t=> date string = %s (should be: %s)\n", date_str, REF_STR_USEC_UTC);
+  g_assert (strcmp (date_str, REF_STR_USEC_UTC) == 0);
+  g_free (date_str);
+
   if (g_test_verbose())
     g_print ("checking g_ascii_strcasecmp...");
   g_assert (g_ascii_strcasecmp ("FroboZZ", "frobozz") == 0);