From 54c394a73f95eb225fd748aef9a7205d45ff16fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= <tomasz.miasko@gmail.com>
Date: Wed, 31 Oct 2018 00:00:00 +0000
Subject: [PATCH 205/682] 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.
---
 glib/gdatetime.c       | 17 +++++++++++------
 glib/tests/gdatetime.c | 22 ++++++++++++++++++++++
 2 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/glib/gdatetime.c b/glib/gdatetime.c
index 1bd916587..32fd501aa 100644
--- a/glib/gdatetime.c
+++ b/glib/gdatetime.c
@@ -2721,34 +2721,39 @@ format_z (GString *outstr,
   gint hours;
   gint minutes;
   gint seconds;
+  gchar sign = offset >= 0 ? '+' : '-';
 
+  offset = ABS (offset);
   hours = offset / 3600;
-  minutes = ABS (offset) / 60 % 60;
-  seconds = ABS (offset) % 60;
+  minutes = offset / 60 % 60;
+  seconds = offset % 60;
 
   switch (colons)
     {
     case 0:
-      g_string_append_printf (outstr, "%+03d%02d",
+      g_string_append_printf (outstr, "%c%02d%02d",
+                              sign,
                               hours,
                               minutes);
       break;
 
     case 1:
-      g_string_append_printf (outstr, "%+03d:%02d",
+      g_string_append_printf (outstr, "%c%02d:%02d",
+                              sign,
                               hours,
                               minutes);
       break;
 
     case 2:
-      g_string_append_printf (outstr, "%+03d:%02d:%02d",
+      g_string_append_printf (outstr, "%c%02d:%02d:%02d",
+                              sign,
                               hours,
                               minutes,
                               seconds);
       break;
 
     case 3:
-      g_string_append_printf (outstr, "%+03d", hours);
+      g_string_append_printf (outstr, "%c%02d", sign, hours);
 
       if (minutes != 0 || seconds != 0)
         {
diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c
index a028f6d20..f4000d96c 100644
--- a/glib/tests/gdatetime.c
+++ b/glib/tests/gdatetime.c
@@ -1986,6 +1986,28 @@ test_z (void)
   g_free (p);
   g_date_time_unref (dt);
   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
-- 
2.19.1

