gdatetime: Fix formatting of time zones offsets in range -01:00 to +00:00

Formatting code for `%z` specifier incorrectly assumed that sign of
offset from UTC can be recovered from the number of hours alone, which
is not true for offsets between -01:00 and +00:00.

Extract and format sign separately to avoid the problem.

Issue #1337.
This commit is contained in:
Tomasz Miąsko 2018-10-31 00:00:00 +00:00
parent 361fed5d75
commit 54c394a73f
2 changed files with 33 additions and 6 deletions

View File

@ -2721,34 +2721,39 @@ format_z (GString *outstr,
gint hours; gint hours;
gint minutes; gint minutes;
gint seconds; gint seconds;
gchar sign = offset >= 0 ? '+' : '-';
offset = ABS (offset);
hours = offset / 3600; hours = offset / 3600;
minutes = ABS (offset) / 60 % 60; minutes = offset / 60 % 60;
seconds = ABS (offset) % 60; seconds = offset % 60;
switch (colons) switch (colons)
{ {
case 0: case 0:
g_string_append_printf (outstr, "%+03d%02d", g_string_append_printf (outstr, "%c%02d%02d",
sign,
hours, hours,
minutes); minutes);
break; break;
case 1: case 1:
g_string_append_printf (outstr, "%+03d:%02d", g_string_append_printf (outstr, "%c%02d:%02d",
sign,
hours, hours,
minutes); minutes);
break; break;
case 2: case 2:
g_string_append_printf (outstr, "%+03d:%02d:%02d", g_string_append_printf (outstr, "%c%02d:%02d:%02d",
sign,
hours, hours,
minutes, minutes,
seconds); seconds);
break; break;
case 3: case 3:
g_string_append_printf (outstr, "%+03d", hours); g_string_append_printf (outstr, "%c%02d", sign, hours);
if (minutes != 0 || seconds != 0) if (minutes != 0 || seconds != 0)
{ {

View File

@ -1986,6 +1986,28 @@ test_z (void)
g_free (p); g_free (p);
g_date_time_unref (dt); g_date_time_unref (dt);
g_time_zone_unref (tz); g_time_zone_unref (tz);
tz = g_time_zone_new ("-00:15");
dt = g_date_time_new (tz, 1, 1, 1, 0, 0, 0);
p = g_date_time_format (dt, "%z");
g_assert_cmpstr (p, ==, "-0015");
g_free (p);
p = g_date_time_format (dt, "%:z");
g_assert_cmpstr (p, ==, "-00:15");
g_free (p);
p = g_date_time_format (dt, "%::z");
g_assert_cmpstr (p, ==, "-00:15:00");
g_free (p);
p = g_date_time_format (dt, "%:::z");
g_assert_cmpstr (p, ==, "-00:15");
g_free (p);
g_date_time_unref (dt);
g_time_zone_unref (tz);
} }
#pragma GCC diagnostic push #pragma GCC diagnostic push