gtimezone: Add new constructor which can report errors

Add a new variant of `g_time_zone_new()` which returns `NULL` on
failure to load a timezone, rather than silently returning UTC.

Signed-off-by: Philip Withnall <pwithnall@endlessos.org>

Fixes: #553
This commit is contained in:
Philip Withnall
2020-11-18 11:31:15 +00:00
parent fe5217bc2b
commit 8105c36e84
4 changed files with 68 additions and 17 deletions

View File

@@ -1939,6 +1939,7 @@ g_time_zone_unref
g_time_zone_ref g_time_zone_ref
<SUBSECTION> <SUBSECTION>
g_time_zone_new g_time_zone_new
g_time_zone_new_identifier
g_time_zone_new_local g_time_zone_new_local
g_time_zone_new_utc g_time_zone_new_utc
g_time_zone_new_offset g_time_zone_new_offset

View File

@@ -1604,7 +1604,36 @@ parse_footertz (const gchar *footer, size_t footerlen)
* g_time_zone_new: * g_time_zone_new:
* @identifier: (nullable): a timezone identifier * @identifier: (nullable): a timezone identifier
* *
* Creates a #GTimeZone corresponding to @identifier. * A version of g_time_zone_new_identifier() which returns the UTC time zone
* if @identifier could not be parsed or loaded.
*
* If you need to check whether @identifier was loaded successfully, use
* g_time_zone_new_identifier().
*
* Returns: (transfer full) (not nullable): the requested timezone
*
* Since: 2.26
**/
GTimeZone *
g_time_zone_new (const gchar *identifier)
{
GTimeZone *tz = g_time_zone_new_identifier (identifier);
/* Always fall back to UTC. */
if (tz == NULL)
tz = g_time_zone_new_utc ();
g_assert (tz != NULL);
return g_steal_pointer (&tz);
}
/**
* g_time_zone_new_identifier:
* @identifier: (nullable): a timezone identifier
*
* Creates a #GTimeZone corresponding to @identifier. If @identifier cannot be
* parsed or loaded, %NULL is returned.
* *
* @identifier can either be an RFC3339/ISO 8601 time offset or * @identifier can either be an RFC3339/ISO 8601 time offset or
* something that would pass as a valid value for the `TZ` environment * something that would pass as a valid value for the `TZ` environment
@@ -1669,12 +1698,12 @@ parse_footertz (const gchar *footer, size_t footerlen)
* You should release the return value by calling g_time_zone_unref() * You should release the return value by calling g_time_zone_unref()
* when you are done with it. * when you are done with it.
* *
* Returns: the requested timezone * Returns: (transfer full) (nullable): the requested timezone, or %NULL on
* * failure
* Since: 2.26 * Since: 2.68
**/ */
GTimeZone * GTimeZone *
g_time_zone_new (const gchar *identifier) g_time_zone_new_identifier (const gchar *identifier)
{ {
GTimeZone *tz = NULL; GTimeZone *tz = NULL;
TimeZoneRule *rules; TimeZoneRule *rules;
@@ -1788,15 +1817,22 @@ g_time_zone_new (const gchar *identifier)
g_free (resolved_identifier); g_free (resolved_identifier);
/* Always fall back to UTC. */ /* Failed to load the timezone. */
if (tz->t_info == NULL) if (tz->t_info == NULL)
zone_for_constant_offset (tz, "UTC"); {
g_slice_free (GTimeZone, tz);
if (identifier)
G_UNLOCK (time_zones);
else
G_UNLOCK (tz_default);
return NULL;
}
g_assert (tz->name != NULL); g_assert (tz->name != NULL);
g_assert (tz->t_info != NULL); g_assert (tz->t_info != NULL);
if (tz->t_info != NULL)
{
if (identifier) if (identifier)
g_hash_table_insert (time_zones, tz->name, tz); g_hash_table_insert (time_zones, tz->name, tz);
else if (tz->name) else if (tz->name)
@@ -1805,7 +1841,7 @@ g_time_zone_new (const gchar *identifier)
g_atomic_int_inc (&tz->ref_count); g_atomic_int_inc (&tz->ref_count);
tz_default = tz; tz_default = tz;
} }
}
g_atomic_int_inc (&tz->ref_count); g_atomic_int_inc (&tz->ref_count);
if (identifier) if (identifier)

View File

@@ -24,6 +24,7 @@
#error "Only <glib.h> can be included directly." #error "Only <glib.h> can be included directly."
#endif #endif
#include <glib/gerror.h>
#include <glib/gtypes.h> #include <glib/gtypes.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@@ -54,6 +55,8 @@ typedef enum
GLIB_AVAILABLE_IN_ALL GLIB_AVAILABLE_IN_ALL
GTimeZone * g_time_zone_new (const gchar *identifier); GTimeZone * g_time_zone_new (const gchar *identifier);
GLIB_AVAILABLE_IN_2_68
GTimeZone * g_time_zone_new_identifier (const gchar *identifier);
GLIB_AVAILABLE_IN_ALL GLIB_AVAILABLE_IN_ALL
GTimeZone * g_time_zone_new_utc (void); GTimeZone * g_time_zone_new_utc (void);
GLIB_AVAILABLE_IN_ALL GLIB_AVAILABLE_IN_ALL

View File

@@ -2398,6 +2398,16 @@ test_no_header (void)
g_time_zone_unref (tz); g_time_zone_unref (tz);
} }
static void
test_no_header_identifier (void)
{
GTimeZone *tz;
tz = g_time_zone_new_identifier ("blabla");
g_assert_null (tz);
}
static void static void
test_posix_parse (void) test_posix_parse (void)
{ {
@@ -2893,6 +2903,7 @@ main (gint argc,
g_test_add_func ("/GTimeZone/find-interval", test_find_interval); g_test_add_func ("/GTimeZone/find-interval", test_find_interval);
g_test_add_func ("/GTimeZone/adjust-time", test_adjust_time); g_test_add_func ("/GTimeZone/adjust-time", test_adjust_time);
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/no-header-identifier", test_no_header_identifier);
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); g_test_add_func ("/GTimeZone/identifier", test_identifier);