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
<SUBSECTION>
g_time_zone_new
g_time_zone_new_identifier
g_time_zone_new_local
g_time_zone_new_utc
g_time_zone_new_offset

View File

@ -1604,7 +1604,36 @@ parse_footertz (const gchar *footer, size_t footerlen)
* g_time_zone_new:
* @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
* 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()
* when you are done with it.
*
* Returns: the requested timezone
*
* Since: 2.26
**/
* Returns: (transfer full) (nullable): the requested timezone, or %NULL on
* failure
* Since: 2.68
*/
GTimeZone *
g_time_zone_new (const gchar *identifier)
g_time_zone_new_identifier (const gchar *identifier)
{
GTimeZone *tz = NULL;
TimeZoneRule *rules;
@ -1788,24 +1817,31 @@ g_time_zone_new (const gchar *identifier)
g_free (resolved_identifier);
/* Always fall back to UTC. */
/* Failed to load the timezone. */
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->t_info != NULL);
if (tz->t_info != NULL)
if (identifier)
g_hash_table_insert (time_zones, tz->name, tz);
else if (tz->name)
{
if (identifier)
g_hash_table_insert (time_zones, tz->name, tz);
else if (tz->name)
{
/* Caching reference */
g_atomic_int_inc (&tz->ref_count);
tz_default = tz;
}
/* Caching reference */
g_atomic_int_inc (&tz->ref_count);
tz_default = tz;
}
g_atomic_int_inc (&tz->ref_count);
if (identifier)

View File

@ -24,6 +24,7 @@
#error "Only <glib.h> can be included directly."
#endif
#include <glib/gerror.h>
#include <glib/gtypes.h>
G_BEGIN_DECLS
@ -54,6 +55,8 @@ typedef enum
GLIB_AVAILABLE_IN_ALL
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
GTimeZone * g_time_zone_new_utc (void);
GLIB_AVAILABLE_IN_ALL

View File

@ -2398,6 +2398,16 @@ test_no_header (void)
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
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/adjust-time", test_adjust_time);
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/floating-point", test_GDateTime_floating_point);
g_test_add_func ("/GTimeZone/identifier", test_identifier);