From 6db9ec40708a4ad60a11a21856a1d54a48b01abd Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 23 Mar 2006 02:54:29 +0000 Subject: [PATCH] Check for timegm. 2006-03-23 Emmanuele Bassi * configure.in: Check for timegm. * glib/gtimer.h: * glib/gtimer.c: * glib/glib.symbols: * docs/reference/glib/glib-sections.txt: Added g_time_val_to_iso8601 and g_time_val_from_iso8601, to convert a GTimeVal to and from an ISO 8601 encoded date. * tests/testglib.c: Added test cases for g_time_val_to_iso8601() and g_time_val_from_iso8601() functions. --- ChangeLog | 14 +++ ChangeLog.pre-2-10 | 14 +++ ChangeLog.pre-2-12 | 14 +++ configure.in | 2 + docs/reference/glib/glib-sections.txt | 2 + glib/glib.symbols | 2 + glib/gtimer.c | 155 ++++++++++++++++++++++++++ glib/gtimer.h | 25 +++-- tests/testglib.c | 35 +++++- 9 files changed, 251 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1e2a8cd57..9234d7f5e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2006-03-23 Emmanuele Bassi + + * configure.in: Check for timegm. + + * glib/gtimer.h: + * glib/gtimer.c: + * glib/glib.symbols: + * docs/reference/glib/glib-sections.txt: Added g_time_val_to_iso8601 + and g_time_val_from_iso8601, to convert a GTimeVal to and from an + ISO 8601 encoded date. + + * tests/testglib.c: Added test cases for g_time_val_to_iso8601() + and g_time_val_from_iso8601() functions. + 2006-03-20 Vladimer Sichinava * configure.in: Added "ka" (Georgian) to ALL_LINGUAS diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 1e2a8cd57..9234d7f5e 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,17 @@ +2006-03-23 Emmanuele Bassi + + * configure.in: Check for timegm. + + * glib/gtimer.h: + * glib/gtimer.c: + * glib/glib.symbols: + * docs/reference/glib/glib-sections.txt: Added g_time_val_to_iso8601 + and g_time_val_from_iso8601, to convert a GTimeVal to and from an + ISO 8601 encoded date. + + * tests/testglib.c: Added test cases for g_time_val_to_iso8601() + and g_time_val_from_iso8601() functions. + 2006-03-20 Vladimer Sichinava * configure.in: Added "ka" (Georgian) to ALL_LINGUAS diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index 1e2a8cd57..9234d7f5e 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,17 @@ +2006-03-23 Emmanuele Bassi + + * configure.in: Check for timegm. + + * glib/gtimer.h: + * glib/gtimer.c: + * glib/glib.symbols: + * docs/reference/glib/glib-sections.txt: Added g_time_val_to_iso8601 + and g_time_val_from_iso8601, to convert a GTimeVal to and from an + ISO 8601 encoded date. + + * tests/testglib.c: Added test cases for g_time_val_to_iso8601() + and g_time_val_from_iso8601() functions. + 2006-03-20 Vladimer Sichinava * configure.in: Added "ka" (Georgian) to ALL_LINGUAS diff --git a/configure.in b/configure.in index 8c5144f0e..2f32722bc 100644 --- a/configure.in +++ b/configure.in @@ -528,6 +528,8 @@ AC_CHECK_FUNCS(valloc) AC_CHECK_FUNCS(atexit on_exit) +AC_CHECK_FUNCS(timegm) + AC_CHECK_SIZEOF(char) AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(long) diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index ed5bb2018..0def2c675 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -1155,6 +1155,8 @@ GTimeVal g_get_current_time g_usleep g_time_val_add +g_time_val_from_iso8601 +g_time_val_to_iso8601 GDate diff --git a/glib/glib.symbols b/glib/glib.symbols index 2b88fec02..71e6974de 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -1111,6 +1111,8 @@ g_timer_reset g_timer_start g_timer_stop g_time_val_add +g_time_val_from_iso8601 +g_time_val_to_iso8601 G_GNUC_MALLOC g_usleep #endif #endif diff --git a/glib/gtimer.c b/glib/gtimer.c index 6a6a06e3c..2d7678b6b 100644 --- a/glib/gtimer.c +++ b/glib/gtimer.c @@ -31,6 +31,8 @@ #include "config.h" #include "glibconfig.h" +#include + #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ @@ -308,5 +310,158 @@ g_time_val_add (GTimeVal *time_, glong microseconds) } } +/* converts a broken down date representation, relative to UTC, to + * a timestamp; it uses timegm() if it's available. + */ +static time_t +mktime_utc (struct tm *tm) +{ + time_t retval; + +#ifndef HAVE_TIMEGM + static const gint days_before[] = + { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 + }; +#endif + +#ifndef HAVE_TIMEGM + if (tm->tm_mon < 0 || tm->tm_mon > 11) + return (time_t) -1; + + retval = (tm->tm_year - 70) * 365; + retval += (tm->tm_year - 68) / 4; + retval += days_before[tm->tm_mon] + tm->tm_mday - 1; + + if (tm->tm_year % 4 == 2 && tm->tm_mon < 2) + retval -= 1; + + retval = ((((retval * 24) + tm->tm_hour) * 60) + tm->tm_min) * 60 + tm->tm_sec; +#else + retval = timegm (tm); +#endif /* !HAVE_TIMEGM */ + + return retval; +} + +/** + * g_time_val_from_iso8601: + * @iso_date: a ISO 8601 encoded date string + * @time_: a #GTimeVal + * + * Converts a string containing an ISO 8601 encoded date and time + * to a #GTimeVal and puts it into @time_. + * + * Return value: %TRUE if the conversion was successful. + * + * Since: 2.10 + */ +gboolean +g_time_val_from_iso8601 (const gchar *iso_date, + GTimeVal *time_) +{ + struct tm tm; + long val; + + g_return_val_if_fail (iso_date != NULL, FALSE); + g_return_val_if_fail (time_ != NULL, FALSE); + + val = strtoul (iso_date, (char **)&iso_date, 10); + if (*iso_date == '-') + { + /* YYYY-MM-DD */ + tm.tm_year = val - 1900; + iso_date++; + tm.tm_mon = strtoul (iso_date, (char **)&iso_date, 10) - 1; + + if (*iso_date++ != '-') + return FALSE; + + tm.tm_mday = strtoul (iso_date, (char **)&iso_date, 10); + } + else + { + /* YYYYMMDD */ + tm.tm_mday = val % 100; + tm.tm_mon = (val % 10000) / 100 - 1; + tm.tm_year = val / 10000 - 1900; + } + + if (*iso_date++ != 'T') + return FALSE; + + val = strtoul (iso_date, (char **)&iso_date, 10); + if (*iso_date == ':') + { + /* hh:mm:ss */ + tm.tm_hour = val; + iso_date++; + tm.tm_min = strtoul (iso_date, (char **)&iso_date, 10); + + if (*iso_date++ != ':') + return FALSE; + + tm.tm_sec = strtoul (iso_date, (char **)&iso_date, 10); + } + else + { + /* hhmmss */ + tm.tm_sec = val % 100; + tm.tm_min = (val % 10000) / 100; + tm.tm_hour = val / 10000; + } + + time_->tv_sec = mktime_utc (&tm); + time_->tv_usec = 1; + + if (*iso_date == '.') + time_->tv_usec = strtoul (iso_date + 1, (char **)&iso_date, 10); + + if (*iso_date == '+' || *iso_date == '-') + { + gint sign = (*iso_date == '+') ? -1 : 1; + + val = 60 * strtoul (iso_date + 1, (char **)&iso_date, 10); + + if (*iso_date == ':') + val = 60 * val + strtoul (iso_date + 1, NULL, 10); + else + val = 60 * (val / 100) + (val % 100); + + time_->tv_sec += (time_t) (val * sign); + } + + return TRUE; +} + +/** + * g_time_val_to_iso8601: + * @time_: a #GTimeVal + * + * Converts @time_ into a ISO 8601 encoded string, relative to the + * Coordinated Universal Time (UTC). + * + * Return value: a newly allocated string containing a ISO 8601 date + * + * Since: 2.10 + */ +gchar * +g_time_val_to_iso8601 (GTimeVal *time_) +{ + gchar *retval; + + 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, + gmtime (&(time_->tv_sec))); + + return retval; +} + #define __G_TIMER_C__ #include "galiasdef.c" diff --git a/glib/gtimer.h b/glib/gtimer.h index fc434d06a..d602ae1b9 100644 --- a/glib/gtimer.h +++ b/glib/gtimer.h @@ -39,19 +39,22 @@ typedef struct _GTimer GTimer; #define G_USEC_PER_SEC 1000000 -GTimer* g_timer_new (void); -void g_timer_destroy (GTimer *timer); -void g_timer_start (GTimer *timer); -void g_timer_stop (GTimer *timer); -void g_timer_reset (GTimer *timer); -void g_timer_continue (GTimer *timer); -gdouble g_timer_elapsed (GTimer *timer, - gulong *microseconds); +GTimer* g_timer_new (void); +void g_timer_destroy (GTimer *timer); +void g_timer_start (GTimer *timer); +void g_timer_stop (GTimer *timer); +void g_timer_reset (GTimer *timer); +void g_timer_continue (GTimer *timer); +gdouble g_timer_elapsed (GTimer *timer, + gulong *microseconds); -void g_usleep (gulong microseconds); +void g_usleep (gulong microseconds); -void g_time_val_add (GTimeVal *time_, - glong microseconds); +void g_time_val_add (GTimeVal *time_, + glong microseconds); +gboolean g_time_val_from_iso8601 (const gchar *iso_date, + GTimeVal *time_); +gchar* g_time_val_to_iso8601 (GTimeVal *time_) G_GNUC_MALLOC; G_END_DECLS diff --git a/tests/testglib.c b/tests/testglib.c index 42f4fce9a..0aadec72a 100644 --- a/tests/testglib.c +++ b/tests/testglib.c @@ -475,7 +475,9 @@ main (int argc, gint morenums[10] = { 8, 9, 7, 0, 3, 2, 5, 1, 4, 6}; gchar *string; gint value = 120; - gint *pvalue=NULL; + gint *pvalue=NULL; + GTimeVal ref_date, date; + gchar *date_str; gchar *mem[10000], *tmp_string = NULL, *tmp_string_2; gint i, j; @@ -1176,6 +1178,37 @@ main (int argc, g_timer_destroy(timer); g_timer_destroy(timer2); +#define REF_SEC_UTC 343737360 +#define REF_STR_UTC "1980-11-22T10:36:00Z" +#define REF_STR_CEST "1980-11-22T12:36:00+02:00" +#define REF_STR_EST "1980-11-22T05:36:00-05:00" + + 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_STR_UTC, &date) != FALSE); + 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_assert (g_time_val_from_iso8601 (REF_STR_CEST, &date) != FALSE); + 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_assert (g_time_val_from_iso8601 (REF_STR_EST, &date) != FALSE); + 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 ("ok\n"); + + g_print ("checking g_time_val_to_iso8601...\n"); + ref_date.tv_sec = REF_SEC_UTC; + ref_date.tv_usec = 1; + date_str = g_time_val_to_iso8601 (&ref_date); + g_assert (date_str != NULL); + g_print ("\t=> date string = %s (should be: %s)\n", date_str, REF_STR_UTC); + g_assert (strcmp (date_str, REF_STR_UTC) == 0); + g_free (date_str); + g_print ("ok\n"); + g_print ("checking g_ascii_strcasecmp..."); g_assert (g_ascii_strcasecmp ("FroboZZ", "frobozz") == 0); g_assert (g_ascii_strcasecmp ("frobozz", "frobozz") == 0);