diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index c02b22a67..f6322f052 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -1648,6 +1648,7 @@ g_time_zone_ref g_time_zone_new g_time_zone_new_local g_time_zone_new_utc +g_time_zone_new_offset GTimeType g_time_zone_find_interval diff --git a/glib/gtimezone.c b/glib/gtimezone.c index 311fe0289..b08119b13 100644 --- a/glib/gtimezone.c +++ b/glib/gtimezone.c @@ -1562,6 +1562,42 @@ g_time_zone_new_local (void) return g_time_zone_new (getenv ("TZ")); } +/** + * g_time_zone_new_offset: + * @seconds: offset to UTC, in seconds + * + * Creates a #GTimeZone corresponding to the given constant offset from UTC, + * in seconds. + * + * This is equivalent to calling g_time_zone_new() with a string in the form + * `[+|-]hh[:mm[:ss]]`. + * + * Returns: (transfer full): a timezone at the given offset from UTC + * Since: 2.58 + */ +GTimeZone * +g_time_zone_new_offset (gint32 seconds) +{ + GTimeZone *tz = NULL; + gchar *identifier = NULL; + + /* Seemingly, we should be using @seconds directly to set the + * #TransitionInfo.gmt_offset to avoid all this string building and parsing. + * However, we always need to set the #GTimeZone.name to a constructed + * string anyway, so we might as well reuse its code. */ + identifier = g_strdup_printf ("%c%02u:%02u:%02u", + (seconds >= 0) ? '+' : '-', + (ABS (seconds) / 60) / 60, + (ABS (seconds) / 60) % 60, + ABS (seconds) % 60); + tz = g_time_zone_new (identifier); + g_free (identifier); + + g_assert (g_time_zone_get_offset (tz, 0) == seconds); + + return tz; +} + #define TRANSITION(n) g_array_index (tz->transitions, Transition, n) #define TRANSITION_INFO(n) g_array_index (tz->t_info, TransitionInfo, n) diff --git a/glib/gtimezone.h b/glib/gtimezone.h index dd10390ab..4e8b10a71 100644 --- a/glib/gtimezone.h +++ b/glib/gtimezone.h @@ -58,6 +58,8 @@ GLIB_AVAILABLE_IN_ALL GTimeZone * g_time_zone_new_utc (void); GLIB_AVAILABLE_IN_ALL GTimeZone * g_time_zone_new_local (void); +GLIB_AVAILABLE_IN_2_58 +GTimeZone * g_time_zone_new_offset (gint32 seconds); GLIB_AVAILABLE_IN_ALL GTimeZone * g_time_zone_ref (GTimeZone *tz); diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c index 1bd8203ad..b102205b9 100644 --- a/glib/tests/gdatetime.c +++ b/glib/tests/gdatetime.c @@ -2362,6 +2362,40 @@ test_identifier (void) g_free (old_tz); } +/* Test various calls to g_time_zone_new_offset(). */ +static void +test_new_offset (void) +{ + const gint32 vectors[] = + { + -10000, + -3600, + -61, + -60, + -59, + 0, + 59, + 60, + 61, + 3600, + 10000, + }; + gsize i; + + for (i = 0; i < G_N_ELEMENTS (vectors); i++) + { + GTimeZone *tz = NULL; + + g_test_message ("Vector %" G_GSIZE_FORMAT ": %d", i, vectors[i]); + + tz = g_time_zone_new_offset (vectors[i]); + g_assert_nonnull (tz); + g_assert_cmpstr (g_time_zone_get_identifier (tz), !=, "UTC"); + g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, vectors[i]); + g_time_zone_unref (tz); + } +} + gint main (gint argc, gchar *argv[]) @@ -2424,6 +2458,7 @@ main (gint argc, 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/identifier", test_identifier); + g_test_add_func ("/GTimeZone/new-offset", test_new_offset); return g_test_run (); }