gtimezone: Add g_time_zone_get_identifier() accessor

This is a non-trivial accessor which gets the identifier string used to
create the GTimeZone — unless the string passed to g_time_zone_new() was
invalid, in which case the identifier will be `UTC`.

Implementing this required reworking how timezone information was loaded
so that the tz->name is always set at the same time as tz->t_info, so
they are in sync. Previously, the tz->name was unconditionally set to
whatever was passed to g_time_zone_new(), and then not updated if the
tz->t_info was eventually set to the default UTC information.

This includes tests for the new g_time_zone_get_identifier() API, and
for the g_date_time_get_timezone() API added in the previous commit.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

https://bugzilla.gnome.org/show_bug.cgi?id=795165
This commit is contained in:
Philip Withnall 2018-04-11 15:59:29 +01:00
parent 9ddd17d304
commit 8945227743
4 changed files with 217 additions and 35 deletions

View File

@ -1653,6 +1653,7 @@ GTimeType
g_time_zone_find_interval g_time_zone_find_interval
g_time_zone_adjust_time g_time_zone_adjust_time
<SUBSECTION> <SUBSECTION>
g_time_zone_get_identifier
g_time_zone_get_abbreviation g_time_zone_get_abbreviation
g_time_zone_get_offset g_time_zone_get_offset
g_time_zone_is_dst g_time_zone_is_dst

View File

@ -52,10 +52,17 @@
* #GTimeZone is a structure that represents a time zone, at no * #GTimeZone is a structure that represents a time zone, at no
* particular point in time. It is refcounted and immutable. * particular point in time. It is refcounted and immutable.
* *
* Each time zone has an identifier (for example, Europe/London) which is
* platform dependent. See g_time_zone_new() for information on the identifier
* formats. The identifier of a time zone can be retrieved using
* g_time_zone_get_identifier().
*
* A time zone contains a number of intervals. Each interval has * A time zone contains a number of intervals. Each interval has
* an abbreviation to describe it, an offet to UTC and a flag indicating * an abbreviation to describe it (for example, PDT), an offet to UTC and a
* if the daylight savings time is in effect during that interval. A * flag indicating if the daylight savings time is in effect during that
* time zone always has at least one interval -- interval 0. * interval. A time zone always has at least one interval interval 0. Note
* that interval abbreviations are not the same as time zone identifiers
* (apart from UTC), and cannot be passed to g_time_zone_new().
* *
* Every UTC time is contained within exactly one interval, but a given * Every UTC time is contained within exactly one interval, but a given
* local time may be contained within zero, one or two intervals (due to * local time may be contained within zero, one or two intervals (due to
@ -384,7 +391,7 @@ zone_for_constant_offset (GTimeZone *gtz, const gchar *name)
info.is_dst = FALSE; info.is_dst = FALSE;
info.abbrev = g_strdup (name); info.abbrev = g_strdup (name);
gtz->name = g_strdup (name);
gtz->t_info = g_array_sized_new (FALSE, TRUE, sizeof (TransitionInfo), 1); gtz->t_info = g_array_sized_new (FALSE, TRUE, sizeof (TransitionInfo), 1);
g_array_append_val (gtz->t_info, info); g_array_append_val (gtz->t_info, info);
@ -394,11 +401,18 @@ zone_for_constant_offset (GTimeZone *gtz, const gchar *name)
#ifdef G_OS_UNIX #ifdef G_OS_UNIX
static GBytes* static GBytes*
zone_info_unix (const gchar *identifier) zone_info_unix (const gchar *identifier,
gchar **out_identifier)
{ {
gchar *filename; gchar *filename;
GMappedFile *file = NULL; GMappedFile *file = NULL;
GBytes *zoneinfo = NULL; GBytes *zoneinfo = NULL;
gchar *resolved_identifier = NULL;
const gchar *tzdir;
tzdir = getenv ("TZDIR");
if (tzdir == NULL)
tzdir = "/usr/share/zoneinfo";
/* identifier can be a relative or absolute path name; /* identifier can be a relative or absolute path name;
if relative, it is interpreted starting from /usr/share/zoneinfo if relative, it is interpreted starting from /usr/share/zoneinfo
@ -406,11 +420,7 @@ zone_info_unix (const gchar *identifier)
glibc allows both syntaxes, so we should too */ glibc allows both syntaxes, so we should too */
if (identifier != NULL) if (identifier != NULL)
{ {
const gchar *tzdir; resolved_identifier = g_strdup (identifier);
tzdir = getenv ("TZDIR");
if (tzdir == NULL)
tzdir = "/usr/share/zoneinfo";
if (*identifier == ':') if (*identifier == ':')
identifier ++; identifier ++;
@ -421,7 +431,33 @@ zone_info_unix (const gchar *identifier)
filename = g_build_filename (tzdir, identifier, NULL); filename = g_build_filename (tzdir, identifier, NULL);
} }
else else
filename = g_strdup ("/etc/localtime"); {
gsize prefix_len = 0;
filename = g_strdup ("/etc/localtime");
/* Resolve the actual timezone pointed to by /etc/localtime. */
resolved_identifier = g_file_read_link (filename, NULL);
if (resolved_identifier == NULL)
{
/* Error */
if (out_identifier != NULL)
*out_identifier = NULL;
return NULL;
}
/* Strip the prefix and slashes if possible. */
if (g_str_has_prefix (resolved_identifier, tzdir))
{
prefix_len = strlen (tzdir);
while (*(resolved_identifier + prefix_len) == '/')
prefix_len++;
}
if (prefix_len > 0)
memmove (resolved_identifier, resolved_identifier + prefix_len,
strlen (resolved_identifier) - prefix_len + 1 /* nul terminator */);
}
file = g_mapped_file_new (filename, FALSE, NULL); file = g_mapped_file_new (filename, FALSE, NULL);
if (file != NULL) if (file != NULL)
@ -433,11 +469,18 @@ zone_info_unix (const gchar *identifier)
g_mapped_file_unref (file); g_mapped_file_unref (file);
} }
g_free (filename); g_free (filename);
g_assert (resolved_identifier != NULL);
if (out_identifier != NULL)
*out_identifier = g_steal_pointer (&resolved_identifier);
return zoneinfo; return zoneinfo;
} }
static void static void
init_zone_from_iana_info (GTimeZone *gtz, GBytes *zoneinfo) init_zone_from_iana_info (GTimeZone *gtz,
GBytes *zoneinfo,
gchar *identifier /* (transfer full) */)
{ {
gsize size; gsize size;
guint index; guint index;
@ -471,6 +514,7 @@ init_zone_from_iana_info (GTimeZone *gtz, GBytes *zoneinfo)
tz_ttinfo = tz_type_index + time_count; tz_ttinfo = tz_type_index + time_count;
tz_abbrs = tz_ttinfo + sizeof (struct ttinfo) * type_count; tz_abbrs = tz_ttinfo + sizeof (struct ttinfo) * type_count;
gtz->name = g_steal_pointer (&identifier);
gtz->t_info = g_array_sized_new (FALSE, TRUE, sizeof (TransitionInfo), gtz->t_info = g_array_sized_new (FALSE, TRUE, sizeof (TransitionInfo),
type_count); type_count);
gtz->transitions = g_array_sized_new (FALSE, TRUE, sizeof (Transition), gtz->transitions = g_array_sized_new (FALSE, TRUE, sizeof (Transition),
@ -611,7 +655,9 @@ register_tzi_to_tzi (RegTZI *reg, TIME_ZONE_INFORMATION *tzi)
} }
static gint static gint
rules_from_windows_time_zone (const gchar *identifier, TimeZoneRule **rules) rules_from_windows_time_zone (const gchar *identifier,
gchar **out_identifier,
TimeZoneRule **rules)
{ {
HKEY key; HKEY key;
gchar *subkey, *subkey_dynamic; gchar *subkey, *subkey_dynamic;
@ -623,6 +669,10 @@ rules_from_windows_time_zone (const gchar *identifier, TimeZoneRule **rules)
gint rules_num = 0; gint rules_num = 0;
RegTZI regtzi, regtzi_prev; RegTZI regtzi, regtzi_prev;
g_assert (out_identifier != NULL);
g_assert (rules != NULL);
*out_identifier = NULL;
*rules = NULL; *rules = NULL;
key_name = NULL; key_name = NULL;
@ -720,7 +770,6 @@ failed:
g_free (subkey_dynamic); g_free (subkey_dynamic);
g_free (subkey); g_free (subkey);
g_free (key_name);
if (*rules) if (*rules)
{ {
@ -730,10 +779,14 @@ failed:
else else
(*rules)[rules_num - 1].start_year = (*rules)[rules_num - 2].start_year + 1; (*rules)[rules_num - 1].start_year = (*rules)[rules_num - 2].start_year + 1;
*out_identifier = g_steal_pointer (&key_name);
return rules_num; return rules_num;
} }
else
return 0; g_free (key_name);
return 0;
} }
#endif #endif
@ -834,7 +887,8 @@ fill_transition_info_from_rule (TransitionInfo *info,
static void static void
init_zone_from_rules (GTimeZone *gtz, init_zone_from_rules (GTimeZone *gtz,
TimeZoneRule *rules, TimeZoneRule *rules,
gint rules_num) gint rules_num,
gchar *identifier /* (transfer full) */)
{ {
guint type_count = 0, trans_count = 0, info_index = 0; guint type_count = 0, trans_count = 0, info_index = 0;
guint ri; /* rule index */ guint ri; /* rule index */
@ -859,6 +913,7 @@ init_zone_from_rules (GTimeZone *gtz,
type_count++; type_count++;
} }
gtz->name = g_steal_pointer (&identifier);
gtz->t_info = g_array_sized_new (FALSE, TRUE, sizeof (TransitionInfo), type_count); gtz->t_info = g_array_sized_new (FALSE, TRUE, sizeof (TransitionInfo), type_count);
gtz->transitions = g_array_sized_new (FALSE, TRUE, sizeof (Transition), trans_count); gtz->transitions = g_array_sized_new (FALSE, TRUE, sizeof (Transition), trans_count);
@ -1217,11 +1272,18 @@ parse_identifier_boundaries (gchar **pos, TimeZoneRule *tzr)
*/ */
static gint static gint
rules_from_identifier (const gchar *identifier, rules_from_identifier (const gchar *identifier,
gchar **out_identifier,
TimeZoneRule **rules) TimeZoneRule **rules)
{ {
gchar *pos; gchar *pos;
TimeZoneRule tzr; TimeZoneRule tzr;
g_assert (out_identifier != NULL);
g_assert (rules != NULL);
*out_identifier = NULL;
*rules = NULL;
if (!identifier) if (!identifier)
return 0; return 0;
@ -1233,7 +1295,10 @@ rules_from_identifier (const gchar *identifier,
return 0; return 0;
if (*pos == 0) if (*pos == 0)
return create_ruleset_from_rule (rules, &tzr); {
*out_identifier = g_strdup (identifier);
return create_ruleset_from_rule (rules, &tzr);
}
/* Format 2 */ /* Format 2 */
if (!(set_tz_name (&pos, tzr.dlt_name, NAME_SIZE))) if (!(set_tz_name (&pos, tzr.dlt_name, NAME_SIZE)))
@ -1251,6 +1316,7 @@ rules_from_identifier (const gchar *identifier,
/* Use US rules, Windows' default is Pacific Standard Time */ /* Use US rules, Windows' default is Pacific Standard Time */
if ((rules_num = rules_from_windows_time_zone ("Pacific Standard Time", if ((rules_num = rules_from_windows_time_zone ("Pacific Standard Time",
out_identifier,
rules))) rules)))
{ {
for (i = 0; i < rules_num - 1; i++) for (i = 0; i < rules_num - 1; i++)
@ -1273,6 +1339,7 @@ rules_from_identifier (const gchar *identifier,
if (!parse_identifier_boundaries (&pos, &tzr)) if (!parse_identifier_boundaries (&pos, &tzr))
return 0; return 0;
*out_identifier = g_strdup (identifier);
return create_ruleset_from_rule (rules, &tzr); return create_ruleset_from_rule (rules, &tzr);
} }
@ -1355,6 +1422,7 @@ g_time_zone_new (const gchar *identifier)
GTimeZone *tz = NULL; GTimeZone *tz = NULL;
TimeZoneRule *rules; TimeZoneRule *rules;
gint rules_num; gint rules_num;
gchar *resolved_identifier = NULL;
G_LOCK (time_zones); G_LOCK (time_zones);
if (time_zones == NULL) if (time_zones == NULL)
@ -1372,42 +1440,41 @@ g_time_zone_new (const gchar *identifier)
} }
tz = g_slice_new0 (GTimeZone); tz = g_slice_new0 (GTimeZone);
tz->name = g_strdup (identifier);
tz->ref_count = 0; tz->ref_count = 0;
zone_for_constant_offset (tz, identifier); zone_for_constant_offset (tz, identifier);
if (tz->t_info == NULL && if (tz->t_info == NULL &&
(rules_num = rules_from_identifier (identifier, &rules))) (rules_num = rules_from_identifier (identifier, &resolved_identifier, &rules)))
{ {
init_zone_from_rules (tz, rules, rules_num); init_zone_from_rules (tz, rules, rules_num, g_steal_pointer (&resolved_identifier));
g_free (rules); g_free (rules);
} }
if (tz->t_info == NULL) if (tz->t_info == NULL)
{ {
#ifdef G_OS_UNIX #ifdef G_OS_UNIX
GBytes *zoneinfo = zone_info_unix (identifier); GBytes *zoneinfo = zone_info_unix (identifier, &resolved_identifier);
if (!zoneinfo) if (zoneinfo != NULL)
zone_for_constant_offset (tz, "UTC");
else
{ {
init_zone_from_iana_info (tz, zoneinfo); init_zone_from_iana_info (tz, zoneinfo, g_steal_pointer (&resolved_identifier));
g_bytes_unref (zoneinfo); g_bytes_unref (zoneinfo);
} }
#elif defined (G_OS_WIN32) #elif defined (G_OS_WIN32)
if ((rules_num = rules_from_windows_time_zone (identifier, &rules))) if ((rules_num = rules_from_windows_time_zone (identifier,
&resolved_identifier,
&rules)))
{ {
init_zone_from_rules (tz, rules, rules_num); init_zone_from_rules (tz, rules, rules_num, g_steal_pointer (&resolved_identifier));
g_free (rules); g_free (rules);
} }
#endif
} }
#if defined (G_OS_WIN32)
if (tz->t_info == NULL) if (tz->t_info == NULL)
{ {
if (identifier) if (identifier == NULL)
zone_for_constant_offset (tz, "UTC");
else
{ {
TIME_ZONE_INFORMATION tzi; TIME_ZONE_INFORMATION tzi;
@ -1423,13 +1490,22 @@ g_time_zone_new (const gchar *identifier)
rules[0].start_year = MIN_TZYEAR; rules[0].start_year = MIN_TZYEAR;
rules[1].start_year = MAX_TZYEAR; rules[1].start_year = MAX_TZYEAR;
init_zone_from_rules (tz, rules, 2); init_zone_from_rules (tz, rules, 2, windows_default_tzname ());
g_free (rules); g_free (rules);
} }
} }
#endif
} }
#endif
g_free (resolved_identifier);
/* Always fall back to UTC. */
if (tz->t_info == NULL)
zone_for_constant_offset (tz, "UTC");
g_assert (tz->name != NULL);
g_assert (tz->t_info != NULL);
if (tz->t_info != NULL) if (tz->t_info != NULL)
{ {
@ -1835,5 +1911,29 @@ g_time_zone_is_dst (GTimeZone *tz,
return interval_isdst (tz, (guint)interval); return interval_isdst (tz, (guint)interval);
} }
/**
* g_time_zone_get_identifier:
* @tz: a #GTimeZone
*
* Get the identifier of this #GTimeZone, as passed to g_time_zone_new().
* If the identifier passed at construction time was not recognised, `UTC` will
* be returned. If it was %NULL, the identifier of the local timezone at
* construction time will be returned.
*
* The identifier will be returned in the same format as provided at
* construction time: if provided as a time offset, that will be returned by
* this function.
*
* Returns: identifier for this timezone
* Since: 2.58
*/
const gchar *
g_time_zone_get_identifier (GTimeZone *tz)
{
g_return_val_if_fail (tz != NULL, NULL);
return tz->name;
}
/* Epilogue {{{1 */ /* Epilogue {{{1 */
/* vim:set foldmethod=marker: */ /* vim:set foldmethod=marker: */

View File

@ -83,6 +83,8 @@ gint32 g_time_zone_get_offset (GTimeZo
GLIB_AVAILABLE_IN_ALL GLIB_AVAILABLE_IN_ALL
gboolean g_time_zone_is_dst (GTimeZone *tz, gboolean g_time_zone_is_dst (GTimeZone *tz,
gint interval); gint interval);
GLIB_AVAILABLE_IN_2_58
const gchar * g_time_zone_get_identifier (GTimeZone *tz);
G_END_DECLS G_END_DECLS

View File

@ -1024,7 +1024,7 @@ test_GDateTime_get_second (void)
static void static void
test_GDateTime_new_full (void) test_GDateTime_new_full (void)
{ {
GTimeZone *tz; GTimeZone *tz, *dt_tz;
GDateTime *dt; GDateTime *dt;
dt = g_date_time_new_utc (2009, 12, 11, 12, 11, 10); dt = g_date_time_new_utc (2009, 12, 11, 12, 11, 10);
@ -1042,7 +1042,11 @@ test_GDateTime_new_full (void)
tz = g_time_zone_new ("Pacific Standard Time"); tz = g_time_zone_new ("Pacific Standard Time");
#endif #endif
dt = g_date_time_new (tz, 2010, 11, 24, 8, 4, 0); dt = g_date_time_new (tz, 2010, 11, 24, 8, 4, 0);
g_time_zone_unref (tz);
dt_tz = g_date_time_get_timezone (dt);
g_assert_cmpstr (g_time_zone_get_identifier (dt_tz), ==,
g_time_zone_get_identifier (tz));
g_assert_cmpint (2010, ==, g_date_time_get_year (dt)); g_assert_cmpint (2010, ==, g_date_time_get_year (dt));
g_assert_cmpint (11, ==, g_date_time_get_month (dt)); g_assert_cmpint (11, ==, g_date_time_get_month (dt));
g_assert_cmpint (24, ==, g_date_time_get_day_of_month (dt)); g_assert_cmpint (24, ==, g_date_time_get_day_of_month (dt));
@ -1051,12 +1055,16 @@ test_GDateTime_new_full (void)
g_assert_cmpint (0, ==, g_date_time_get_second (dt)); g_assert_cmpint (0, ==, g_date_time_get_second (dt));
#ifdef G_OS_UNIX #ifdef G_OS_UNIX
g_assert_cmpstr ("PST", ==, g_date_time_get_timezone_abbreviation (dt)); g_assert_cmpstr ("PST", ==, g_date_time_get_timezone_abbreviation (dt));
g_assert_cmpstr ("America/Tijuana", ==, g_time_zone_get_identifier (dt_tz));
#elif defined G_OS_WIN32 #elif defined G_OS_WIN32
g_assert_cmpstr ("Pacific Standard Time", ==, g_assert_cmpstr ("Pacific Standard Time", ==,
g_date_time_get_timezone_abbreviation (dt)); g_date_time_get_timezone_abbreviation (dt));
g_assert_cmpstr ("Pacific Standard Time", ==,
g_time_zone_get_identifier (dt_tz));
#endif #endif
g_assert (!g_date_time_is_daylight_savings (dt)); g_assert (!g_date_time_is_daylight_savings (dt));
g_date_time_unref (dt); g_date_time_unref (dt);
g_time_zone_unref (tz);
/* Check month limits */ /* Check month limits */
dt = g_date_time_new_utc (2016, 1, 31, 22, 10, 42); dt = g_date_time_new_utc (2016, 1, 31, 22, 10, 42);
@ -2084,6 +2092,7 @@ test_no_header (void)
tz = g_time_zone_new ("blabla"); tz = g_time_zone_new ("blabla");
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "UTC"); g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "UTC");
g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 0); g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 0);
g_assert (!g_time_zone_is_dst (tz, 0)); g_assert (!g_time_zone_is_dst (tz, 0));
@ -2098,12 +2107,14 @@ test_posix_parse (void)
GDateTime *gdt1, *gdt2; GDateTime *gdt1, *gdt2;
tz = g_time_zone_new ("PST"); tz = g_time_zone_new ("PST");
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "UTC"); g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "UTC");
g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 0); g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 0);
g_assert (!g_time_zone_is_dst (tz, 0)); g_assert (!g_time_zone_is_dst (tz, 0));
g_time_zone_unref (tz); g_time_zone_unref (tz);
tz = g_time_zone_new ("PST8"); tz = g_time_zone_new ("PST8");
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "PST8");
g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "PST"); g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "PST");
g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, - 8 * 3600); g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, - 8 * 3600);
g_assert (!g_time_zone_is_dst (tz, 0)); g_assert (!g_time_zone_is_dst (tz, 0));
@ -2113,6 +2124,7 @@ test_posix_parse (void)
* but passes anyway because PST8PDT is a zone name. * but passes anyway because PST8PDT is a zone name.
*/ */
tz = g_time_zone_new ("PST8PDT"); tz = g_time_zone_new ("PST8PDT");
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "PST8PDT");
g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "PST"); g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "PST");
g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, - 8 * 3600); g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, - 8 * 3600);
g_assert (!g_time_zone_is_dst (tz, 0)); g_assert (!g_time_zone_is_dst (tz, 0));
@ -2123,6 +2135,7 @@ test_posix_parse (void)
tz = g_time_zone_new ("PST8PDT6:32:15"); tz = g_time_zone_new ("PST8PDT6:32:15");
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "PST8PDT6:32:15");
g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "PST"); g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "PST");
g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, - 8 * 3600); g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, - 8 * 3600);
g_assert (!g_time_zone_is_dst (tz, 0)); g_assert (!g_time_zone_is_dst (tz, 0));
@ -2138,6 +2151,7 @@ test_posix_parse (void)
g_date_time_unref (gdt1); g_date_time_unref (gdt1);
g_date_time_unref (gdt2); g_date_time_unref (gdt2);
#else #else
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "UTC"); g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "UTC");
g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 0); g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 0);
g_assert (!g_time_zone_is_dst (tz, 0)); g_assert (!g_time_zone_is_dst (tz, 0));
@ -2145,6 +2159,7 @@ test_posix_parse (void)
g_time_zone_unref (tz); g_time_zone_unref (tz);
tz = g_time_zone_new ("NZST-12:00:00NZDT-13:00:00,M10.1.0,M3.3.0"); tz = g_time_zone_new ("NZST-12:00:00NZDT-13:00:00,M10.1.0,M3.3.0");
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "NZST-12:00:00NZDT-13:00:00,M10.1.0,M3.3.0");
g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "NZST"); g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "NZST");
g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 12 * 3600); g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 12 * 3600);
g_assert (!g_time_zone_is_dst (tz, 0)); g_assert (!g_time_zone_is_dst (tz, 0));
@ -2170,6 +2185,7 @@ test_posix_parse (void)
g_time_zone_unref (tz); g_time_zone_unref (tz);
tz = g_time_zone_new ("NZST-12:00:00NZDT-13:00:00,280,77"); tz = g_time_zone_new ("NZST-12:00:00NZDT-13:00:00,280,77");
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "NZST-12:00:00NZDT-13:00:00,280,77");
g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "NZST"); g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "NZST");
g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 12 * 3600); g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 12 * 3600);
g_assert (!g_time_zone_is_dst (tz, 0)); g_assert (!g_time_zone_is_dst (tz, 0));
@ -2195,6 +2211,7 @@ test_posix_parse (void)
g_time_zone_unref (tz); g_time_zone_unref (tz);
tz = g_time_zone_new ("NZST-12:00:00NZDT-13:00:00,J279,J76"); tz = g_time_zone_new ("NZST-12:00:00NZDT-13:00:00,J279,J76");
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "NZST-12:00:00NZDT-13:00:00,J279,J76");
g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "NZST"); g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "NZST");
g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 12 * 3600); g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 12 * 3600);
g_assert (!g_time_zone_is_dst (tz, 0)); g_assert (!g_time_zone_is_dst (tz, 0));
@ -2220,6 +2237,7 @@ test_posix_parse (void)
g_time_zone_unref (tz); g_time_zone_unref (tz);
tz = g_time_zone_new ("NZST-12:00:00NZDT-13:00:00,M10.1.0/07:00,M3.3.0/07:00"); tz = g_time_zone_new ("NZST-12:00:00NZDT-13:00:00,M10.1.0/07:00,M3.3.0/07:00");
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "NZST-12:00:00NZDT-13:00:00,M10.1.0/07:00,M3.3.0/07:00");
g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "NZST"); g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "NZST");
g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 12 * 3600); g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 12 * 3600);
g_assert (!g_time_zone_is_dst (tz, 0)); g_assert (!g_time_zone_is_dst (tz, 0));
@ -2278,12 +2296,72 @@ test_GDateTime_floating_point (void)
g_test_bug ("697715"); g_test_bug ("697715");
tz = g_time_zone_new ("-03:00"); tz = g_time_zone_new ("-03:00");
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "-03:00");
dt = g_date_time_new (tz, 2010, 5, 24, 8, 0, 1.000001); dt = g_date_time_new (tz, 2010, 5, 24, 8, 0, 1.000001);
g_time_zone_unref (tz); g_time_zone_unref (tz);
g_assert_cmpint (g_date_time_get_microsecond (dt), ==, 1); g_assert_cmpint (g_date_time_get_microsecond (dt), ==, 1);
g_date_time_unref (dt); g_date_time_unref (dt);
} }
/* Check that g_time_zone_get_identifier() returns the identifier given to
* g_time_zone_new(), or "UTC" if loading the timezone failed. */
static void
test_identifier (void)
{
GTimeZone *tz;
gchar *old_tz = g_strdup (g_getenv ("TZ"));
tz = g_time_zone_new ("UTC");
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
g_time_zone_unref (tz);
tz = g_time_zone_new_utc ();
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
g_time_zone_unref (tz);
tz = g_time_zone_new ("some rubbish");
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
g_time_zone_unref (tz);
tz = g_time_zone_new ("Z");
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "Z");
g_time_zone_unref (tz);
tz = g_time_zone_new ("+03:15");
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "+03:15");
g_time_zone_unref (tz);
/* System timezone. We cant change this, but we can at least assert that
* the identifier is non-NULL and doesnt start with a slash. */
tz = g_time_zone_new (NULL);
g_assert_nonnull (g_time_zone_get_identifier (tz));
g_assert_cmpstr (g_time_zone_get_identifier (tz), !=, "");
g_assert_true (*g_time_zone_get_identifier (tz) != '/');
g_time_zone_unref (tz);
/* Local timezone tests. */
if (g_setenv ("TZ", "America/Recife", TRUE))
{
tz = g_time_zone_new_local ();
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "America/Recife");
g_time_zone_unref (tz);
}
if (g_setenv ("TZ", "some rubbish", TRUE))
{
tz = g_time_zone_new_local ();
g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
g_time_zone_unref (tz);
}
if (old_tz != NULL)
g_assert_true (g_setenv ("TZ", old_tz, TRUE));
else
g_unsetenv ("TZ");
g_free (old_tz);
}
gint gint
main (gint argc, main (gint argc,
gchar *argv[]) gchar *argv[])
@ -2345,6 +2423,7 @@ main (gint argc,
g_test_add_func ("/GTimeZone/no-header", test_no_header); g_test_add_func ("/GTimeZone/no-header", test_no_header);
g_test_add_func ("/GTimeZone/posix-parse", test_posix_parse); g_test_add_func ("/GTimeZone/posix-parse", test_posix_parse);
g_test_add_func ("/GTimeZone/floating-point", test_GDateTime_floating_point); g_test_add_func ("/GTimeZone/floating-point", test_GDateTime_floating_point);
g_test_add_func ("/GTimeZone/identifier", test_identifier);
return g_test_run (); return g_test_run ();
} }