datetime: Rework time zone support in constructors

Timezone handling is complicated. Really complicated.

In order to simplify it a little bit, we need to expose the GTimeZone
structure.

First of all, we allow creating time zone information directly from the
offset and the DST state, and then pass it to the g_date_time_new_full()
constructor. We also need to clean up the mess that is UTC-vs.-localtime
for the other constructors.

We also allow creating a GTimeZone from the Olson zoneinfo database
names; a time zone created like this will be "floating": it will just
reference the zoneinfo file - which are mmap()'ed, kept in a cache and
refcounted. Once the GTimeZone has been associated with a GDateTime, it
will be "anchored" to it: the offset will be resolved, as well as the
DST state.

https://bugzilla.gnome.org/show_bug.cgi?id=50076
This commit is contained in:
Emmanuele Bassi 2010-09-14 08:00:40 +01:00 committed by Ryan Lortie
parent bff4ac15d0
commit 67f1e52ce2
5 changed files with 637 additions and 291 deletions

View File

@ -1424,7 +1424,6 @@ g_date_time_new_from_timeval
g_date_time_new_now
g_date_time_new_utc_now
g_date_time_new_today
g_date_time_copy
g_date_time_ref
g_date_time_unref
<SUBSECTION>

File diff suppressed because it is too large Load Diff

View File

@ -74,6 +74,25 @@ G_BEGIN_DECLS
*/
#define G_TIME_SPAN_MILLISECOND (G_GINT64_CONSTANT (1000))
/**
* GTimeSpan:
*
* A value representing an interval of time, in microseconds.
*
* Since: 2.26
*/
typedef gint64 GTimeSpan;
/**
* GTimeZone:
*
* <structname>GTimeZone</structname> is an opaque structure whose members
* cannot be accessed directly.
*
* Since: 2.26
*/
typedef struct _GTimeZone GTimeZone;
/**
* GDateTime:
*
@ -84,15 +103,6 @@ G_BEGIN_DECLS
*/
typedef struct _GDateTime GDateTime;
/**
* GTimeSpan:
*
* A value representing an interval of time, in microseconds.
*
* Since: 2.26
*/
typedef gint64 GTimeSpan;
GDateTime * g_date_time_new_now (void);
GDateTime * g_date_time_new_today (void);
GDateTime * g_date_time_new_utc_now (void);
@ -107,9 +117,8 @@ GDateTime * g_date_time_new_full (gint year,
gint hour,
gint minute,
gint second,
const gchar *time_zone);
const GTimeZone *time_zone);
GDateTime * g_date_time_copy (const GDateTime *datetime);
GDateTime * g_date_time_ref (GDateTime *datetime);
void g_date_time_unref (GDateTime *datetime);
@ -174,9 +183,9 @@ void g_date_time_get_dmy (const GDateTime *datet
GTimeSpan g_date_time_get_utc_offset (const GDateTime *datetime);
G_CONST_RETURN gchar *g_date_time_get_timezone_name (const GDateTime *datetime);
gboolean g_date_time_is_daylight_savings (const GDateTime *datetime);
gboolean g_date_time_is_leap_year (const GDateTime *datetime);
gboolean g_date_time_is_daylight_savings (const GDateTime *datetime);
GDateTime * g_date_time_to_local (const GDateTime *datetime);
gint64 g_date_time_to_epoch (const GDateTime *datetime);
@ -186,6 +195,18 @@ GDateTime * g_date_time_to_utc (const GDateTime *datet
gchar * g_date_time_printf (const GDateTime *datetime,
const gchar *format) G_GNUC_MALLOC;
GTimeZone * g_time_zone_new (gint offset,
gboolean is_dst);
GTimeZone * g_time_zone_new_for_name (const gchar *name);
GTimeZone * g_time_zone_new_utc (void);
GTimeZone * g_time_zone_new_local (void);
GTimeZone * g_time_zone_copy (const GTimeZone *time_zone);
void g_time_zone_free (GTimeZone *time_zone);
G_CONST_RETURN gchar *g_time_zone_get_name (const GTimeZone *time_zone);
gint g_time_zone_get_offset (const GTimeZone *time_zone);
gboolean g_time_zone_get_is_dst (const GTimeZone *time_zone);
gboolean g_time_zone_is_floating (const GTimeZone *time_zone);
G_END_DECLS
#endif /* __G_DATE_TIME_H__ */

View File

@ -336,7 +336,6 @@ g_date_time_add_seconds
g_date_time_add_weeks
g_date_time_add_years
g_date_time_compare
g_date_time_copy
g_date_time_day
g_date_time_difference
g_date_time_equal
@ -372,6 +371,16 @@ g_date_time_to_epoch
g_date_time_to_timeval
g_date_time_to_utc
g_date_time_unref
g_time_zone_copy
g_time_zone_free
g_time_zone_get_is_dst
g_time_zone_get_name
g_time_zone_get_offset
g_time_zone_is_floating
g_time_zone_new
g_time_zone_new_for_name
g_time_zone_new_local
g_time_zone_new_utc
#endif
#endif

View File

@ -192,20 +192,6 @@ test_GDateTime_compare (void)
g_date_time_unref (dt1);
}
static void
test_GDateTime_copy (void)
{
GDateTime *dt1, *dt2;
dt1 = g_date_time_new_now ();
dt2 = g_date_time_copy (dt1);
g_assert (dt1 != NULL);
g_assert (dt2 != NULL);
g_assert_cmpint (0, ==, g_date_time_compare (dt1, dt2));
g_date_time_unref (dt1);
g_date_time_unref (dt2);
}
static void
test_GDateTime_date (void)
{
@ -229,6 +215,7 @@ static void
test_GDateTime_equal (void)
{
GDateTime *dt1, *dt2;
GTimeZone *time_zone;
dt1 = g_date_time_new_from_date (2009, 10, 19);
dt2 = g_date_time_new_from_date (2009, 10, 19);
@ -242,12 +229,26 @@ test_GDateTime_equal (void)
g_date_time_unref (dt1);
g_date_time_unref (dt2);
/* America/Recife is GMT-3 and is not in DST for this time */
dt1 = g_date_time_new_full (2010, 5, 24, 8, 0, 0, "America/Recife");
dt2 = g_date_time_new_full (2010, 5, 24, 11, 0, 0, "UTC");
/* UTC-0300 and not in DST */
time_zone = g_time_zone_new (-3 * 3600, FALSE);
dt1 = g_date_time_new_full (2010, 5, 24, 8, 0, 0, time_zone);
g_assert_cmpint (g_date_time_get_utc_offset (dt1) / G_USEC_PER_SEC, ==, (-3 * 3600));
/* UTC */
dt2 = g_date_time_new_full (2010, 5, 24, 11, 0, 0, NULL);
g_assert_cmpint (g_date_time_get_utc_offset (dt2), ==, 0);
g_assert (g_date_time_equal (dt1, dt2));
g_date_time_unref (dt1);
g_time_zone_free (time_zone);
/* America/Recife is in UTC-0300 */
time_zone = g_time_zone_new_for_name ("America/Recife");
dt1 = g_date_time_new_full (2010, 5, 24, 8, 0, 0, time_zone);
g_assert_cmpint (g_date_time_get_utc_offset (dt1) / G_USEC_PER_SEC, ==, (-3 * 3600));
g_assert (g_date_time_equal (dt1, dt2));
g_date_time_unref (dt1);
g_date_time_unref (dt2);
g_time_zone_free (time_zone);
}
static void
@ -388,7 +389,7 @@ test_GDateTime_get_millisecond (void)
g_get_current_time (&tv);
dt = g_date_time_new_from_timeval (&tv);
g_assert_cmpint ((tv.tv_usec/1000), ==, g_date_time_get_millisecond (dt));
g_assert_cmpint ((tv.tv_usec / 1000), ==, g_date_time_get_millisecond (dt));
g_date_time_unref (dt);
}
@ -437,10 +438,14 @@ test_GDateTime_new_from_timeval (void)
dt = g_date_time_new_from_timeval (&tv);
if (g_test_verbose ())
g_print ("\nDT%d/%d/%d\n",
g_print ("\nDT%04d-%02d-%02dT%02d:%02d:%02d%s\n",
g_date_time_get_year (dt),
g_date_time_get_month (dt),
g_date_time_get_day_of_month (dt));
g_date_time_get_day_of_month (dt),
g_date_time_get_hour (dt),
g_date_time_get_minute (dt),
g_date_time_get_second (dt),
g_date_time_get_timezone_name (dt));
g_date_time_to_timeval (dt, &tv2);
g_assert_cmpint (tv.tv_sec, ==, tv2.tv_sec);
@ -723,6 +728,7 @@ static void
test_GDateTime_new_full (void)
{
GDateTime *dt;
GTimeZone *time_zone;
dt = g_date_time_new_full (2009, 12, 11, 12, 11, 10, NULL);
g_assert_cmpint (2009, ==, g_date_time_get_year (dt));
@ -733,7 +739,8 @@ test_GDateTime_new_full (void)
g_assert_cmpint (10, ==, g_date_time_get_second (dt));
g_date_time_unref (dt);
dt = g_date_time_new_full (2010, 5, 24, 8, 4, 0, "America/Recife");
time_zone = g_time_zone_new_for_name ("America/Recife");
dt = g_date_time_new_full (2010, 5, 24, 8, 4, 0, time_zone);
g_assert_cmpint (2010, ==, g_date_time_get_year (dt));
g_assert_cmpint (5, ==, g_date_time_get_month (dt));
g_assert_cmpint (24, ==, g_date_time_get_day_of_month (dt));
@ -743,6 +750,7 @@ test_GDateTime_new_full (void)
g_assert_cmpstr ("BRT", ==, g_date_time_get_timezone_name (dt));
g_assert (!g_date_time_is_daylight_savings (dt));
g_date_time_unref (dt);
g_time_zone_free (time_zone);
}
static void
@ -987,7 +995,6 @@ main (gint argc,
g_test_add_func ("/GDateTime/add_weeks", test_GDateTime_add_weeks);
g_test_add_func ("/GDateTime/add_years", test_GDateTime_add_years);
g_test_add_func ("/GDateTime/compare", test_GDateTime_compare);
g_test_add_func ("/GDateTime/copy", test_GDateTime_copy);
g_test_add_func ("/GDateTime/date", test_GDateTime_date);
g_test_add_func ("/GDateTime/diff", test_GDateTime_diff);
g_test_add_func ("/GDateTime/equal", test_GDateTime_equal);