Imported Upstream version 2.66.5
[platform/upstream/glib.git] / glib / tests / gdatetime.c
1 /* gdatetime-tests.c
2  *
3  * Copyright (C) 2009-2010 Christian Hergert <chris@dronelabs.com>
4  *
5  * This is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this library; if not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include "config.h"
20
21 #include <math.h>
22 #include <string.h>
23 #include <time.h>
24 #include <gi18n.h>
25 #include <glib.h>
26 #include <glib/gstdio.h>
27 #include <locale.h>
28
29 #ifdef G_OS_WIN32
30 #define WIN32_LEAN_AND_MEAN
31 #include <windows.h>
32
33 #ifndef NAN
34 #define NAN HUGE_VAL * 0.0f
35 #endif
36 #endif
37
38 #define ASSERT_DATE(dt,y,m,d) G_STMT_START { \
39   g_assert_nonnull ((dt)); \
40   g_assert_cmpint ((y), ==, g_date_time_get_year ((dt))); \
41   g_assert_cmpint ((m), ==, g_date_time_get_month ((dt))); \
42   g_assert_cmpint ((d), ==, g_date_time_get_day_of_month ((dt))); \
43 } G_STMT_END
44 #define ASSERT_TIME(dt,H,M,S,U) G_STMT_START { \
45   g_assert_nonnull ((dt)); \
46   g_assert_cmpint ((H), ==, g_date_time_get_hour ((dt))); \
47   g_assert_cmpint ((M), ==, g_date_time_get_minute ((dt))); \
48   g_assert_cmpint ((S), ==, g_date_time_get_second ((dt))); \
49   g_assert_cmpint ((U), ==, g_date_time_get_microsecond ((dt))); \
50 } G_STMT_END
51
52 static void
53 get_localtime_tm (time_t     time_,
54                   struct tm *retval)
55 {
56 #ifdef HAVE_LOCALTIME_R
57   localtime_r (&time_, retval);
58 #else
59   {
60     struct tm *ptm = localtime (&time_);
61
62     if (ptm == NULL)
63       {
64         /* Happens at least in Microsoft's C library if you pass a
65          * negative time_t. Use 2000-01-01 as default date.
66          */
67 #ifndef G_DISABLE_CHECKS
68         g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, "ptm != NULL");
69 #endif
70
71         retval->tm_mon = 0;
72         retval->tm_mday = 1;
73         retval->tm_year = 100;
74       }
75     else
76       memcpy ((void *) retval, (void *) ptm, sizeof (struct tm));
77   }
78 #endif /* HAVE_LOCALTIME_R */
79 }
80
81 static void
82 test_GDateTime_now (void)
83 {
84   GDateTime *dt;
85   struct tm tm;
86   time_t before;
87   time_t after;
88
89   /* before <= dt.to_unix() <= after, but the inequalities might not be
90    * equality if we're close to the boundary between seconds.
91    * We loop until before == after (and hence dt.to_unix() should equal both)
92    * to guard against that. */
93   do
94     {
95       before = g_get_real_time () / G_TIME_SPAN_SECOND;
96
97       memset (&tm, 0, sizeof (tm));
98       get_localtime_tm (before, &tm);
99
100       dt = g_date_time_new_now_local ();
101
102       after = g_get_real_time () / G_TIME_SPAN_SECOND;
103     }
104   while (before != after);
105
106   g_assert_cmpint (g_date_time_get_year (dt), ==, 1900 + tm.tm_year);
107   g_assert_cmpint (g_date_time_get_month (dt), ==, 1 + tm.tm_mon);
108   g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, tm.tm_mday);
109   g_assert_cmpint (g_date_time_get_hour (dt), ==, tm.tm_hour);
110   g_assert_cmpint (g_date_time_get_minute (dt), ==, tm.tm_min);
111   g_assert_cmpint (g_date_time_get_second (dt), ==, tm.tm_sec);
112
113   g_date_time_unref (dt);
114 }
115
116 static void
117 test_GDateTime_new_from_unix (void)
118 {
119   GDateTime *dt;
120   struct tm  tm;
121   time_t     t;
122
123   memset (&tm, 0, sizeof (tm));
124   t = time (NULL);
125   g_assert_cmpint (t, !=, (time_t) -1);
126   get_localtime_tm (t, &tm);
127
128   dt = g_date_time_new_from_unix_local (t);
129   g_assert_cmpint (g_date_time_get_year (dt), ==, 1900 + tm.tm_year);
130   g_assert_cmpint (g_date_time_get_month (dt), ==, 1 + tm.tm_mon);
131   g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, tm.tm_mday);
132   g_assert_cmpint (g_date_time_get_hour (dt), ==, tm.tm_hour);
133   g_assert_cmpint (g_date_time_get_minute (dt), ==, tm.tm_min);
134   g_assert_cmpint (g_date_time_get_second (dt), ==, tm.tm_sec);
135   g_date_time_unref (dt);
136
137   /* Choose 1990-01-01 04:00:00 because no DST leaps happened then. The more
138    * obvious 1990-01-01 00:00:00 was a DST leap in America/Lima (which has,
139    * confusingly, since stopped using DST). */
140   memset (&tm, 0, sizeof (tm));
141   tm.tm_year = 90;
142   tm.tm_mday = 1;
143   tm.tm_mon = 0;
144   tm.tm_hour = 4;
145   tm.tm_min = 0;
146   tm.tm_sec = 0;
147   tm.tm_isdst = -1;
148   t = mktime (&tm);
149
150   dt = g_date_time_new_from_unix_local (t);
151   g_assert_cmpint (g_date_time_get_year (dt), ==, 1990);
152   g_assert_cmpint (g_date_time_get_month (dt), ==, 1);
153   g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, 1);
154   g_assert_cmpint (g_date_time_get_hour (dt), ==, 4);
155   g_assert_cmpint (g_date_time_get_minute (dt), ==, 0);
156   g_assert_cmpint (g_date_time_get_second (dt), ==, 0);
157   g_date_time_unref (dt);
158 }
159
160 /* Check that trying to create a #GDateTime too far in the future (or past) reliably
161  * fails. Previously, the checks for this overflowed and it silently returned
162  * an incorrect #GDateTime. */
163 static void
164 test_GDateTime_new_from_unix_overflow (void)
165 {
166   GDateTime *dt;
167
168   g_test_bug ("http://bugzilla.gnome.org/782089");
169
170   dt = g_date_time_new_from_unix_utc (G_MAXINT64);
171   g_assert_null (dt);
172
173   dt = g_date_time_new_from_unix_local (G_MAXINT64);
174   g_assert_null (dt);
175
176   dt = g_date_time_new_from_unix_utc (G_MININT64);
177   g_assert_null (dt);
178
179   dt = g_date_time_new_from_unix_local (G_MININT64);
180   g_assert_null (dt);
181 }
182
183 static void
184 test_GDateTime_invalid (void)
185 {
186   GDateTime *dt;
187
188   g_test_bug ("http://bugzilla.gnome.org/702674");
189
190   dt = g_date_time_new_utc (2013, -2147483647, 31, 17, 15, 48);
191   g_assert (dt == NULL);
192 }
193
194 static void
195 test_GDateTime_compare (void)
196 {
197   GDateTime *dt1, *dt2;
198   gint       i;
199
200   dt1 = g_date_time_new_utc (2000, 1, 1, 0, 0, 0);
201
202   for (i = 1; i < 2000; i++)
203     {
204       dt2 = g_date_time_new_utc (i, 12, 31, 0, 0, 0);
205       g_assert_cmpint (1, ==, g_date_time_compare (dt1, dt2));
206       g_date_time_unref (dt2);
207     }
208
209   dt2 = g_date_time_new_utc (1999, 12, 31, 23, 59, 59);
210   g_assert_cmpint (1, ==, g_date_time_compare (dt1, dt2));
211   g_date_time_unref (dt2);
212
213   dt2 = g_date_time_new_utc (2000, 1, 1, 0, 0, 1);
214   g_assert_cmpint (-1, ==, g_date_time_compare (dt1, dt2));
215   g_date_time_unref (dt2);
216
217   dt2 = g_date_time_new_utc (2000, 1, 1, 0, 0, 0);
218   g_assert_cmpint (0, ==, g_date_time_compare (dt1, dt2));
219   g_date_time_unref (dt2);
220   g_date_time_unref (dt1);
221 }
222
223 static void
224 test_GDateTime_equal (void)
225 {
226   GDateTime *dt1, *dt2;
227   GTimeZone *tz;
228
229   dt1 = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
230   dt2 = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
231   g_assert (g_date_time_equal (dt1, dt2));
232   g_date_time_unref (dt1);
233   g_date_time_unref (dt2);
234
235   dt1 = g_date_time_new_local (2009, 10, 18, 0, 0, 0);
236   dt2 = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
237   g_assert (!g_date_time_equal (dt1, dt2));
238   g_date_time_unref (dt1);
239   g_date_time_unref (dt2);
240
241   /* UTC-0300 and not in DST */
242   tz = g_time_zone_new ("-03:00");
243   dt1 = g_date_time_new (tz, 2010, 5, 24,  8, 0, 0);
244   g_time_zone_unref (tz);
245   g_assert_cmpint (g_date_time_get_utc_offset (dt1) / G_USEC_PER_SEC, ==, (-3 * 3600));
246   /* UTC */
247   dt2 = g_date_time_new_utc (2010, 5, 24, 11, 0, 0);
248   g_assert_cmpint (g_date_time_get_utc_offset (dt2), ==, 0);
249
250   g_assert (g_date_time_equal (dt1, dt2));
251   g_date_time_unref (dt1);
252
253   /* America/Recife is in UTC-0300 */
254 #ifdef G_OS_UNIX
255   tz = g_time_zone_new ("America/Recife");
256 #elif defined G_OS_WIN32
257   tz = g_time_zone_new ("E. South America Standard Time");
258 #endif
259   dt1 = g_date_time_new (tz, 2010, 5, 24,  8, 0, 0);
260   g_time_zone_unref (tz);
261   g_assert_cmpint (g_date_time_get_utc_offset (dt1) / G_USEC_PER_SEC, ==, (-3 * 3600));
262   g_assert (g_date_time_equal (dt1, dt2));
263   g_date_time_unref (dt1);
264   g_date_time_unref (dt2);
265 }
266
267 static void
268 test_GDateTime_get_day_of_week (void)
269 {
270   GDateTime *dt;
271
272   dt = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
273   g_assert_cmpint (1, ==, g_date_time_get_day_of_week (dt));
274   g_date_time_unref (dt);
275
276   dt = g_date_time_new_local (2000, 10, 1, 0, 0, 0);
277   g_assert_cmpint (7, ==, g_date_time_get_day_of_week (dt));
278   g_date_time_unref (dt);
279 }
280
281 static void
282 test_GDateTime_get_day_of_month (void)
283 {
284   GDateTime *dt;
285
286   dt = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
287   g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, 19);
288   g_date_time_unref (dt);
289
290   dt = g_date_time_new_local (1400, 3, 12, 0, 0, 0);
291   g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, 12);
292   g_date_time_unref (dt);
293
294   dt = g_date_time_new_local (1800, 12, 31, 0, 0, 0);
295   g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, 31);
296   g_date_time_unref (dt);
297
298   dt = g_date_time_new_local (1000, 1, 1, 0, 0, 0);
299   g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, 1);
300   g_date_time_unref (dt);
301 }
302
303 static void
304 test_GDateTime_get_hour (void)
305 {
306   GDateTime *dt;
307
308   dt = g_date_time_new_utc (2009, 10, 19, 15, 13, 11);
309   g_assert_cmpint (15, ==, g_date_time_get_hour (dt));
310   g_date_time_unref (dt);
311
312   dt = g_date_time_new_utc (100, 10, 19, 1, 0, 0);
313   g_assert_cmpint (1, ==, g_date_time_get_hour (dt));
314   g_date_time_unref (dt);
315
316   dt = g_date_time_new_utc (100, 10, 19, 0, 0, 0);
317   g_assert_cmpint (0, ==, g_date_time_get_hour (dt));
318   g_date_time_unref (dt);
319
320   dt = g_date_time_new_utc (100, 10, 1, 23, 59, 59);
321   g_assert_cmpint (23, ==, g_date_time_get_hour (dt));
322   g_date_time_unref (dt);
323 }
324
325 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
326 static void
327 test_GDateTime_get_microsecond (void)
328 {
329   GTimeVal   tv;
330   GDateTime *dt;
331
332   g_get_current_time (&tv);
333   dt = g_date_time_new_from_timeval_local (&tv);
334   g_assert_cmpint (tv.tv_usec, ==, g_date_time_get_microsecond (dt));
335   g_date_time_unref (dt);
336 }
337 G_GNUC_END_IGNORE_DEPRECATIONS
338
339 static void
340 test_GDateTime_get_year (void)
341 {
342   GDateTime *dt;
343
344   dt = g_date_time_new_local (2009, 1, 1, 0, 0, 0);
345   g_assert_cmpint (2009, ==, g_date_time_get_year (dt));
346   g_date_time_unref (dt);
347
348   dt = g_date_time_new_local (1, 1, 1, 0, 0, 0);
349   g_assert_cmpint (1, ==, g_date_time_get_year (dt));
350   g_date_time_unref (dt);
351
352   dt = g_date_time_new_local (13, 1, 1, 0, 0, 0);
353   g_assert_cmpint (13, ==, g_date_time_get_year (dt));
354   g_date_time_unref (dt);
355
356   dt = g_date_time_new_local (3000, 1, 1, 0, 0, 0);
357   g_assert_cmpint (3000, ==, g_date_time_get_year (dt));
358   g_date_time_unref (dt);
359 }
360
361 static void
362 test_GDateTime_hash (void)
363 {
364   GHashTable *h;
365
366   h = g_hash_table_new_full (g_date_time_hash, g_date_time_equal,
367                              (GDestroyNotify)g_date_time_unref,
368                              NULL);
369   g_hash_table_add (h, g_date_time_new_now_local ());
370   g_hash_table_remove_all (h);
371   g_hash_table_destroy (h);
372 }
373
374 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
375 static void
376 test_GDateTime_new_from_timeval (void)
377 {
378   GDateTime *dt;
379   GTimeVal   tv, tv2;
380
381   g_get_current_time (&tv);
382   dt = g_date_time_new_from_timeval_local (&tv);
383
384   if (g_test_verbose ())
385     g_printerr ("\nDT%04d-%02d-%02dT%02d:%02d:%02d%s\n",
386              g_date_time_get_year (dt),
387              g_date_time_get_month (dt),
388              g_date_time_get_day_of_month (dt),
389              g_date_time_get_hour (dt),
390              g_date_time_get_minute (dt),
391              g_date_time_get_second (dt),
392              g_date_time_get_timezone_abbreviation (dt));
393
394   g_date_time_to_timeval (dt, &tv2);
395   g_assert_cmpint (tv.tv_sec, ==, tv2.tv_sec);
396   g_assert_cmpint (tv.tv_usec, ==, tv2.tv_usec);
397   g_date_time_unref (dt);
398 }
399
400 static glong
401 find_maximum_supported_tv_sec (void)
402 {
403   glong highest_success = 0, lowest_failure = G_MAXLONG;
404   GTimeVal tv;
405   GDateTime *dt = NULL;
406
407   tv.tv_usec = 0;
408
409   /* Corner case of all glong values being valid. */
410   tv.tv_sec = G_MAXLONG;
411   dt = g_date_time_new_from_timeval_utc (&tv);
412   if (dt != NULL)
413     {
414       highest_success = tv.tv_sec;
415       g_date_time_unref (dt);
416     }
417
418   while (highest_success < lowest_failure - 1)
419     {
420       tv.tv_sec = highest_success + (lowest_failure - highest_success) / 2;
421       dt = g_date_time_new_from_timeval_utc (&tv);
422
423       if (dt != NULL)
424         {
425           highest_success = tv.tv_sec;
426           g_date_time_unref (dt);
427         }
428       else
429         {
430           lowest_failure = tv.tv_sec;
431         }
432     }
433
434   return highest_success;
435 }
436
437 /* Check that trying to create a #GDateTime too far in the future reliably
438  * fails. With a #GTimeVal, this is subtle, as the tv_usec are added into the
439  * calculation part-way through.
440  *
441  * This varies a bit between 32- and 64-bit architectures, due to the
442  * differences in the size of glong (tv.tv_sec). */
443 static void
444 test_GDateTime_new_from_timeval_overflow (void)
445 {
446   GDateTime *dt;
447   GTimeVal tv;
448
449   g_test_bug ("http://bugzilla.gnome.org/782089");
450
451   tv.tv_sec = find_maximum_supported_tv_sec ();
452   tv.tv_usec = G_USEC_PER_SEC - 1;
453
454   g_test_message ("Maximum supported GTimeVal.tv_sec = %lu", tv.tv_sec);
455
456   /* Sanity check: do we support the year 2000? */
457   g_assert_cmpint (tv.tv_sec, >=, 946684800);
458
459   dt = g_date_time_new_from_timeval_utc (&tv);
460   g_assert_nonnull (dt);
461   g_date_time_unref (dt);
462
463   if (tv.tv_sec < G_MAXLONG)
464     {
465       tv.tv_sec++;
466       tv.tv_usec = 0;
467
468       dt = g_date_time_new_from_timeval_utc (&tv);
469       g_assert_null (dt);
470     }
471 }
472
473 static void
474 test_GDateTime_new_from_timeval_utc (void)
475 {
476   GDateTime *dt;
477   GTimeVal   tv, tv2;
478
479   g_get_current_time (&tv);
480   dt = g_date_time_new_from_timeval_utc (&tv);
481
482   if (g_test_verbose ())
483     g_printerr ("\nDT%04d-%02d-%02dT%02d:%02d:%02d%s\n",
484              g_date_time_get_year (dt),
485              g_date_time_get_month (dt),
486              g_date_time_get_day_of_month (dt),
487              g_date_time_get_hour (dt),
488              g_date_time_get_minute (dt),
489              g_date_time_get_second (dt),
490              g_date_time_get_timezone_abbreviation (dt));
491
492   g_date_time_to_timeval (dt, &tv2);
493   g_assert_cmpint (tv.tv_sec, ==, tv2.tv_sec);
494   g_assert_cmpint (tv.tv_usec, ==, tv2.tv_usec);
495   g_date_time_unref (dt);
496 }
497 G_GNUC_END_IGNORE_DEPRECATIONS
498
499 static void
500 test_GDateTime_new_from_iso8601 (void)
501 {
502   GDateTime *dt;
503   GTimeZone *tz;
504
505   /* Need non-empty string */
506   dt = g_date_time_new_from_iso8601 ("", NULL);
507   g_assert_null (dt);
508
509   /* Needs to be correctly formatted */
510   dt = g_date_time_new_from_iso8601 ("not a date", NULL);
511   g_assert_null (dt);
512
513   dt = g_date_time_new_from_iso8601 (" +55", NULL);
514   g_assert_null (dt);
515
516   /* Check common case */
517   dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42Z", NULL);
518   ASSERT_DATE (dt, 2016, 8, 24);
519   ASSERT_TIME (dt, 22, 10, 42, 0);
520   g_date_time_unref (dt);
521
522   /* Timezone is required in text or passed as arg */
523   tz = g_time_zone_new_utc ();
524   dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42", tz);
525   ASSERT_DATE (dt, 2016, 8, 24);
526   g_date_time_unref (dt);
527   g_time_zone_unref (tz);
528   dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42", NULL);
529   g_assert_null (dt);
530
531   /* Can't have whitespace */
532   dt = g_date_time_new_from_iso8601 ("2016 08 24T22:10:42Z", NULL);
533   g_assert_null (dt);
534   dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42Z ", NULL);
535   g_assert_null (dt);
536   dt = g_date_time_new_from_iso8601 (" 2016-08-24T22:10:42Z", NULL);
537   g_assert_null (dt);
538
539   /* Check lowercase time separator or space allowed */
540   dt = g_date_time_new_from_iso8601 ("2016-08-24t22:10:42Z", NULL);
541   ASSERT_DATE (dt, 2016, 8, 24);
542   ASSERT_TIME (dt, 22, 10, 42, 0);
543   g_date_time_unref (dt);
544   dt = g_date_time_new_from_iso8601 ("2016-08-24 22:10:42Z", NULL);
545   ASSERT_DATE (dt, 2016, 8, 24);
546   ASSERT_TIME (dt, 22, 10, 42, 0);
547   g_date_time_unref (dt);
548
549   /* Check dates without separators allowed */
550   dt = g_date_time_new_from_iso8601 ("20160824T22:10:42Z", NULL);
551   ASSERT_DATE (dt, 2016, 8, 24);
552   ASSERT_TIME (dt, 22, 10, 42, 0);
553   g_date_time_unref (dt);
554
555   /* Months are two digits */
556   dt = g_date_time_new_from_iso8601 ("2016-1-01T22:10:42Z", NULL);
557   g_assert_null (dt);
558
559   /* Days are two digits */
560   dt = g_date_time_new_from_iso8601 ("2016-01-1T22:10:42Z", NULL);
561   g_assert_null (dt);
562
563   /* Need consistent usage of separators */
564   dt = g_date_time_new_from_iso8601 ("2016-0824T22:10:42Z", NULL);
565   g_assert_null (dt);
566   dt = g_date_time_new_from_iso8601 ("201608-24T22:10:42Z", NULL);
567   g_assert_null (dt);
568
569   /* Check month within valid range */
570   dt = g_date_time_new_from_iso8601 ("2016-00-13T22:10:42Z", NULL);
571   g_assert_null (dt);
572   dt = g_date_time_new_from_iso8601 ("2016-13-13T22:10:42Z", NULL);
573   g_assert_null (dt);
574
575   /* Check day within valid range */
576   dt = g_date_time_new_from_iso8601 ("2016-01-00T22:10:42Z", NULL);
577   g_assert_null (dt);
578   dt = g_date_time_new_from_iso8601 ("2016-01-31T22:10:42Z", NULL);
579   ASSERT_DATE (dt, 2016, 1, 31);
580   g_date_time_unref (dt);
581   dt = g_date_time_new_from_iso8601 ("2016-01-32T22:10:42Z", NULL);
582   g_assert_null (dt);
583   dt = g_date_time_new_from_iso8601 ("2016-02-29T22:10:42Z", NULL);
584   ASSERT_DATE (dt, 2016, 2, 29);
585   g_date_time_unref (dt);
586   dt = g_date_time_new_from_iso8601 ("2016-02-30T22:10:42Z", NULL);
587   g_assert_null (dt);
588   dt = g_date_time_new_from_iso8601 ("2017-02-28T22:10:42Z", NULL);
589   ASSERT_DATE (dt, 2017, 2, 28);
590   g_date_time_unref (dt);
591   dt = g_date_time_new_from_iso8601 ("2017-02-29T22:10:42Z", NULL);
592   g_assert_null (dt);
593   dt = g_date_time_new_from_iso8601 ("2016-03-31T22:10:42Z", NULL);
594   ASSERT_DATE (dt, 2016, 3, 31);
595   g_date_time_unref (dt);
596   dt = g_date_time_new_from_iso8601 ("2016-03-32T22:10:42Z", NULL);
597   g_assert_null (dt);
598   dt = g_date_time_new_from_iso8601 ("2016-04-30T22:10:42Z", NULL);
599   ASSERT_DATE (dt, 2016, 4, 30);
600   g_date_time_unref (dt);
601   dt = g_date_time_new_from_iso8601 ("2016-04-31T22:10:42Z", NULL);
602   g_assert_null (dt);
603   dt = g_date_time_new_from_iso8601 ("2016-05-31T22:10:42Z", NULL);
604   ASSERT_DATE (dt, 2016, 5, 31);
605   g_date_time_unref (dt);
606   dt = g_date_time_new_from_iso8601 ("2016-05-32T22:10:42Z", NULL);
607   g_assert_null (dt);
608   dt = g_date_time_new_from_iso8601 ("2016-06-30T22:10:42Z", NULL);
609   ASSERT_DATE (dt, 2016, 6, 30);
610   g_date_time_unref (dt);
611   dt = g_date_time_new_from_iso8601 ("2016-06-31T22:10:42Z", NULL);
612   g_assert_null (dt);
613   dt = g_date_time_new_from_iso8601 ("2016-07-31T22:10:42Z", NULL);
614   ASSERT_DATE (dt, 2016, 7, 31);
615   g_date_time_unref (dt);
616   dt = g_date_time_new_from_iso8601 ("2016-07-32T22:10:42Z", NULL);
617   g_assert_null (dt);
618   dt = g_date_time_new_from_iso8601 ("2016-08-31T22:10:42Z", NULL);
619   ASSERT_DATE (dt, 2016, 8, 31);
620   g_date_time_unref (dt);
621   dt = g_date_time_new_from_iso8601 ("2016-08-32T22:10:42Z", NULL);
622   g_assert_null (dt);
623   dt = g_date_time_new_from_iso8601 ("2016-09-30T22:10:42Z", NULL);
624   ASSERT_DATE (dt, 2016, 9, 30);
625   g_date_time_unref (dt);
626   dt = g_date_time_new_from_iso8601 ("2016-09-31T22:10:42Z", NULL);
627   g_assert_null (dt);
628   dt = g_date_time_new_from_iso8601 ("2016-10-31T22:10:42Z", NULL);
629   ASSERT_DATE (dt, 2016, 10, 31);
630   g_date_time_unref (dt);
631   dt = g_date_time_new_from_iso8601 ("2016-10-32T22:10:42Z", NULL);
632   g_assert_null (dt);
633   dt = g_date_time_new_from_iso8601 ("2016-11-30T22:10:42Z", NULL);
634   ASSERT_DATE (dt, 2016, 11, 30);
635   g_date_time_unref (dt);
636   dt = g_date_time_new_from_iso8601 ("2016-11-31T22:10:42Z", NULL);
637   g_assert_null (dt);
638   dt = g_date_time_new_from_iso8601 ("2016-12-31T22:10:42Z", NULL);
639   ASSERT_DATE (dt, 2016, 12, 31);
640   g_date_time_unref (dt);
641   dt = g_date_time_new_from_iso8601 ("2016-12-32T22:10:42Z", NULL);
642   g_assert_null (dt);
643
644   /* Check ordinal days work */
645   dt = g_date_time_new_from_iso8601 ("2016-237T22:10:42Z", NULL);
646   ASSERT_DATE (dt, 2016, 8, 24);
647   ASSERT_TIME (dt, 22, 10, 42, 0);
648   g_date_time_unref (dt);
649   dt = g_date_time_new_from_iso8601 ("2016237T22:10:42Z", NULL);
650   ASSERT_DATE (dt, 2016, 8, 24);
651   ASSERT_TIME (dt, 22, 10, 42, 0);
652   g_date_time_unref (dt);
653
654   /* Check ordinal leap days */
655   dt = g_date_time_new_from_iso8601 ("2016-366T22:10:42Z", NULL);
656   ASSERT_DATE (dt, 2016, 12, 31);
657   ASSERT_TIME (dt, 22, 10, 42, 0);
658   g_date_time_unref (dt);
659   dt = g_date_time_new_from_iso8601 ("2017-365T22:10:42Z", NULL);
660   ASSERT_DATE (dt, 2017, 12, 31);
661   ASSERT_TIME (dt, 22, 10, 42, 0);
662   g_date_time_unref (dt);
663   dt = g_date_time_new_from_iso8601 ("2017-366T22:10:42Z", NULL);
664   g_assert_null (dt);
665
666   /* Days start at 1 */
667   dt = g_date_time_new_from_iso8601 ("2016-000T22:10:42Z", NULL);
668   g_assert_null (dt);
669
670   /* Limited to number of days in the year (2016 is a leap year) */
671   dt = g_date_time_new_from_iso8601 ("2016-367T22:10:42Z", NULL);
672   g_assert_null (dt);
673
674   /* Days are two digits */
675   dt = g_date_time_new_from_iso8601 ("2016-1T22:10:42Z", NULL);
676   g_assert_null (dt);
677   dt = g_date_time_new_from_iso8601 ("2016-12T22:10:42Z", NULL);
678   g_assert_null (dt);
679
680   /* Check week days work */
681   dt = g_date_time_new_from_iso8601 ("2016-W34-3T22:10:42Z", NULL);
682   ASSERT_DATE (dt, 2016, 8, 24);
683   ASSERT_TIME (dt, 22, 10, 42, 0);
684   g_date_time_unref (dt);
685   dt = g_date_time_new_from_iso8601 ("2016W343T22:10:42Z", NULL);
686   ASSERT_DATE (dt, 2016, 8, 24);
687   ASSERT_TIME (dt, 22, 10, 42, 0);
688   g_date_time_unref (dt);
689
690   /* We don't support weeks without weekdays (valid ISO 8601) */
691   dt = g_date_time_new_from_iso8601 ("2016-W34T22:10:42Z", NULL);
692   g_assert_null (dt);
693   dt = g_date_time_new_from_iso8601 ("2016W34T22:10:42Z", NULL);
694   g_assert_null (dt);
695
696   /* Weeks are two digits */
697   dt = g_date_time_new_from_iso8601 ("2016-W3-1T22:10:42Z", NULL);
698   g_assert_null (dt);
699
700   /* Weeks start at 1 */
701   dt = g_date_time_new_from_iso8601 ("2016-W00-1T22:10:42Z", NULL);
702   g_assert_null (dt);
703
704   /* Week one might be in the previous year */
705   dt = g_date_time_new_from_iso8601 ("2015-W01-1T22:10:42Z", NULL);
706   ASSERT_DATE (dt, 2014, 12, 29);
707   g_date_time_unref (dt);
708
709   /* Last week might be in next year */
710   dt = g_date_time_new_from_iso8601 ("2015-W53-7T22:10:42Z", NULL);
711   ASSERT_DATE (dt, 2016, 1, 3);
712   g_date_time_unref (dt);
713
714   /* Week 53 doesn't always exist */
715   dt = g_date_time_new_from_iso8601 ("2016-W53-1T22:10:42Z", NULL);
716   g_assert_null (dt);
717
718   /* Limited to number of days in the week */
719   dt = g_date_time_new_from_iso8601 ("2016-W34-0T22:10:42Z", NULL);
720   g_assert_null (dt);
721   dt = g_date_time_new_from_iso8601 ("2016-W34-8T22:10:42Z", NULL);
722   g_assert_null (dt);
723
724   /* Days are one digit */
725   dt = g_date_time_new_from_iso8601 ("2016-W34-99T22:10:42Z", NULL);
726   g_assert_null (dt);
727
728   /* Check week day changes depending on year */
729   dt = g_date_time_new_from_iso8601 ("2017-W34-1T22:10:42Z", NULL);
730   ASSERT_DATE (dt, 2017, 8, 21);
731   g_date_time_unref (dt);
732
733   /* Check week day changes depending on leap years */
734   dt = g_date_time_new_from_iso8601 ("1900-W01-1T22:10:42Z", NULL);
735   ASSERT_DATE (dt, 1900, 1, 1);
736   g_date_time_unref (dt);
737
738   /* YYYY-MM not allowed (NOT valid ISO 8601) */
739   dt = g_date_time_new_from_iso8601 ("2016-08T22:10:42Z", NULL);
740   g_assert_null (dt);
741
742   /* We don't support omitted year (valid ISO 8601) */
743   dt = g_date_time_new_from_iso8601 ("--08-24T22:10:42Z", NULL);
744   g_assert_null (dt);
745   dt = g_date_time_new_from_iso8601 ("--0824T22:10:42Z", NULL);
746   g_assert_null (dt);
747
748   /* Seconds must be two digits. */
749   dt = g_date_time_new_from_iso8601 ("2016-08-10T22:10:4Z", NULL);
750   g_assert_null (dt);
751
752   /* Seconds must all be digits. */
753   dt = g_date_time_new_from_iso8601 ("2016-08-10T22:10:4aZ", NULL);
754   g_assert_null (dt);
755
756   /* Check subseconds work */
757   dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42.123456Z", NULL);
758   ASSERT_DATE (dt, 2016, 8, 24);
759   ASSERT_TIME (dt, 22, 10, 42, 123456);
760   g_date_time_unref (dt);
761   dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42,123456Z", NULL);
762   ASSERT_DATE (dt, 2016, 8, 24);
763   ASSERT_TIME (dt, 22, 10, 42, 123456);
764   g_date_time_unref (dt);
765   dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42.Z", NULL);
766   g_assert_null (dt);
767   dt = g_date_time_new_from_iso8601 ("2016-08-24T221042.123456Z", NULL);
768   ASSERT_DATE (dt, 2016, 8, 24);
769   ASSERT_TIME (dt, 22, 10, 42, 123456);
770   g_date_time_unref (dt);
771
772   /* Subseconds must all be digits. */
773   dt = g_date_time_new_from_iso8601 ("2016-08-10T22:10:42.5aZ", NULL);
774   g_assert_null (dt);
775
776   /* Subseconds can be an arbitrary length, but must not overflow.
777    * The ASSERT_TIME() comparisons are constrained by only comparing up to
778    * microsecond granularity. */
779   dt = g_date_time_new_from_iso8601 ("2016-08-10T22:10:09.222222222222222222Z", NULL);
780   ASSERT_DATE (dt, 2016, 8, 10);
781   ASSERT_TIME (dt, 22, 10, 9, 222222);
782   g_date_time_unref (dt);
783   dt = g_date_time_new_from_iso8601 ("2016-08-10T22:10:09.2222222222222222222Z", NULL);
784   g_assert_null (dt);
785
786   /* Small numerator, large divisor when parsing the subseconds. */
787   dt = g_date_time_new_from_iso8601 ("2016-08-10T22:10:00.0000000000000000001Z", NULL);
788   ASSERT_DATE (dt, 2016, 8, 10);
789   ASSERT_TIME (dt, 22, 10, 0, 0);
790   g_date_time_unref (dt);
791   dt = g_date_time_new_from_iso8601 ("2016-08-10T22:10:00.00000000000000000001Z", NULL);
792   g_assert_null (dt);
793
794   /* We don't support times without minutes / seconds (valid ISO 8601) */
795   dt = g_date_time_new_from_iso8601 ("2016-08-24T22Z", NULL);
796   g_assert_null (dt);
797   dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10Z", NULL);
798   g_assert_null (dt);
799   dt = g_date_time_new_from_iso8601 ("2016-08-24T2210Z", NULL);
800   g_assert_null (dt);
801
802   /* UTC time uses 'Z' */
803   dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42Z", NULL);
804   ASSERT_DATE (dt, 2016, 8, 24);
805   ASSERT_TIME (dt, 22, 10, 42, 0);
806   g_assert_cmpint (g_date_time_get_utc_offset (dt), ==, 0);
807   g_date_time_unref (dt);
808
809   /* Check timezone works */
810   dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42+12:00", NULL);
811   ASSERT_DATE (dt, 2016, 8, 24);
812   ASSERT_TIME (dt, 22, 10, 42, 0);
813   g_assert_cmpint (g_date_time_get_utc_offset (dt), ==, 12 * G_TIME_SPAN_HOUR);
814   g_date_time_unref (dt);
815   dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42+12", NULL);
816   ASSERT_DATE (dt, 2016, 8, 24);
817   ASSERT_TIME (dt, 22, 10, 42, 0);
818   g_assert_cmpint (g_date_time_get_utc_offset (dt), ==, 12 * G_TIME_SPAN_HOUR);
819   g_date_time_unref (dt);
820   dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42-02", NULL);
821   ASSERT_DATE (dt, 2016, 8, 24);
822   ASSERT_TIME (dt, 22, 10, 42, 0);
823   g_assert_cmpint (g_date_time_get_utc_offset (dt), ==, -2 * G_TIME_SPAN_HOUR);
824   g_date_time_unref (dt);
825
826   /* Timezone seconds not allowed */
827   dt = g_date_time_new_from_iso8601 ("2016-08-24T22-12:00:00", NULL);
828   g_assert_null (dt);
829   dt = g_date_time_new_from_iso8601 ("2016-08-24T22-12:00:00.000", NULL);
830   g_assert_null (dt);
831
832   /* Timezone hours two digits */
833   dt = g_date_time_new_from_iso8601 ("2016-08-24T22-2Z", NULL);
834   g_assert_null (dt);
835
836   /* Ordinal date (YYYYDDD), space separator, and then time as HHMMSS,SSS
837    * The interesting bit is that the seconds field is so long as to parse as
838    * NaN */
839   dt = g_date_time_new_from_iso8601 ("0005306 000001,666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666600080000-00", NULL);
840   g_assert_null (dt);
841 }
842
843 typedef struct {
844   gboolean success;
845   const gchar *in;
846
847   /* Expected result: */
848   guint year;
849   guint month;
850   guint day;
851   guint hour;
852   guint minute;
853   guint second;
854   guint microsecond;
855   GTimeSpan utc_offset;
856 } Iso8601ParseTest;
857
858 static void
859 test_GDateTime_new_from_iso8601_2 (void)
860 {
861   const Iso8601ParseTest tests[] = {
862     { TRUE, "1990-11-01T10:21:17Z", 1990, 11, 1, 10, 21, 17, 0, 0 },
863     { TRUE, "19901101T102117Z", 1990, 11, 1, 10, 21, 17, 0, 0 },
864     { TRUE, "1970-01-01T00:00:17.12Z", 1970, 1, 1, 0, 0, 17, 120000, 0 },
865     { TRUE, "1970-01-01T00:00:17.1234Z", 1970, 1, 1, 0, 0, 17, 123400, 0 },
866     { TRUE, "1970-01-01T00:00:17.123456Z", 1970, 1, 1, 0, 0, 17, 123456, 0 },
867     { TRUE, "1980-02-22T12:36:00+02:00", 1980, 2, 22, 12, 36, 0, 0, 2 * G_TIME_SPAN_HOUR },
868     { TRUE, "1990-12-31T15:59:60-08:00", 1990, 12, 31, 15, 59, 59, 0, -8 * G_TIME_SPAN_HOUR },
869     { FALSE, "   ", 0, 0, 0, 0, 0, 0, 0, 0 },
870     { FALSE, "x", 0, 0, 0, 0, 0, 0, 0, 0 },
871     { FALSE, "123x", 0, 0, 0, 0, 0, 0, 0, 0 },
872     { FALSE, "2001-10+x", 0, 0, 0, 0, 0, 0, 0, 0 },
873     { FALSE, "1980-02-22T", 0, 0, 0, 0, 0, 0, 0, 0 },
874     { FALSE, "2001-10-08Tx", 0, 0, 0, 0, 0, 0, 0, 0 },
875     { FALSE, "2001-10-08T10:11x", 0, 0, 0, 0, 0, 0, 0, 0 },
876     { FALSE, "Wed Dec 19 17:20:20 GMT 2007", 0, 0, 0, 0, 0, 0, 0, 0 },
877     { FALSE, "1980-02-22T10:36:00Zulu", 0, 0, 0, 0, 0, 0, 0, 0 },
878     { FALSE, "2T0+819855292164632335", 0, 0, 0, 0, 0, 0, 0, 0 },
879     { TRUE, "2018-08-03T14:08:05.446178377+01:00", 2018, 8, 3, 14, 8, 5, 446178, 1 * G_TIME_SPAN_HOUR },
880     { FALSE, "2147483648-08-03T14:08:05.446178377+01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
881     { FALSE, "2018-13-03T14:08:05.446178377+01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
882     { FALSE, "2018-00-03T14:08:05.446178377+01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
883     { FALSE, "2018-08-00T14:08:05.446178377+01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
884     { FALSE, "2018-08-32T14:08:05.446178377+01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
885     { FALSE, "2018-08-03T24:08:05.446178377+01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
886     { FALSE, "2018-08-03T14:60:05.446178377+01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
887     { FALSE, "2018-08-03T14:08:63.446178377+01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
888     { FALSE, "2018-08-03T14:08:05.446178377+100:00", 0, 0, 0, 0, 0, 0, 0, 0 },
889     { TRUE, "20180803T140805.446178377+0100", 2018, 8, 3, 14, 8, 5, 446178, 1 * G_TIME_SPAN_HOUR },
890     { FALSE, "21474836480803T140805.446178377+0100", 0, 0, 0, 0, 0, 0, 0, 0 },
891     { FALSE, "20181303T140805.446178377+0100", 0, 0, 0, 0, 0, 0, 0, 0 },
892     { FALSE, "20180003T140805.446178377+0100", 0, 0, 0, 0, 0, 0, 0, 0 },
893     { FALSE, "20180800T140805.446178377+0100", 0, 0, 0, 0, 0, 0, 0, 0 },
894     { FALSE, "20180832T140805.446178377+0100", 0, 0, 0, 0, 0, 0, 0, 0 },
895     { FALSE, "20180803T240805.446178377+0100", 0, 0, 0, 0, 0, 0, 0, 0 },
896     { FALSE, "20180803T146005.446178377+0100", 0, 0, 0, 0, 0, 0, 0, 0 },
897     { FALSE, "20180803T140863.446178377+0100", 0, 0, 0, 0, 0, 0, 0, 0 },
898     { FALSE, "20180803T140805.446178377+10000", 0, 0, 0, 0, 0, 0, 0, 0 },
899     { FALSE, "-0005-01-01T00:00:00Z", 0, 0, 0, 0, 0, 0, 0, 0 },
900     { FALSE, "2018-08-06", 0, 0, 0, 0, 0, 0, 0, 0 },
901     /* This is not accepted by g_time_val_from_iso8601(), but is accepted by g_date_time_new_from_iso8601():
902     { FALSE, "2018-08-06 13:51:00Z", 0, 0, 0, 0, 0, 0, 0, 0 },
903     * */
904     { TRUE, "20180803T140805,446178377+0100", 2018, 8, 3, 14, 8, 5, 446178, 1 * G_TIME_SPAN_HOUR },
905     { TRUE, "2018-08-03T14:08:05.446178377-01:00", 2018, 8, 3, 14, 8, 5, 446178, -1 * G_TIME_SPAN_HOUR },
906     { FALSE, "2018-08-03T14:08:05.446178377 01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
907     { TRUE, "1990-11-01T10:21:17", 1990, 11, 1, 10, 21, 17, 0, 0 },
908     /* These are accepted by g_time_val_from_iso8601(), but not by g_date_time_new_from_iso8601():
909     { TRUE, "19901101T102117+5", 1990, 11, 1, 10, 21, 17, 0, 5 * G_TIME_SPAN_HOUR },
910     { TRUE, "19901101T102117+3:15", 1990, 11, 1, 10, 21, 17, 0, 3 * G_TIME_SPAN_HOUR + 15 * G_TIME_SPAN_MINUTE },
911     { TRUE, "  1990-11-01T10:21:17Z  ", 1990, 11, 1, 10, 21, 17, 0, 0 },
912     { FALSE, "2018-08-03T14:08:05.446178377+01:60", 0, 0, 0, 0, 0, 0, 0, 0 },
913     { FALSE, "20180803T140805.446178377+0160", 0, 0, 0, 0, 0, 0, 0, 0 },
914     { TRUE, "+1980-02-22T12:36:00+02:00", 1980, 2, 22, 12, 36, 0, 0, 2 * G_TIME_SPAN_HOUR },
915     { TRUE, "1990-11-01T10:21:17     ", 1990, 11, 1, 10, 21, 17, 0, 0 },
916     */
917     { FALSE, "1719W462 407777-07", 0, 0, 0, 0, 0, 0, 0, 0 },
918     { FALSE, "4011090 260528Z", 0, 0, 0, 0, 0, 0, 0, 0 },
919     { FALSE, "0000W011 228214-22", 0, 0, 0, 0, 0, 0, 0, 0 },
920   };
921   GTimeZone *tz = NULL;
922   GDateTime *dt = NULL;
923   gsize i;
924
925   g_test_summary ("Further parser tests for g_date_time_new_from_iso8601(), "
926                   "checking success and failure using test vectors.");
927
928   tz = g_time_zone_new_utc ();
929
930   for (i = 0; i < G_N_ELEMENTS (tests); i++)
931     {
932       g_test_message ("Vector %" G_GSIZE_FORMAT ": %s", i, tests[i].in);
933
934       dt = g_date_time_new_from_iso8601 (tests[i].in, tz);
935       if (tests[i].success)
936         {
937           g_assert_nonnull (dt);
938           ASSERT_DATE (dt, tests[i].year, tests[i].month, tests[i].day);
939           ASSERT_TIME (dt, tests[i].hour, tests[i].minute, tests[i].second, tests[i].microsecond);
940           g_assert_cmpint (g_date_time_get_utc_offset (dt), ==, tests[i].utc_offset);
941         }
942       else
943         {
944           g_assert_null (dt);
945         }
946
947       g_clear_pointer (&dt, g_date_time_unref);
948     }
949
950   g_time_zone_unref (tz);
951 }
952
953 static void
954 test_GDateTime_to_unix (void)
955 {
956   GDateTime *dt;
957   time_t     t;
958
959   t = time (NULL);
960   g_assert_cmpint (t, !=, (time_t) -1);
961   dt = g_date_time_new_from_unix_local (t);
962   g_assert_cmpint (g_date_time_to_unix (dt), ==, t);
963   g_date_time_unref (dt);
964 }
965
966 static void
967 test_GDateTime_add_years (void)
968 {
969   GDateTime *dt, *dt2;
970
971   dt = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
972   dt2 = g_date_time_add_years (dt, 1);
973   g_assert_cmpint (2010, ==, g_date_time_get_year (dt2));
974   g_date_time_unref (dt);
975   g_date_time_unref (dt2);
976 }
977
978 static void
979 test_GDateTime_add_months (void)
980 {
981 #define TEST_ADD_MONTHS(y,m,d,a,ny,nm,nd) G_STMT_START { \
982   GDateTime *dt, *dt2; \
983   dt = g_date_time_new_utc (y, m, d, 0, 0, 0); \
984   dt2 = g_date_time_add_months (dt, a); \
985   ASSERT_DATE (dt2, ny, nm, nd); \
986   g_date_time_unref (dt); \
987   g_date_time_unref (dt2); \
988 } G_STMT_END
989
990   TEST_ADD_MONTHS (2009, 12, 31,    1, 2010, 1, 31);
991   TEST_ADD_MONTHS (2009, 12, 31,    1, 2010, 1, 31);
992   TEST_ADD_MONTHS (2009,  6, 15,    1, 2009, 7, 15);
993   TEST_ADD_MONTHS (1400,  3,  1,    1, 1400, 4,  1);
994   TEST_ADD_MONTHS (1400,  1, 31,    1, 1400, 2, 28);
995   TEST_ADD_MONTHS (1400,  1, 31, 7200, 2000, 1, 31);
996   TEST_ADD_MONTHS (2008,  2, 29,   12, 2009, 2, 28);
997   TEST_ADD_MONTHS (2000,  8, 16,   -5, 2000, 3, 16);
998   TEST_ADD_MONTHS (2000,  8, 16,  -12, 1999, 8, 16);
999   TEST_ADD_MONTHS (2011,  2,  1,  -13, 2010, 1,  1);
1000   TEST_ADD_MONTHS (1776,  7,  4, 1200, 1876, 7,  4);
1001 }
1002
1003 static void
1004 test_GDateTime_add_days (void)
1005 {
1006 #define TEST_ADD_DAYS(y,m,d,a,ny,nm,nd) G_STMT_START { \
1007   GDateTime *dt, *dt2; \
1008   dt = g_date_time_new_local (y, m, d, 0, 0, 0); \
1009   dt2 = g_date_time_add_days (dt, a); \
1010   g_assert_cmpint (ny, ==, g_date_time_get_year (dt2)); \
1011   g_assert_cmpint (nm, ==, g_date_time_get_month (dt2)); \
1012   g_assert_cmpint (nd, ==, g_date_time_get_day_of_month (dt2)); \
1013   g_date_time_unref (dt); \
1014   g_date_time_unref (dt2); \
1015 } G_STMT_END
1016
1017   TEST_ADD_DAYS (2009, 1, 31, 1, 2009, 2, 1);
1018   TEST_ADD_DAYS (2009, 2, 1, -1, 2009, 1, 31);
1019   TEST_ADD_DAYS (2008, 2, 28, 1, 2008, 2, 29);
1020   TEST_ADD_DAYS (2008, 12, 31, 1, 2009, 1, 1);
1021   TEST_ADD_DAYS (1, 1, 1, 1, 1, 1, 2);
1022   TEST_ADD_DAYS (1955, 5, 24, 10, 1955, 6, 3);
1023   TEST_ADD_DAYS (1955, 5, 24, -10, 1955, 5, 14);
1024 }
1025
1026 static void
1027 test_GDateTime_add_weeks (void)
1028 {
1029 #define TEST_ADD_WEEKS(y,m,d,a,ny,nm,nd) G_STMT_START { \
1030   GDateTime *dt, *dt2; \
1031   dt = g_date_time_new_local (y, m, d, 0, 0, 0); \
1032   dt2 = g_date_time_add_weeks (dt, a); \
1033   g_assert_cmpint (ny, ==, g_date_time_get_year (dt2)); \
1034   g_assert_cmpint (nm, ==, g_date_time_get_month (dt2)); \
1035   g_assert_cmpint (nd, ==, g_date_time_get_day_of_month (dt2)); \
1036   g_date_time_unref (dt); \
1037   g_date_time_unref (dt2); \
1038 } G_STMT_END
1039
1040   TEST_ADD_WEEKS (2009, 1, 1, 1, 2009, 1, 8);
1041   TEST_ADD_WEEKS (2009, 8, 30, 1, 2009, 9, 6);
1042   TEST_ADD_WEEKS (2009, 12, 31, 1, 2010, 1, 7);
1043   TEST_ADD_WEEKS (2009, 1, 1, -1, 2008, 12, 25);
1044 }
1045
1046 static void
1047 test_GDateTime_add_hours (void)
1048 {
1049 #define TEST_ADD_HOURS(y,m,d,h,mi,s,a,ny,nm,nd,nh,nmi,ns) G_STMT_START { \
1050   GDateTime *dt, *dt2; \
1051   dt = g_date_time_new_utc (y, m, d, h, mi, s); \
1052   dt2 = g_date_time_add_hours (dt, a); \
1053   g_assert_cmpint (ny, ==, g_date_time_get_year (dt2)); \
1054   g_assert_cmpint (nm, ==, g_date_time_get_month (dt2)); \
1055   g_assert_cmpint (nd, ==, g_date_time_get_day_of_month (dt2)); \
1056   g_assert_cmpint (nh, ==, g_date_time_get_hour (dt2)); \
1057   g_assert_cmpint (nmi, ==, g_date_time_get_minute (dt2)); \
1058   g_assert_cmpint (ns, ==, g_date_time_get_second (dt2)); \
1059   g_date_time_unref (dt); \
1060   g_date_time_unref (dt2); \
1061 } G_STMT_END
1062
1063   TEST_ADD_HOURS (2009,  1,  1,  0, 0, 0, 1, 2009, 1, 1, 1, 0, 0);
1064   TEST_ADD_HOURS (2008, 12, 31, 23, 0, 0, 1, 2009, 1, 1, 0, 0, 0);
1065 }
1066
1067 static void
1068 test_GDateTime_add_full (void)
1069 {
1070 #define TEST_ADD_FULL(y,m,d,h,mi,s,ay,am,ad,ah,ami,as,ny,nm,nd,nh,nmi,ns) G_STMT_START { \
1071   GDateTime *dt, *dt2; \
1072   dt = g_date_time_new_utc (y, m, d, h, mi, s); \
1073   dt2 = g_date_time_add_full (dt, ay, am, ad, ah, ami, as); \
1074   g_assert_cmpint (ny, ==, g_date_time_get_year (dt2)); \
1075   g_assert_cmpint (nm, ==, g_date_time_get_month (dt2)); \
1076   g_assert_cmpint (nd, ==, g_date_time_get_day_of_month (dt2)); \
1077   g_assert_cmpint (nh, ==, g_date_time_get_hour (dt2)); \
1078   g_assert_cmpint (nmi, ==, g_date_time_get_minute (dt2)); \
1079   g_assert_cmpint (ns, ==, g_date_time_get_second (dt2)); \
1080   g_date_time_unref (dt); \
1081   g_date_time_unref (dt2); \
1082 } G_STMT_END
1083
1084   TEST_ADD_FULL (2009, 10, 21,  0,  0, 0,
1085                     1,  1,  1,  1,  1, 1,
1086                  2010, 11, 22,  1,  1, 1);
1087   TEST_ADD_FULL (2000,  1,  1,  1,  1, 1,
1088                     0,  1,  0,  0,  0, 0,
1089                  2000,  2,  1,  1,  1, 1);
1090   TEST_ADD_FULL (2000,  1,  1,  0,  0, 0,
1091                    -1,  1,  0,  0,  0, 0,
1092                  1999,  2,  1,  0,  0, 0);
1093   TEST_ADD_FULL (2010, 10, 31,  0,  0, 0,
1094                     0,  4,  0,  0,  0, 0,
1095                  2011,  2, 28,  0,  0, 0);
1096   TEST_ADD_FULL (2010,  8, 25, 22, 45, 0,
1097                     0,  1,  6,  1, 25, 0,
1098                  2010, 10,  2,  0, 10, 0);
1099 }
1100
1101 static void
1102 test_GDateTime_add_minutes (void)
1103 {
1104 #define TEST_ADD_MINUTES(i,o) G_STMT_START { \
1105   GDateTime *dt, *dt2; \
1106   dt = g_date_time_new_local (2000, 1, 1, 0, 0, 0); \
1107   dt2 = g_date_time_add_minutes (dt, i); \
1108   g_assert_cmpint (o, ==, g_date_time_get_minute (dt2)); \
1109   g_date_time_unref (dt); \
1110   g_date_time_unref (dt2); \
1111 } G_STMT_END
1112
1113   TEST_ADD_MINUTES (60, 0);
1114   TEST_ADD_MINUTES (100, 40);
1115   TEST_ADD_MINUTES (5, 5);
1116   TEST_ADD_MINUTES (1441, 1);
1117   TEST_ADD_MINUTES (-1441, 59);
1118 }
1119
1120 static void
1121 test_GDateTime_add_seconds (void)
1122 {
1123 #define TEST_ADD_SECONDS(i,o) G_STMT_START { \
1124   GDateTime *dt, *dt2; \
1125   dt = g_date_time_new_local (2000, 1, 1, 0, 0, 0); \
1126   dt2 = g_date_time_add_seconds (dt, i); \
1127   g_assert_cmpint (o, ==, g_date_time_get_second (dt2)); \
1128   g_date_time_unref (dt); \
1129   g_date_time_unref (dt2); \
1130 } G_STMT_END
1131
1132   TEST_ADD_SECONDS (1, 1);
1133   TEST_ADD_SECONDS (60, 0);
1134   TEST_ADD_SECONDS (61, 1);
1135   TEST_ADD_SECONDS (120, 0);
1136   TEST_ADD_SECONDS (-61, 59);
1137   TEST_ADD_SECONDS (86401, 1);
1138   TEST_ADD_SECONDS (-86401, 59);
1139   TEST_ADD_SECONDS (-31, 29);
1140   TEST_ADD_SECONDS (13, 13);
1141 }
1142
1143 static void
1144 test_GDateTime_diff (void)
1145 {
1146 #define TEST_DIFF(y,m,d,y2,m2,d2,u) G_STMT_START { \
1147   GDateTime *dt1, *dt2; \
1148   GTimeSpan  ts = 0; \
1149   dt1 = g_date_time_new_utc (y, m, d, 0, 0, 0); \
1150   dt2 = g_date_time_new_utc (y2, m2, d2, 0, 0, 0); \
1151   ts = g_date_time_difference (dt2, dt1); \
1152   g_assert_cmpint (ts, ==, u); \
1153   g_date_time_unref (dt1); \
1154   g_date_time_unref (dt2); \
1155 } G_STMT_END
1156
1157   TEST_DIFF (2009, 1, 1, 2009, 2, 1, G_TIME_SPAN_DAY * 31);
1158   TEST_DIFF (2009, 1, 1, 2010, 1, 1, G_TIME_SPAN_DAY * 365);
1159   TEST_DIFF (2008, 2, 28, 2008, 2, 29, G_TIME_SPAN_DAY);
1160   TEST_DIFF (2008, 2, 29, 2008, 2, 28, -G_TIME_SPAN_DAY);
1161
1162   /* TODO: Add usec tests */
1163 }
1164
1165 static void
1166 test_GDateTime_get_minute (void)
1167 {
1168   GDateTime *dt;
1169
1170   dt = g_date_time_new_utc (2009, 12, 1, 1, 31, 0);
1171   g_assert_cmpint (31, ==, g_date_time_get_minute (dt));
1172   g_date_time_unref (dt);
1173 }
1174
1175 static void
1176 test_GDateTime_get_month (void)
1177 {
1178   GDateTime *dt;
1179
1180   dt = g_date_time_new_utc (2009, 12, 1, 1, 31, 0);
1181   g_assert_cmpint (12, ==, g_date_time_get_month (dt));
1182   g_date_time_unref (dt);
1183 }
1184
1185 static void
1186 test_GDateTime_get_second (void)
1187 {
1188   GDateTime *dt;
1189
1190   dt = g_date_time_new_utc (2009, 12, 1, 1, 31, 44);
1191   g_assert_cmpint (44, ==, g_date_time_get_second (dt));
1192   g_date_time_unref (dt);
1193 }
1194
1195 static void
1196 test_GDateTime_new_full (void)
1197 {
1198   GTimeZone *tz, *dt_tz;
1199   GDateTime *dt;
1200
1201 #ifdef G_OS_WIN32
1202   LCID currLcid = GetThreadLocale ();
1203   LANGID currLangId = LANGIDFROMLCID (currLcid);
1204   LANGID en = MAKELANGID (LANG_ENGLISH, SUBLANG_ENGLISH_US);
1205   SetThreadUILanguage (en);
1206 #endif
1207
1208   dt = g_date_time_new_utc (2009, 12, 11, 12, 11, 10);
1209   g_assert_cmpint (2009, ==, g_date_time_get_year (dt));
1210   g_assert_cmpint (12, ==, g_date_time_get_month (dt));
1211   g_assert_cmpint (11, ==, g_date_time_get_day_of_month (dt));
1212   g_assert_cmpint (12, ==, g_date_time_get_hour (dt));
1213   g_assert_cmpint (11, ==, g_date_time_get_minute (dt));
1214   g_assert_cmpint (10, ==, g_date_time_get_second (dt));
1215   g_date_time_unref (dt);
1216
1217 #ifdef G_OS_UNIX
1218   tz = g_time_zone_new ("America/Tijuana");
1219 #elif defined G_OS_WIN32
1220   tz = g_time_zone_new ("Pacific Standard Time");
1221 #endif
1222   dt = g_date_time_new (tz, 2010, 11, 24, 8, 4, 0);
1223
1224   dt_tz = g_date_time_get_timezone (dt);
1225   g_assert_cmpstr (g_time_zone_get_identifier (dt_tz), ==,
1226                    g_time_zone_get_identifier (tz));
1227
1228   g_assert_cmpint (2010, ==, g_date_time_get_year (dt));
1229   g_assert_cmpint (11, ==, g_date_time_get_month (dt));
1230   g_assert_cmpint (24, ==, g_date_time_get_day_of_month (dt));
1231   g_assert_cmpint (8, ==, g_date_time_get_hour (dt));
1232   g_assert_cmpint (4, ==, g_date_time_get_minute (dt));
1233   g_assert_cmpint (0, ==, g_date_time_get_second (dt));
1234 #ifdef G_OS_UNIX
1235   g_assert_cmpstr ("PST", ==, g_date_time_get_timezone_abbreviation (dt));
1236   g_assert_cmpstr ("America/Tijuana", ==, g_time_zone_get_identifier (dt_tz));
1237 #elif defined G_OS_WIN32
1238   g_assert_cmpstr ("Pacific Standard Time", ==,
1239                     g_date_time_get_timezone_abbreviation (dt));
1240   g_assert_cmpstr ("Pacific Standard Time", ==,
1241                    g_time_zone_get_identifier (dt_tz));
1242   SetThreadUILanguage (currLangId);
1243 #endif
1244   g_assert (!g_date_time_is_daylight_savings (dt));
1245   g_date_time_unref (dt);
1246   g_time_zone_unref (tz);
1247
1248   /* Check month limits */
1249   dt = g_date_time_new_utc (2016, 1, 31, 22, 10, 42);
1250   ASSERT_DATE (dt, 2016, 1, 31);
1251   g_date_time_unref (dt);
1252   dt = g_date_time_new_utc (2016, 1, 32, 22, 10, 42);
1253   g_assert_null (dt);
1254   dt = g_date_time_new_utc (2016, 2, 29, 22, 10, 42);
1255   ASSERT_DATE (dt, 2016, 2, 29);
1256   g_date_time_unref (dt);
1257   dt = g_date_time_new_utc (2016, 2, 30, 22, 10, 42);
1258   g_assert_null (dt);
1259   dt = g_date_time_new_utc (2017, 2, 28, 22, 10, 42);
1260   ASSERT_DATE (dt, 2017, 2, 28);
1261   g_date_time_unref (dt);
1262   dt = g_date_time_new_utc (2017, 2, 29, 22, 10, 42);
1263   g_assert_null (dt);
1264   dt = g_date_time_new_utc (2016, 3, 31, 22, 10, 42);
1265   ASSERT_DATE (dt, 2016, 3, 31);
1266   g_date_time_unref (dt);
1267   dt = g_date_time_new_utc (2016, 3, 32, 22, 10, 42);
1268   g_assert_null (dt);
1269   dt = g_date_time_new_utc (2016, 4, 30, 22, 10, 42);
1270   ASSERT_DATE (dt, 2016, 4, 30);
1271   g_date_time_unref (dt);
1272   dt = g_date_time_new_utc (2016, 4, 31, 22, 10, 42);
1273   g_assert_null (dt);
1274   dt = g_date_time_new_utc (2016, 5, 31, 22, 10, 42);
1275   ASSERT_DATE (dt, 2016, 5, 31);
1276   g_date_time_unref (dt);
1277   dt = g_date_time_new_utc (2016, 5, 32, 22, 10, 42);
1278   g_assert_null (dt);
1279   dt = g_date_time_new_utc (2016, 6, 30, 22, 10, 42);
1280   ASSERT_DATE (dt, 2016, 6, 30);
1281   g_date_time_unref (dt);
1282   dt = g_date_time_new_utc (2016, 6, 31, 22, 10, 42);
1283   g_assert_null (dt);
1284   dt = g_date_time_new_utc (2016, 7, 31, 22, 10, 42);
1285   ASSERT_DATE (dt, 2016, 7, 31);
1286   g_date_time_unref (dt);
1287   dt = g_date_time_new_utc (2016, 7, 32, 22, 10, 42);
1288   g_assert_null (dt);
1289   dt = g_date_time_new_utc (2016, 8, 31, 22, 10, 42);
1290   ASSERT_DATE (dt, 2016, 8, 31);
1291   g_date_time_unref (dt);
1292   dt = g_date_time_new_utc (2016, 8, 32, 22, 10, 42);
1293   g_assert_null (dt);
1294   dt = g_date_time_new_utc (2016, 9, 30, 22, 10, 42);
1295   ASSERT_DATE (dt, 2016, 9, 30);
1296   g_date_time_unref (dt);
1297   dt = g_date_time_new_utc (2016, 9, 31, 22, 10, 42);
1298   g_assert_null (dt);
1299   dt = g_date_time_new_utc (2016, 10, 31, 22, 10, 42);
1300   ASSERT_DATE (dt, 2016, 10, 31);
1301   g_date_time_unref (dt);
1302   dt = g_date_time_new_utc (2016, 10, 32, 22, 10, 42);
1303   g_assert_null (dt);
1304   dt = g_date_time_new_utc (2016, 11, 30, 22, 10, 42);
1305   ASSERT_DATE (dt, 2016, 11, 30);
1306   g_date_time_unref (dt);
1307   dt = g_date_time_new_utc (2016, 11, 31, 22, 10, 42);
1308   g_assert_null (dt);
1309   dt = g_date_time_new_utc (2016, 12, 31, 22, 10, 42);
1310   ASSERT_DATE (dt, 2016, 12, 31);
1311   g_date_time_unref (dt);
1312   dt = g_date_time_new_utc (2016, 12, 32, 22, 10, 42);
1313   g_assert_null (dt);
1314
1315   /* Seconds limits. */
1316   dt = g_date_time_new_utc (2020, 12, 9, 14, 49, NAN);
1317   g_assert_null (dt);
1318   dt = g_date_time_new_utc (2020, 12, 9, 14, 49, -0.1);
1319   g_assert_null (dt);
1320   dt = g_date_time_new_utc (2020, 12, 9, 14, 49, 60.0);
1321   g_assert_null (dt);
1322
1323   /* Year limits */
1324   dt = g_date_time_new_utc (10000, 1, 1, 0, 0, 0);
1325   dt = g_date_time_new_utc (0, 1, 1, 0, 0, 0);
1326 }
1327
1328 static void
1329 test_GDateTime_now_utc (void)
1330 {
1331   GDateTime *dt;
1332   struct tm  tm;
1333   time_t     t;
1334   time_t     after;
1335
1336   /* t <= dt.to_unix() <= after, but the inequalities might not be
1337    * equality if we're close to the boundary between seconds.
1338    * We loop until t == after (and hence dt.to_unix() should equal both)
1339    * to guard against that. */
1340   do
1341     {
1342       t = g_get_real_time () / G_TIME_SPAN_SECOND;
1343 #ifdef HAVE_GMTIME_R
1344       gmtime_r (&t, &tm);
1345 #else
1346       {
1347         struct tm *tmp = gmtime (&t);
1348         /* Assume gmtime() can't fail as we got t from time(NULL). (Note
1349          * that on Windows, gmtime() *is* MT-safe, it uses a thread-local
1350          * buffer.)
1351          */
1352         memcpy (&tm, tmp, sizeof (struct tm));
1353       }
1354 #endif
1355       dt = g_date_time_new_now_utc ();
1356
1357       after = g_get_real_time () / G_TIME_SPAN_SECOND;
1358     }
1359   while (t != after);
1360
1361   g_assert_cmpint (tm.tm_year + 1900, ==, g_date_time_get_year (dt));
1362   g_assert_cmpint (tm.tm_mon + 1, ==, g_date_time_get_month (dt));
1363   g_assert_cmpint (tm.tm_mday, ==, g_date_time_get_day_of_month (dt));
1364   g_assert_cmpint (tm.tm_hour, ==, g_date_time_get_hour (dt));
1365   g_assert_cmpint (tm.tm_min, ==, g_date_time_get_minute (dt));
1366   g_assert_cmpint (tm.tm_sec, ==, g_date_time_get_second (dt));
1367   g_date_time_unref (dt);
1368 }
1369
1370 static void
1371 test_GDateTime_new_from_unix_utc (void)
1372 {
1373   GDateTime *dt;
1374   gint64 t;
1375
1376   t = g_get_real_time ();
1377
1378 #if 0
1379   dt = g_date_time_new_from_unix_utc (t);
1380   g_assert (dt == NULL);
1381 #endif
1382
1383   t = t / 1e6;  /* oops, this was microseconds */
1384
1385   dt = g_date_time_new_from_unix_utc (t);
1386   g_assert (dt != NULL);
1387
1388   g_assert (dt == g_date_time_ref (dt));
1389   g_date_time_unref (dt);
1390   g_assert_cmpint (g_date_time_to_unix (dt), ==, t);
1391   g_date_time_unref (dt);
1392 }
1393
1394 static void
1395 test_GDateTime_get_utc_offset (void)
1396 {
1397 #if defined (HAVE_STRUCT_TM_TM_GMTOFF) || defined (HAVE_STRUCT_TM___TM_GMTOFF)
1398   GDateTime *dt;
1399   GTimeSpan ts;
1400   struct tm tm;
1401
1402   memset (&tm, 0, sizeof (tm));
1403   get_localtime_tm (g_get_real_time () / G_TIME_SPAN_SECOND, &tm);
1404
1405   dt = g_date_time_new_now_local ();
1406   ts = g_date_time_get_utc_offset (dt);
1407 #ifdef HAVE_STRUCT_TM_TM_GMTOFF
1408   g_assert_cmpint (ts, ==, (tm.tm_gmtoff * G_TIME_SPAN_SECOND));
1409 #endif
1410 #ifdef HAVE_STRUCT_TM___TM_GMTOFF
1411   g_assert_cmpint (ts, ==, (tm.__tm_gmtoff * G_TIME_SPAN_SECOND));
1412 #endif
1413   g_date_time_unref (dt);
1414 #endif
1415 }
1416
1417 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1418 static void
1419 test_GDateTime_to_timeval (void)
1420 {
1421   GTimeVal tv1, tv2;
1422   GDateTime *dt;
1423
1424   memset (&tv1, 0, sizeof (tv1));
1425   memset (&tv2, 0, sizeof (tv2));
1426
1427   g_get_current_time (&tv1);
1428   dt = g_date_time_new_from_timeval_local (&tv1);
1429   g_date_time_to_timeval (dt, &tv2);
1430   g_assert_cmpint (tv1.tv_sec, ==, tv2.tv_sec);
1431   g_assert_cmpint (tv1.tv_usec, ==, tv2.tv_usec);
1432   g_date_time_unref (dt);
1433 }
1434 G_GNUC_END_IGNORE_DEPRECATIONS
1435
1436 static void
1437 test_GDateTime_to_local (void)
1438 {
1439   GDateTime *utc = NULL, *now = NULL, *dt;
1440   time_t before, after;
1441
1442   /* before <= utc.to_unix() <= now.to_unix() <= after, but the inequalities
1443    * might not be equality if we're close to the boundary between seconds.
1444    * We loop until before == after (and hence the GDateTimes should match)
1445    * to guard against that. */
1446   do
1447     {
1448       before = g_get_real_time () / G_TIME_SPAN_SECOND;
1449       g_clear_pointer (&utc, g_date_time_unref);
1450       g_clear_pointer (&now, g_date_time_unref);
1451       utc = g_date_time_new_now_utc ();
1452       now = g_date_time_new_now_local ();
1453       after = g_get_real_time () / G_TIME_SPAN_SECOND;
1454     }
1455   while (before != after);
1456
1457   dt = g_date_time_to_local (utc);
1458
1459   g_assert_cmpint (g_date_time_get_year (now), ==, g_date_time_get_year (dt));
1460   g_assert_cmpint (g_date_time_get_month (now), ==, g_date_time_get_month (dt));
1461   g_assert_cmpint (g_date_time_get_day_of_month (now), ==, g_date_time_get_day_of_month (dt));
1462   g_assert_cmpint (g_date_time_get_hour (now), ==, g_date_time_get_hour (dt));
1463   g_assert_cmpint (g_date_time_get_minute (now), ==, g_date_time_get_minute (dt));
1464   g_assert_cmpint (g_date_time_get_second (now), ==, g_date_time_get_second (dt));
1465
1466   g_date_time_unref (now);
1467   g_date_time_unref (utc);
1468   g_date_time_unref (dt);
1469 }
1470
1471 static void
1472 test_GDateTime_to_utc (void)
1473 {
1474   GDateTime *dt, *dt2;
1475   time_t     t;
1476   struct tm  tm;
1477
1478   t = time (NULL);
1479   g_assert_cmpint (t, !=, (time_t) -1);
1480 #ifdef HAVE_GMTIME_R
1481   gmtime_r (&t, &tm);
1482 #else
1483   {
1484     struct tm *tmp = gmtime (&t);
1485     memcpy (&tm, tmp, sizeof (struct tm));
1486   }
1487 #endif
1488   dt2 = g_date_time_new_from_unix_local (t);
1489   dt = g_date_time_to_utc (dt2);
1490   g_assert_cmpint (tm.tm_year + 1900, ==, g_date_time_get_year (dt));
1491   g_assert_cmpint (tm.tm_mon + 1, ==, g_date_time_get_month (dt));
1492   g_assert_cmpint (tm.tm_mday, ==, g_date_time_get_day_of_month (dt));
1493   g_assert_cmpint (tm.tm_hour, ==, g_date_time_get_hour (dt));
1494   g_assert_cmpint (tm.tm_min, ==, g_date_time_get_minute (dt));
1495   g_assert_cmpint (tm.tm_sec, ==, g_date_time_get_second (dt));
1496   g_date_time_unref (dt);
1497   g_date_time_unref (dt2);
1498 }
1499
1500 static void
1501 test_GDateTime_get_day_of_year (void)
1502 {
1503 #define TEST_DAY_OF_YEAR(y,m,d,o)                       G_STMT_START {  \
1504   GDateTime *__dt = g_date_time_new_local ((y), (m), (d), 0, 0, 0);     \
1505   g_assert_cmpint ((o), ==, g_date_time_get_day_of_year (__dt));        \
1506   g_date_time_unref (__dt);                             } G_STMT_END
1507
1508   TEST_DAY_OF_YEAR (2009, 1, 1, 1);
1509   TEST_DAY_OF_YEAR (2009, 2, 1, 32);
1510   TEST_DAY_OF_YEAR (2009, 8, 16, 228);
1511   TEST_DAY_OF_YEAR (2008, 8, 16, 229);
1512 }
1513
1514 static void
1515 test_GDateTime_printf (void)
1516 {
1517 /* 64 seems big, but one zoneinfo file, Factory, has an abbreviation
1518  * that long, and it will cause the test to fail if dst isn't big
1519  * enough.
1520  */
1521   gchar *old_lc_all;
1522   gchar *old_lc_messages;
1523   gchar dst[64];
1524   struct tm tt;
1525   time_t t;
1526
1527 #ifdef G_OS_WIN32
1528   gchar *current_tz = NULL;
1529   DYNAMIC_TIME_ZONE_INFORMATION dtz_info;
1530 #endif
1531
1532 #define TEST_PRINTF(f,o)                        G_STMT_START {  \
1533 GDateTime *__dt = g_date_time_new_local (2009, 10, 24, 0, 0, 0);\
1534   gchar *__p = g_date_time_format (__dt, (f));                  \
1535   g_assert_cmpstr (__p, ==, (o));                               \
1536   g_date_time_unref (__dt);                                     \
1537   g_free (__p);                                 } G_STMT_END
1538
1539 #define TEST_PRINTF_DATE(y,m,d,f,o)             G_STMT_START {  \
1540   GDateTime *dt = g_date_time_new_local (y, m, d, 0, 0, 0);     \
1541   gchar *p = g_date_time_format (dt, (f));                      \
1542   gchar *o_casefold = g_utf8_casefold (o, -1);                  \
1543   gchar *p_casefold = g_utf8_casefold (p, -1);                  \
1544   g_assert_cmpstr (p_casefold, ==, (o_casefold));               \
1545   g_date_time_unref (dt);                                       \
1546   g_free (p_casefold);                                          \
1547   g_free (o_casefold);                                          \
1548   g_free (p);                                   } G_STMT_END
1549
1550 #define TEST_PRINTF_TIME(h,m,s,f,o)             G_STMT_START { \
1551   GDateTime *dt = g_date_time_new_local (2009, 10, 24, (h), (m), (s)); \
1552   gchar *p = g_date_time_format (dt, (f));                      \
1553   g_assert_cmpstr (p, ==, (o));                                 \
1554   g_date_time_unref (dt);                                       \
1555   g_free (p);                                   } G_STMT_END
1556
1557   old_lc_all = g_strdup (g_getenv ("LC_ALL"));
1558   g_unsetenv ("LC_ALL");
1559
1560   old_lc_messages = g_strdup (g_getenv ("LC_MESSAGES"));
1561   g_setenv ("LC_MESSAGES", "C", TRUE);
1562
1563   /*
1564    * This is a little helper to make sure we can compare timezones to
1565    * that of the generated timezone.
1566    */
1567   t = time (NULL);
1568   g_assert_cmpint (t, !=, (time_t) -1);
1569   memset (&tt, 0, sizeof(tt));
1570   get_localtime_tm (t, &tt);
1571   tt.tm_year = 2009 - 1900;
1572   tt.tm_mon = 9; /* 0 indexed */
1573   tt.tm_mday = 24;
1574   t = mktime (&tt);
1575   memset (&tt, 0, sizeof(tt));
1576   get_localtime_tm (t, &tt);
1577   strftime (dst, sizeof(dst), "%Z", &tt);
1578
1579   /* get current time_t for 20090924 in the local timezone */
1580   tt.tm_sec = 0;
1581   tt.tm_min = 0;
1582   tt.tm_hour = 0;
1583   t = mktime (&tt);
1584
1585   TEST_PRINTF ("%a", "Sat");
1586   TEST_PRINTF ("%A", "Saturday");
1587   TEST_PRINTF ("%b", "Oct");
1588   TEST_PRINTF ("%B", "October");
1589   TEST_PRINTF ("%d", "24");
1590   TEST_PRINTF_DATE (2009, 1, 1, "%d", "01");
1591   TEST_PRINTF ("%e", "24"); // fixme
1592   TEST_PRINTF_TIME (10, 10, 1.001, "%f", "001000");
1593   TEST_PRINTF ("%h", "Oct");
1594   TEST_PRINTF ("%H", "00");
1595   TEST_PRINTF_TIME (15, 0, 0, "%H", "15");
1596   TEST_PRINTF ("%I", "12");
1597   TEST_PRINTF_TIME (12, 0, 0, "%I", "12");
1598   TEST_PRINTF_TIME (15, 0, 0, "%I", "03");
1599   TEST_PRINTF ("%j", "297");
1600   TEST_PRINTF ("%k", " 0");
1601   TEST_PRINTF_TIME (13, 13, 13, "%k", "13");
1602   TEST_PRINTF ("%l", "12");
1603   TEST_PRINTF_TIME (12, 0, 0, "%I", "12");
1604   TEST_PRINTF_TIME (13, 13, 13, "%l", " 1");
1605   TEST_PRINTF_TIME (10, 13, 13, "%l", "10");
1606   TEST_PRINTF ("%m", "10");
1607   TEST_PRINTF ("%M", "00");
1608   TEST_PRINTF ("%p", "AM");
1609   TEST_PRINTF_TIME (13, 13, 13, "%p", "PM");
1610   TEST_PRINTF ("%P", "am");
1611   TEST_PRINTF_TIME (13, 13, 13, "%P", "pm");
1612   TEST_PRINTF ("%r", "12:00:00 AM");
1613   TEST_PRINTF_TIME (13, 13, 13, "%r", "01:13:13 PM");
1614   TEST_PRINTF ("%R", "00:00");
1615   TEST_PRINTF_TIME (13, 13, 31, "%R", "13:13");
1616   TEST_PRINTF ("%S", "00");
1617   TEST_PRINTF ("%t", "  ");
1618   TEST_PRINTF ("%u", "6");
1619   TEST_PRINTF ("%x", "10/24/09");
1620   TEST_PRINTF ("%X", "00:00:00");
1621   TEST_PRINTF_TIME (13, 14, 15, "%X", "13:14:15");
1622   TEST_PRINTF ("%y", "09");
1623   TEST_PRINTF ("%Y", "2009");
1624   TEST_PRINTF ("%%", "%");
1625   TEST_PRINTF ("%", "");
1626   TEST_PRINTF ("%9", NULL);
1627 #ifdef G_OS_UNIX
1628   TEST_PRINTF ("%Z", dst);
1629 #elif defined G_OS_WIN32
1630   g_assert (GetDynamicTimeZoneInformation (&dtz_info) != TIME_ZONE_ID_INVALID);
1631   if (wcscmp (dtz_info.StandardName, L"") != 0)
1632     current_tz = g_utf16_to_utf8 (dtz_info.StandardName, -1, NULL, NULL, NULL);
1633   else
1634     current_tz = g_utf16_to_utf8 (dtz_info.DaylightName, -1, NULL, NULL, NULL);
1635
1636   TEST_PRINTF ("%Z", current_tz);
1637   g_free (current_tz);
1638 #endif
1639
1640   if (old_lc_messages != NULL)
1641     g_setenv ("LC_MESSAGES", old_lc_messages, TRUE);
1642   else
1643     g_unsetenv ("LC_MESSAGES");
1644   g_free (old_lc_messages);
1645
1646   if (old_lc_all != NULL)
1647     g_setenv ("LC_ALL", old_lc_all, TRUE);
1648   g_free (old_lc_all);
1649 }
1650
1651 static void
1652 test_non_utf8_printf (void)
1653 {
1654   gchar *oldlocale;
1655
1656   /* If running uninstalled (G_TEST_BUILDDIR is set), skip this test, since we
1657    * need the translations to be installed. We can’t mess around with
1658    * bindtextdomain() here, as the compiled .gmo files in po/ are not in the
1659    * right installed directory hierarchy to be successfully loaded by gettext. */
1660   if (g_getenv ("G_TEST_BUILDDIR") != NULL)
1661     {
1662       g_test_skip ("Skipping due to running uninstalled. "
1663                    "This test can only be run when the translations are installed.");
1664       return;
1665     }
1666
1667   oldlocale = g_strdup (setlocale (LC_ALL, NULL));
1668   setlocale (LC_ALL, "ja_JP.eucjp");
1669   if (strstr (setlocale (LC_ALL, NULL), "ja_JP") == NULL)
1670     {
1671       g_test_skip ("locale ja_JP.eucjp not available, skipping non-UTF8 tests");
1672       g_free (oldlocale);
1673       return;
1674     }
1675   if (g_get_charset (NULL))
1676     {
1677       g_test_skip ("locale ja_JP.eucjp may be available, but glib seems to think that it's equivalent to UTF-8, skipping non-UTF-8 tests. This is a known issue on Darwin");
1678       setlocale (LC_ALL, oldlocale);
1679       g_free (oldlocale);
1680       return;
1681     }
1682
1683   /* These are the outputs that ja_JP.UTF-8 generates; if everything
1684    * is working then ja_JP.eucjp should generate the same.
1685    */
1686   TEST_PRINTF ("%a", "\345\234\237");
1687   TEST_PRINTF ("%A", "\345\234\237\346\233\234\346\227\245");
1688 #ifndef __APPLE__ /* OSX just returns the number */
1689   TEST_PRINTF ("%b", "10\346\234\210");
1690 #endif
1691   TEST_PRINTF ("%B", "10\346\234\210");
1692   TEST_PRINTF ("%d", "24");
1693   TEST_PRINTF_DATE (2009, 1, 1, "%d", "01");
1694   TEST_PRINTF ("%e", "24"); // fixme
1695 #ifndef __APPLE__ /* OSX just returns the number */
1696   TEST_PRINTF ("%h", "10\346\234\210");
1697 #endif
1698   TEST_PRINTF ("%H", "00");
1699   TEST_PRINTF_TIME (15, 0, 0, "%H", "15");
1700   TEST_PRINTF ("%I", "12");
1701   TEST_PRINTF_TIME (12, 0, 0, "%I", "12");
1702   TEST_PRINTF_TIME (15, 0, 0, "%I", "03");
1703   TEST_PRINTF ("%j", "297");
1704   TEST_PRINTF ("%k", " 0");
1705   TEST_PRINTF_TIME (13, 13, 13, "%k", "13");
1706   TEST_PRINTF ("%l", "12");
1707   TEST_PRINTF_TIME (12, 0, 0, "%I", "12");
1708   TEST_PRINTF_TIME (13, 13, 13, "%l", " 1");
1709   TEST_PRINTF_TIME (10, 13, 13, "%l", "10");
1710   TEST_PRINTF ("%m", "10");
1711   TEST_PRINTF ("%M", "00");
1712 #ifndef __APPLE__ /* OSX returns latin "AM", not japanese */
1713   TEST_PRINTF ("%p", "\345\215\210\345\211\215");
1714   TEST_PRINTF_TIME (13, 13, 13, "%p", "\345\215\210\345\276\214");
1715   TEST_PRINTF ("%P", "\345\215\210\345\211\215");
1716   TEST_PRINTF_TIME (13, 13, 13, "%P", "\345\215\210\345\276\214");
1717   TEST_PRINTF ("%r", "\345\215\210\345\211\21512\346\231\20200\345\210\20600\347\247\222");
1718   TEST_PRINTF_TIME (13, 13, 13, "%r", "\345\215\210\345\276\21401\346\231\20213\345\210\20613\347\247\222");
1719 #endif
1720   TEST_PRINTF ("%R", "00:00");
1721   TEST_PRINTF_TIME (13, 13, 31, "%R", "13:13");
1722   TEST_PRINTF ("%S", "00");
1723   TEST_PRINTF ("%t", "  ");
1724   TEST_PRINTF ("%u", "6");
1725 #ifndef __APPLE__ /* OSX returns YYYY/MM/DD in ASCII */
1726   TEST_PRINTF ("%x", "2009\345\271\26410\346\234\21024\346\227\245");
1727 #endif
1728   TEST_PRINTF ("%X", "00\346\231\20200\345\210\20600\347\247\222");
1729   TEST_PRINTF_TIME (13, 14, 15, "%X", "13\346\231\20214\345\210\20615\347\247\222");
1730   TEST_PRINTF ("%y", "09");
1731   TEST_PRINTF ("%Y", "2009");
1732   TEST_PRINTF ("%%", "%");
1733   TEST_PRINTF ("%", "");
1734   TEST_PRINTF ("%9", NULL);
1735
1736   setlocale (LC_ALL, oldlocale);
1737   g_free (oldlocale);
1738 }
1739
1740 /* Checks that it is possible to use format string that
1741  * is unrepresentable in current locale charset. */
1742 static void
1743 test_format_unrepresentable (void)
1744 {
1745   gchar *oldlocale = g_strdup (setlocale (LC_ALL, NULL));
1746   setlocale (LC_ALL, "POSIX");
1747
1748   TEST_PRINTF ("ąśćł", "ąśćł");
1749
1750   /* We are using Unicode ratio symbol here, which is outside ASCII. */
1751   TEST_PRINTF_TIME (23, 15, 0, "%H∶%M", "23∶15");
1752
1753   /* Test again, this time in locale with non ASCII charset. */
1754   if (setlocale (LC_ALL, "pl_PL.ISO-8859-2") != NULL)
1755     TEST_PRINTF_TIME (23, 15, 0, "%H∶%M", "23∶15");
1756   else
1757     g_test_skip ("locale pl_PL.ISO-8859-2 not available, skipping test");
1758
1759   setlocale (LC_ALL, oldlocale);
1760   g_free (oldlocale);
1761 }
1762
1763 static void
1764 test_modifiers (void)
1765 {
1766   gchar *oldlocale;
1767
1768   TEST_PRINTF_DATE (2009, 1,  1,  "%d", "01");
1769   TEST_PRINTF_DATE (2009, 1,  1, "%_d", " 1");
1770   TEST_PRINTF_DATE (2009, 1,  1, "%-d", "1");
1771   TEST_PRINTF_DATE (2009, 1,  1, "%0d", "01");
1772   TEST_PRINTF_DATE (2009, 1, 21,  "%d", "21");
1773   TEST_PRINTF_DATE (2009, 1, 21, "%_d", "21");
1774   TEST_PRINTF_DATE (2009, 1, 21, "%-d", "21");
1775   TEST_PRINTF_DATE (2009, 1, 21, "%0d", "21");
1776
1777   TEST_PRINTF_DATE (2009, 1,  1,  "%e", " 1");
1778   TEST_PRINTF_DATE (2009, 1,  1, "%_e", " 1");
1779   TEST_PRINTF_DATE (2009, 1,  1, "%-e", "1");
1780   TEST_PRINTF_DATE (2009, 1,  1, "%0e", "01");
1781   TEST_PRINTF_DATE (2009, 1, 21,  "%e", "21");
1782   TEST_PRINTF_DATE (2009, 1, 21, "%_e", "21");
1783   TEST_PRINTF_DATE (2009, 1, 21, "%-e", "21");
1784   TEST_PRINTF_DATE (2009, 1, 21, "%0e", "21");
1785
1786   TEST_PRINTF_TIME ( 1, 0, 0,  "%H", "01");
1787   TEST_PRINTF_TIME ( 1, 0, 0, "%_H", " 1");
1788   TEST_PRINTF_TIME ( 1, 0, 0, "%-H", "1");
1789   TEST_PRINTF_TIME ( 1, 0, 0, "%0H", "01");
1790   TEST_PRINTF_TIME (21, 0, 0,  "%H", "21");
1791   TEST_PRINTF_TIME (21, 0, 0, "%_H", "21");
1792   TEST_PRINTF_TIME (21, 0, 0, "%-H", "21");
1793   TEST_PRINTF_TIME (21, 0, 0, "%0H", "21");
1794
1795   TEST_PRINTF_TIME ( 1, 0, 0,  "%I", "01");
1796   TEST_PRINTF_TIME ( 1, 0, 0, "%_I", " 1");
1797   TEST_PRINTF_TIME ( 1, 0, 0, "%-I", "1");
1798   TEST_PRINTF_TIME ( 1, 0, 0, "%0I", "01");
1799   TEST_PRINTF_TIME (23, 0, 0,  "%I", "11");
1800   TEST_PRINTF_TIME (23, 0, 0, "%_I", "11");
1801   TEST_PRINTF_TIME (23, 0, 0, "%-I", "11");
1802   TEST_PRINTF_TIME (23, 0, 0, "%0I", "11");
1803
1804   TEST_PRINTF_TIME ( 1, 0, 0,  "%k", " 1");
1805   TEST_PRINTF_TIME ( 1, 0, 0, "%_k", " 1");
1806   TEST_PRINTF_TIME ( 1, 0, 0, "%-k", "1");
1807   TEST_PRINTF_TIME ( 1, 0, 0, "%0k", "01");
1808
1809   oldlocale = g_strdup (setlocale (LC_ALL, NULL));
1810   setlocale (LC_ALL, "fa_IR.utf-8");
1811   if (strstr (setlocale (LC_ALL, NULL), "fa_IR") != NULL)
1812     {
1813       TEST_PRINTF_TIME (23, 0, 0, "%OH", "\333\262\333\263");    /* '23' */
1814       TEST_PRINTF_TIME (23, 0, 0, "%OI", "\333\261\333\261");    /* '11' */
1815       TEST_PRINTF_TIME (23, 0, 0, "%OM", "\333\260\333\260");    /* '00' */
1816
1817       TEST_PRINTF_DATE (2011, 7, 1, "%Om", "\333\260\333\267");  /* '07' */
1818       TEST_PRINTF_DATE (2011, 7, 1, "%0Om", "\333\260\333\267"); /* '07' */
1819       TEST_PRINTF_DATE (2011, 7, 1, "%-Om", "\333\267");         /* '7' */
1820       TEST_PRINTF_DATE (2011, 7, 1, "%_Om", " \333\267");        /* ' 7' */
1821     }
1822   else
1823     g_test_skip ("locale fa_IR not available, skipping O modifier tests");
1824   setlocale (LC_ALL, oldlocale);
1825   g_free (oldlocale);
1826 }
1827
1828 /* Test that the `O` modifier for g_date_time_format() works with %B, %b and %h;
1829  * i.e. whether genitive month names are supported. */
1830 static void
1831 test_month_names (void)
1832 {
1833   gchar *oldlocale;
1834
1835   g_test_bug ("http://bugzilla.gnome.org/749206");
1836
1837   /* If running uninstalled (G_TEST_BUILDDIR is set), skip this test, since we
1838    * need the translations to be installed. We can’t mess around with
1839    * bindtextdomain() here, as the compiled .gmo files in po/ are not in the
1840    * right installed directory hierarchy to be successfully loaded by gettext. */
1841   if (g_getenv ("G_TEST_BUILDDIR") != NULL)
1842     {
1843       g_test_skip ("Skipping due to running uninstalled. "
1844                    "This test can only be run when the translations are installed.");
1845       return;
1846     }
1847
1848   oldlocale = g_strdup (setlocale (LC_ALL, NULL));
1849
1850   /* Make sure that nothing has been changed in western European languages.  */
1851   setlocale (LC_ALL, "en_GB.utf-8");
1852   if (strstr (setlocale (LC_ALL, NULL), "en_GB") != NULL)
1853     {
1854       TEST_PRINTF_DATE (2018,  1,  1,  "%B", "January");
1855       TEST_PRINTF_DATE (2018,  2,  1, "%OB", "February");
1856       TEST_PRINTF_DATE (2018,  3,  1,  "%b", "Mar");
1857       TEST_PRINTF_DATE (2018,  4,  1, "%Ob", "Apr");
1858       TEST_PRINTF_DATE (2018,  5,  1,  "%h", "May");
1859       TEST_PRINTF_DATE (2018,  6,  1, "%Oh", "Jun");
1860     }
1861   else
1862     g_test_skip ("locale en_GB not available, skipping English month names test");
1863
1864   setlocale (LC_ALL, "de_DE.utf-8");
1865   if (strstr (setlocale (LC_ALL, NULL), "de_DE") != NULL)
1866     {
1867       TEST_PRINTF_DATE (2018,  7,  1,  "%B", "Juli");
1868       TEST_PRINTF_DATE (2018,  8,  1, "%OB", "August");
1869       TEST_PRINTF_DATE (2018,  9,  1,  "%b", "Sep");
1870       TEST_PRINTF_DATE (2018, 10,  1, "%Ob", "Okt");
1871       TEST_PRINTF_DATE (2018, 11,  1,  "%h", "Nov");
1872       TEST_PRINTF_DATE (2018, 12,  1, "%Oh", "Dez");
1873     }
1874   else
1875     g_test_skip ("locale de_DE not available, skipping German month names test");
1876
1877   setlocale (LC_ALL, "es_ES.utf-8");
1878   if (strstr (setlocale (LC_ALL, NULL), "es_ES") != NULL)
1879     {
1880       TEST_PRINTF_DATE (2018,  1,  1,  "%B", "enero");
1881       TEST_PRINTF_DATE (2018,  2,  1, "%OB", "febrero");
1882       TEST_PRINTF_DATE (2018,  3,  1,  "%b", "mar");
1883       TEST_PRINTF_DATE (2018,  4,  1, "%Ob", "abr");
1884       TEST_PRINTF_DATE (2018,  5,  1,  "%h", "may");
1885       TEST_PRINTF_DATE (2018,  6,  1, "%Oh", "jun");
1886     }
1887   else
1888     g_test_skip ("locale es_ES not available, skipping Spanish month names test");
1889
1890   setlocale (LC_ALL, "fr_FR.utf-8");
1891   if (strstr (setlocale (LC_ALL, NULL), "fr_FR") != NULL)
1892     {
1893       TEST_PRINTF_DATE (2018,  7,  1,  "%B", "juillet");
1894       TEST_PRINTF_DATE (2018,  8,  1, "%OB", "août");
1895       TEST_PRINTF_DATE (2018,  9,  1,  "%b", "sept.");
1896       TEST_PRINTF_DATE (2018, 10,  1, "%Ob", "oct.");
1897       TEST_PRINTF_DATE (2018, 11,  1,  "%h", "nov.");
1898       TEST_PRINTF_DATE (2018, 12,  1, "%Oh", "déc.");
1899     }
1900   else
1901     g_test_skip ("locale fr_FR not available, skipping French month names test");
1902
1903   /* Make sure that there are visible changes in some European languages.  */
1904   setlocale (LC_ALL, "el_GR.utf-8");
1905   if (strstr (setlocale (LC_ALL, NULL), "el_GR") != NULL)
1906     {
1907       TEST_PRINTF_DATE (2018,  1,  1,  "%B", "Ιανουαρίου");
1908       TEST_PRINTF_DATE (2018,  2,  1,  "%B", "Φεβρουαρίου");
1909       TEST_PRINTF_DATE (2018,  3,  1,  "%B", "Μαρτίου");
1910       TEST_PRINTF_DATE (2018,  4,  1, "%OB", "Απρίλιος");
1911       TEST_PRINTF_DATE (2018,  5,  1, "%OB", "Μάιος");
1912       TEST_PRINTF_DATE (2018,  6,  1, "%OB", "Ιούνιος");
1913       TEST_PRINTF_DATE (2018,  7,  1,  "%b", "Ιουλ");
1914       TEST_PRINTF_DATE (2018,  8,  1, "%Ob", "Αύγ");
1915     }
1916   else
1917     g_test_skip ("locale el_GR not available, skipping Greek month names test");
1918
1919   setlocale (LC_ALL, "hr_HR.utf-8");
1920   if (strstr (setlocale (LC_ALL, NULL), "hr_HR") != NULL)
1921     {
1922       TEST_PRINTF_DATE (2018,  5,  1,  "%B", "svibnja");
1923       TEST_PRINTF_DATE (2018,  6,  1,  "%B", "lipnja");
1924       TEST_PRINTF_DATE (2018,  7,  1,  "%B", "srpnja");
1925       TEST_PRINTF_DATE (2018,  8,  1, "%OB", "Kolovoz");
1926       TEST_PRINTF_DATE (2018,  9,  1, "%OB", "Rujan");
1927       TEST_PRINTF_DATE (2018, 10,  1, "%OB", "Listopad");
1928       TEST_PRINTF_DATE (2018, 11,  1,  "%b", "Stu");
1929       TEST_PRINTF_DATE (2018, 12,  1, "%Ob", "Pro");
1930     }
1931   else
1932     g_test_skip ("locale hr_HR not available, skipping Croatian month names test");
1933
1934   setlocale (LC_ALL, "lt_LT.utf-8");
1935   if (strstr (setlocale (LC_ALL, NULL), "lt_LT") != NULL)
1936     {
1937       TEST_PRINTF_DATE (2018,  1,  1,  "%B", "sausio");
1938       TEST_PRINTF_DATE (2018,  2,  1,  "%B", "vasario");
1939       TEST_PRINTF_DATE (2018,  3,  1,  "%B", "kovo");
1940       TEST_PRINTF_DATE (2018,  4,  1, "%OB", "balandis");
1941       TEST_PRINTF_DATE (2018,  5,  1, "%OB", "gegužė");
1942       TEST_PRINTF_DATE (2018,  6,  1, "%OB", "birželis");
1943       TEST_PRINTF_DATE (2018,  7,  1,  "%b", "liep.");
1944       TEST_PRINTF_DATE (2018,  8,  1, "%Ob", "rugp.");
1945     }
1946   else
1947     g_test_skip ("locale lt_LT not available, skipping Lithuanian month names test");
1948
1949   setlocale (LC_ALL, "pl_PL.utf-8");
1950   if (strstr (setlocale (LC_ALL, NULL), "pl_PL") != NULL)
1951     {
1952       TEST_PRINTF_DATE (2018,  5,  1,  "%B", "maja");
1953       TEST_PRINTF_DATE (2018,  6,  1,  "%B", "czerwca");
1954       TEST_PRINTF_DATE (2018,  7,  1,  "%B", "lipca");
1955       TEST_PRINTF_DATE (2018,  8,  1, "%OB", "sierpień");
1956       TEST_PRINTF_DATE (2018,  9,  1, "%OB", "wrzesień");
1957       TEST_PRINTF_DATE (2018, 10,  1, "%OB", "październik");
1958       TEST_PRINTF_DATE (2018, 11,  1,  "%b", "lis");
1959       TEST_PRINTF_DATE (2018, 12,  1, "%Ob", "gru");
1960     }
1961   else
1962     g_test_skip ("locale pl_PL not available, skipping Polish month names test");
1963
1964   setlocale (LC_ALL, "ru_RU.utf-8");
1965   if (strstr (setlocale (LC_ALL, NULL), "ru_RU") != NULL)
1966     {
1967       TEST_PRINTF_DATE (2018,  1,  1,  "%B", "января");
1968       TEST_PRINTF_DATE (2018,  2,  1,  "%B", "февраля");
1969       TEST_PRINTF_DATE (2018,  3,  1,  "%B", "марта");
1970       TEST_PRINTF_DATE (2018,  4,  1, "%OB", "Апрель");
1971       TEST_PRINTF_DATE (2018,  5,  1, "%OB", "Май");
1972       TEST_PRINTF_DATE (2018,  6,  1, "%OB", "Июнь");
1973       TEST_PRINTF_DATE (2018,  7,  1,  "%b", "июл");
1974       TEST_PRINTF_DATE (2018,  8,  1, "%Ob", "авг");
1975       /* This difference is very important in Russian:  */
1976       TEST_PRINTF_DATE (2018,  5,  1,  "%b", "мая");
1977       TEST_PRINTF_DATE (2018,  5,  1, "%Ob", "май");
1978     }
1979   else
1980     g_test_skip ("locale ru_RU not available, skipping Russian month names test");
1981
1982   setlocale (LC_ALL, oldlocale);
1983   g_free (oldlocale);
1984 }
1985
1986 static void
1987 test_GDateTime_dst (void)
1988 {
1989   GDateTime *dt1, *dt2;
1990   GTimeZone *tz;
1991
1992   /* this date has the DST state set for Europe/London */
1993 #ifdef G_OS_UNIX
1994   tz = g_time_zone_new ("Europe/London");
1995 #elif defined G_OS_WIN32
1996   tz = g_time_zone_new ("GMT Standard Time");
1997 #endif
1998   dt1 = g_date_time_new (tz, 2009, 8, 15, 3, 0, 1);
1999   g_assert (g_date_time_is_daylight_savings (dt1));
2000   g_assert_cmpint (g_date_time_get_utc_offset (dt1) / G_USEC_PER_SEC, ==, 3600);
2001   g_assert_cmpint (g_date_time_get_hour (dt1), ==, 3);
2002
2003   /* add 6 months to clear the DST flag but keep the same time */
2004   dt2 = g_date_time_add_months (dt1, 6);
2005   g_assert (!g_date_time_is_daylight_savings (dt2));
2006   g_assert_cmpint (g_date_time_get_utc_offset (dt2) / G_USEC_PER_SEC, ==, 0);
2007   g_assert_cmpint (g_date_time_get_hour (dt2), ==, 3);
2008
2009   g_date_time_unref (dt2);
2010   g_date_time_unref (dt1);
2011
2012   /* now do the reverse: start with a non-DST state and move to DST */
2013   dt1 = g_date_time_new (tz, 2009, 2, 15, 2, 0, 1);
2014   g_assert (!g_date_time_is_daylight_savings (dt1));
2015   g_assert_cmpint (g_date_time_get_hour (dt1), ==, 2);
2016
2017   dt2 = g_date_time_add_months (dt1, 6);
2018   g_assert (g_date_time_is_daylight_savings (dt2));
2019   g_assert_cmpint (g_date_time_get_hour (dt2), ==, 2);
2020
2021   g_date_time_unref (dt2);
2022   g_date_time_unref (dt1);
2023   g_time_zone_unref (tz);
2024 }
2025
2026 static inline gboolean
2027 is_leap_year (gint year)
2028 {
2029   g_assert (1 <= year && year <= 9999);
2030
2031   return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
2032 }
2033
2034 static inline gint
2035 days_in_month (gint year, gint month)
2036 {
2037   const gint table[2][13] = {
2038     {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
2039     {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
2040   };
2041
2042   g_assert (1 <= month && month <= 12);
2043
2044   return table[is_leap_year (year)][month];
2045 }
2046
2047 static void
2048 test_all_dates (void)
2049 {
2050   gint year, month, day;
2051   GTimeZone *timezone;
2052   gint64 unix_time;
2053   gint day_of_year;
2054   gint week_year;
2055   gint week_num;
2056   gint weekday;
2057
2058   /* save some time by hanging on to this. */
2059   timezone = g_time_zone_new_utc ();
2060
2061   unix_time = G_GINT64_CONSTANT(-62135596800);
2062
2063   /* 0001-01-01 is 0001-W01-1 */
2064   week_year = 1;
2065   week_num = 1;
2066   weekday = 1;
2067
2068
2069   /* The calendar makes a full cycle every 400 years, so we could
2070    * theoretically just test years 1 through 400.  That assumes that our
2071    * software has no bugs, so probably we should just test them all. :)
2072    */
2073   for (year = 1; year <= 9999; year++)
2074     {
2075       day_of_year = 1;
2076
2077       for (month = 1; month <= 12; month++)
2078         for (day = 1; day <= days_in_month (year, month); day++)
2079           {
2080             GDateTime *dt;
2081
2082             dt = g_date_time_new (timezone, year, month, day, 0, 0, 0);
2083
2084 #if 0
2085             g_printerr ("%04d-%02d-%02d = %04d-W%02d-%d = %04d-%03d\n",
2086                      year, month, day,
2087                      week_year, week_num, weekday,
2088                      year, day_of_year);
2089 #endif
2090
2091             /* sanity check */
2092             if G_UNLIKELY (g_date_time_get_year (dt) != year ||
2093                            g_date_time_get_month (dt) != month ||
2094                            g_date_time_get_day_of_month (dt) != day)
2095               g_error ("%04d-%02d-%02d comes out as %04d-%02d-%02d",
2096                        year, month, day,
2097                        g_date_time_get_year (dt),
2098                        g_date_time_get_month (dt),
2099                        g_date_time_get_day_of_month (dt));
2100
2101             if G_UNLIKELY (g_date_time_get_week_numbering_year (dt) != week_year ||
2102                            g_date_time_get_week_of_year (dt) != week_num ||
2103                            g_date_time_get_day_of_week (dt) != weekday)
2104               g_error ("%04d-%02d-%02d should be %04d-W%02d-%d but "
2105                        "comes out as %04d-W%02d-%d", year, month, day,
2106                        week_year, week_num, weekday,
2107                        g_date_time_get_week_numbering_year (dt),
2108                        g_date_time_get_week_of_year (dt),
2109                        g_date_time_get_day_of_week (dt));
2110
2111             if G_UNLIKELY (g_date_time_to_unix (dt) != unix_time)
2112               g_error ("%04d-%02d-%02d 00:00:00 UTC should have unix time %"
2113                        G_GINT64_FORMAT " but comes out as %"G_GINT64_FORMAT,
2114                        year, month, day, unix_time, g_date_time_to_unix (dt));
2115
2116             if G_UNLIKELY (g_date_time_get_day_of_year (dt) != day_of_year)
2117               g_error ("%04d-%02d-%02d should be day of year %d"
2118                        " but comes out as %d", year, month, day,
2119                        day_of_year, g_date_time_get_day_of_year (dt));
2120
2121             if G_UNLIKELY (g_date_time_get_hour (dt) != 0 ||
2122                            g_date_time_get_minute (dt) != 0 ||
2123                            g_date_time_get_seconds (dt) != 0)
2124               g_error ("%04d-%02d-%02d 00:00:00 UTC comes out "
2125                        "as %02d:%02d:%02.6f", year, month, day,
2126                        g_date_time_get_hour (dt),
2127                        g_date_time_get_minute (dt),
2128                        g_date_time_get_seconds (dt));
2129             /* done */
2130
2131             /* add 24 hours to unix time */
2132             unix_time += 24 * 60 * 60;
2133
2134             /* move day of year forward */
2135             day_of_year++;
2136
2137             /* move the week date forward */
2138             if (++weekday == 8)
2139               {
2140                 weekday = 1; /* Sunday -> Monday */
2141
2142                 /* NOTE: year/month/day is the final day of the week we
2143                  * just finished.
2144                  *
2145                  * If we just finished the last week of last year then
2146                  * we are definitely starting the first week of this
2147                  * year.
2148                  *
2149                  * Otherwise, if we're still in this year, but Sunday
2150                  * fell on or after December 28 then December 29, 30, 31
2151                  * could be days within the next year's first year.
2152                  */
2153                 if (year != week_year || (month == 12 && day >= 28))
2154                   {
2155                     /* first week of the new year */
2156                     week_num = 1;
2157                     week_year++;
2158                   }
2159                 else
2160                   week_num++;
2161               }
2162
2163             g_date_time_unref (dt);
2164           }
2165     }
2166
2167   g_time_zone_unref (timezone);
2168 }
2169
2170 static void
2171 test_z (void)
2172 {
2173   GTimeZone *tz;
2174   GDateTime *dt;
2175   gchar *p;
2176
2177   g_test_bug ("http://bugzilla.gnome.org/642935");
2178
2179   tz = g_time_zone_new ("-08:00");
2180   dt = g_date_time_new (tz, 1, 1, 1, 0, 0, 0);
2181
2182   p = g_date_time_format (dt, "%z");
2183   g_assert_cmpstr (p, ==, "-0800");
2184   g_free (p);
2185
2186   p = g_date_time_format (dt, "%:z");
2187   g_assert_cmpstr (p, ==, "-08:00");
2188   g_free (p);
2189
2190   p = g_date_time_format (dt, "%::z");
2191   g_assert_cmpstr (p, ==, "-08:00:00");
2192   g_free (p);
2193
2194   p = g_date_time_format (dt, "%:::z");
2195   g_assert_cmpstr (p, ==, "-08");
2196   g_free (p);
2197
2198   g_date_time_unref (dt);
2199   g_time_zone_unref (tz);
2200
2201   tz = g_time_zone_new ("+00:00");
2202   dt = g_date_time_new (tz, 1, 1, 1, 0, 0, 0);
2203   p = g_date_time_format (dt, "%:::z");
2204   g_assert_cmpstr (p, ==, "+00");
2205   g_free (p);
2206   g_date_time_unref (dt);
2207   g_time_zone_unref (tz);
2208
2209   tz = g_time_zone_new ("+08:23");
2210   dt = g_date_time_new (tz, 1, 1, 1, 0, 0, 0);
2211   p = g_date_time_format (dt, "%:::z");
2212   g_assert_cmpstr (p, ==, "+08:23");
2213   g_free (p);
2214   g_date_time_unref (dt);
2215   g_time_zone_unref (tz);
2216
2217   tz = g_time_zone_new ("+08:23:45");
2218   dt = g_date_time_new (tz, 1, 1, 1, 0, 0, 0);
2219   p = g_date_time_format (dt, "%:::z");
2220   g_assert_cmpstr (p, ==, "+08:23:45");
2221   g_free (p);
2222   g_date_time_unref (dt);
2223   g_time_zone_unref (tz);
2224
2225   tz = g_time_zone_new ("-00:15");
2226   dt = g_date_time_new (tz, 1, 1, 1, 0, 0, 0);
2227
2228   p = g_date_time_format (dt, "%z");
2229   g_assert_cmpstr (p, ==, "-0015");
2230   g_free (p);
2231
2232   p = g_date_time_format (dt, "%:z");
2233   g_assert_cmpstr (p, ==, "-00:15");
2234   g_free (p);
2235
2236   p = g_date_time_format (dt, "%::z");
2237   g_assert_cmpstr (p, ==, "-00:15:00");
2238   g_free (p);
2239
2240   p = g_date_time_format (dt, "%:::z");
2241   g_assert_cmpstr (p, ==, "-00:15");
2242   g_free (p);
2243
2244   g_date_time_unref (dt);
2245   g_time_zone_unref (tz);
2246 }
2247
2248 static void
2249 test_6_days_until_end_of_the_month (void)
2250 {
2251   GTimeZone *tz;
2252   GDateTime *dt;
2253   gchar *p;
2254
2255   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2215");
2256
2257 #ifdef G_OS_UNIX
2258   /* This is the footertz string from `Europe/Paris` from tzdata 2020b. It’s
2259    * used by GLib when the tzdata file was compiled with `zic -b slim`, which is
2260    * the default in tzcode ≥2020b.
2261    *
2262    * The `M10.5.0` part indicates that the summer time end transition happens on
2263    * the Sunday (`0`) in the last week (`5`) of October (`10`). That’s 6 days
2264    * before the end of the month, and hence was triggering issue #2215.
2265    *
2266    * References:
2267    *  - https://tools.ietf.org/id/draft-murchison-tzdist-tzif-15.html#rfc.section.3.3
2268    *  - https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03
2269    */
2270   tz = g_time_zone_new ("CET-1CEST,M3.5.0,M10.5.0/3");
2271 #elif defined (G_OS_WIN32)
2272   tz = g_time_zone_new ("Romance Standard Time");
2273 #endif
2274   dt = g_date_time_new (tz, 2020, 10, 5, 1, 1, 1);
2275
2276   p = g_date_time_format (dt, "%Y-%m-%d %H:%M:%S%z");
2277   /* Incorrect output is  "2020-10-05 01:01:01+0100" */
2278   g_assert_cmpstr (p, ==, "2020-10-05 01:01:01+0200");
2279   g_free (p);
2280
2281   g_date_time_unref (dt);
2282   g_time_zone_unref (tz);
2283 }
2284
2285 static void
2286 test_format_iso8601 (void)
2287 {
2288   GTimeZone *tz = NULL;
2289   GDateTime *dt = NULL;
2290   gchar *p = NULL;
2291
2292   tz = g_time_zone_new_utc ();
2293   dt = g_date_time_new (tz, 2019, 6, 26, 15, 1, 5);
2294   p = g_date_time_format_iso8601 (dt);
2295   g_assert_cmpstr (p, ==, "2019-06-26T15:01:05Z");
2296   g_free (p);
2297   g_date_time_unref (dt);
2298   g_time_zone_unref (tz);
2299
2300   tz = g_time_zone_new_offset (-60 * 60);
2301   dt = g_date_time_new (tz, 2019, 6, 26, 15, 1, 5);
2302   p = g_date_time_format_iso8601 (dt);
2303   g_assert_cmpstr (p, ==, "2019-06-26T15:01:05-01");
2304   g_free (p);
2305   g_date_time_unref (dt);
2306   g_time_zone_unref (tz);
2307
2308   tz = g_time_zone_new_utc ();
2309   dt = g_date_time_new (tz, 2020, 8, 5, 12, 30, 55.000001);
2310   p = g_date_time_format_iso8601 (dt);
2311   g_assert_cmpstr (p, ==, "2020-08-05T12:30:55.000001Z");
2312   g_free (p);
2313   g_date_time_unref (dt);
2314   g_time_zone_unref (tz);
2315 }
2316
2317 #pragma GCC diagnostic push
2318 #pragma GCC diagnostic ignored "-Wformat-y2k"
2319 static void
2320 test_strftime (void)
2321 {
2322 #ifdef __linux__
2323 #define TEST_FORMAT \
2324   "a%a A%A b%b B%B c%c C%C d%d e%e F%F g%g G%G h%h H%H I%I j%j m%m M%M " \
2325   "n%n p%p r%r R%R S%S t%t T%T u%u V%V w%w x%x X%X y%y Y%Y z%z Z%Z %%"
2326   time_t t;
2327
2328   /* 127997 is prime, 1315005118 is now */
2329   for (t = 0; t < 1315005118; t += 127997)
2330     {
2331       GDateTime *date_time;
2332       gchar c_str[1000];
2333       gchar *dt_str;
2334
2335       date_time = g_date_time_new_from_unix_local (t);
2336       dt_str = g_date_time_format (date_time, TEST_FORMAT);
2337       strftime (c_str, sizeof c_str, TEST_FORMAT, localtime (&t));
2338       g_assert_cmpstr (c_str, ==, dt_str);
2339       g_date_time_unref (date_time);
2340       g_free (dt_str);
2341     }
2342 #endif
2343 }
2344 #pragma GCC diagnostic pop
2345
2346 /* Check that g_date_time_format() correctly returns %NULL for format
2347  * placeholders which are not supported in the current locale. */
2348 static void
2349 test_GDateTime_strftime_error_handling (void)
2350 {
2351   gchar *oldlocale;
2352
2353   oldlocale = g_strdup (setlocale (LC_ALL, NULL));
2354   setlocale (LC_ALL, "de_DE.utf-8");
2355   if (strstr (setlocale (LC_ALL, NULL), "de_DE") != NULL)
2356     {
2357       /* de_DE doesn’t ever write time in 12-hour notation, so %r is
2358        * unsupported for it. */
2359       TEST_PRINTF_TIME (23, 0, 0, "%r", NULL);
2360     }
2361   else
2362     g_test_skip ("locale de_DE not available, skipping error handling tests");
2363   setlocale (LC_ALL, oldlocale);
2364   g_free (oldlocale);
2365 }
2366
2367 static void
2368 test_find_interval (void)
2369 {
2370   GTimeZone *tz;
2371   GDateTime *dt;
2372   gint64 u;
2373   gint i1, i2;
2374
2375 #ifdef G_OS_UNIX
2376   tz = g_time_zone_new ("America/Toronto");
2377 #elif defined G_OS_WIN32
2378   tz = g_time_zone_new ("Eastern Standard Time");
2379 #endif
2380   dt = g_date_time_new_utc (2010, 11, 7, 1, 30, 0);
2381   u = g_date_time_to_unix (dt);
2382
2383   i1 = g_time_zone_find_interval (tz, G_TIME_TYPE_STANDARD, u);
2384   i2 = g_time_zone_find_interval (tz, G_TIME_TYPE_DAYLIGHT, u);
2385
2386   g_assert_cmpint (i1, !=, i2);
2387
2388   g_date_time_unref (dt);
2389
2390   dt = g_date_time_new_utc (2010, 3, 14, 2, 0, 0);
2391   u = g_date_time_to_unix (dt);
2392
2393   i1 = g_time_zone_find_interval (tz, G_TIME_TYPE_STANDARD, u);
2394   g_assert_cmpint (i1, ==, -1);
2395
2396   g_date_time_unref (dt);
2397   g_time_zone_unref (tz);
2398 }
2399
2400 static void
2401 test_adjust_time (void)
2402 {
2403   GTimeZone *tz;
2404   GDateTime *dt;
2405   gint64 u, u2;
2406   gint i1, i2;
2407
2408 #ifdef G_OS_UNIX
2409   tz = g_time_zone_new ("America/Toronto");
2410 #elif defined G_OS_WIN32
2411   tz = g_time_zone_new ("Eastern Standard Time");
2412 #endif
2413   dt = g_date_time_new_utc (2010, 11, 7, 1, 30, 0);
2414   u = g_date_time_to_unix (dt);
2415   u2 = u;
2416
2417   i1 = g_time_zone_find_interval (tz, G_TIME_TYPE_DAYLIGHT, u);
2418   i2 = g_time_zone_adjust_time (tz, G_TIME_TYPE_DAYLIGHT, &u2);
2419
2420   g_assert_cmpint (i1, ==, i2);
2421   g_assert (u == u2);
2422
2423   g_date_time_unref (dt);
2424
2425   dt = g_date_time_new_utc (2010, 3, 14, 2, 30, 0);
2426   u2 = g_date_time_to_unix (dt);
2427   g_date_time_unref (dt);
2428
2429   dt = g_date_time_new_utc (2010, 3, 14, 3, 0, 0);
2430   u = g_date_time_to_unix (dt);
2431   g_date_time_unref (dt);
2432
2433   i1 = g_time_zone_adjust_time (tz, G_TIME_TYPE_DAYLIGHT, &u2);
2434   g_assert (u == u2);
2435
2436   g_time_zone_unref (tz);
2437 }
2438
2439 static void
2440 test_no_header (void)
2441 {
2442   GTimeZone *tz;
2443
2444   tz = g_time_zone_new ("blabla");
2445
2446   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
2447   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "UTC");
2448   g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 0);
2449   g_assert (!g_time_zone_is_dst (tz, 0));
2450
2451   g_time_zone_unref (tz);
2452 }
2453
2454 static void
2455 test_posix_parse (void)
2456 {
2457   GTimeZone *tz;
2458   GDateTime *gdt1, *gdt2;
2459
2460   /* Check that an unknown zone name falls back to UTC. */
2461   tz = g_time_zone_new ("nonexistent");
2462   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
2463   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "UTC");
2464   g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 0);
2465   g_assert (!g_time_zone_is_dst (tz, 0));
2466   g_time_zone_unref (tz);
2467
2468   /* An existent zone name should not fall back to UTC. */
2469   tz = g_time_zone_new ("PST8");
2470   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "PST8");
2471   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "PST");
2472   g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, - 8 * 3600);
2473   g_assert (!g_time_zone_is_dst (tz, 0));
2474   g_time_zone_unref (tz);
2475
2476 /* This fails rules_from_identifier on Unix (though not on Windows)
2477  * but passes anyway because PST8PDT is a zone name.
2478  */
2479   tz = g_time_zone_new ("PST8PDT");
2480   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "PST8PDT");
2481   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "PST");
2482   g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, - 8 * 3600);
2483   g_assert (!g_time_zone_is_dst (tz, 0));
2484   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "PDT");
2485   g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==,- 7 * 3600);
2486   g_assert (g_time_zone_is_dst (tz, 1));
2487   g_time_zone_unref (tz);
2488
2489   tz = g_time_zone_new ("PST8PDT6:32:15");
2490 #ifdef G_OS_WIN32
2491   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "PST8PDT6:32:15");
2492   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "PST");
2493   g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, - 8 * 3600);
2494   g_assert (!g_time_zone_is_dst (tz, 0));
2495   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "PDT");
2496   g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, - 6 * 3600 - 32 *60 - 15);
2497   g_assert (g_time_zone_is_dst (tz, 1));
2498   gdt1 = g_date_time_new (tz, 2012, 12, 6, 11, 15, 23.0);
2499   gdt2 = g_date_time_new (tz, 2012, 6, 6, 11, 15, 23.0);
2500   g_assert (!g_date_time_is_daylight_savings (gdt1));
2501   g_assert_cmpint (g_date_time_get_utc_offset (gdt1) /  1000000, ==, -28800);
2502   g_assert (g_date_time_is_daylight_savings (gdt2));
2503   g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, -23535);
2504   g_date_time_unref (gdt1);
2505   g_date_time_unref (gdt2);
2506 #else
2507   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
2508   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "UTC");
2509   g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 0);
2510   g_assert (!g_time_zone_is_dst (tz, 0));
2511 #endif
2512   g_time_zone_unref (tz);
2513
2514   tz = g_time_zone_new ("NZST-12:00:00NZDT-13:00:00,M10.1.0,M3.3.0");
2515   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "NZST-12:00:00NZDT-13:00:00,M10.1.0,M3.3.0");
2516   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "NZST");
2517   g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 12 * 3600);
2518   g_assert (!g_time_zone_is_dst (tz, 0));
2519   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "NZDT");
2520   g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, 13 * 3600);
2521   g_assert (g_time_zone_is_dst (tz, 1));
2522   gdt1 = g_date_time_new (tz, 2012, 3, 18, 0, 15, 23.0);
2523   gdt2 = g_date_time_new (tz, 2012, 3, 18, 3, 15, 23.0);
2524   g_assert (g_date_time_is_daylight_savings (gdt1));
2525   g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
2526   g_assert (!g_date_time_is_daylight_savings (gdt2));
2527   g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
2528   g_date_time_unref (gdt1);
2529   g_date_time_unref (gdt2);
2530   gdt1 = g_date_time_new (tz, 2012, 10, 7, 3, 15, 23.0);
2531   gdt2 = g_date_time_new (tz, 2012, 10, 7, 1, 15, 23.0);
2532   g_assert (g_date_time_is_daylight_savings (gdt1));
2533   g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
2534   g_assert (!g_date_time_is_daylight_savings (gdt2));
2535   g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
2536   g_date_time_unref (gdt1);
2537   g_date_time_unref (gdt2);
2538   g_time_zone_unref (tz);
2539
2540   tz = g_time_zone_new ("NZST-12:00:00NZDT-13:00:00,279,76");
2541   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "NZST-12:00:00NZDT-13:00:00,279,76");
2542   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "NZST");
2543   g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 12 * 3600);
2544   g_assert (!g_time_zone_is_dst (tz, 0));
2545   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "NZDT");
2546   g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, 13 * 3600);
2547   g_assert (g_time_zone_is_dst (tz, 1));
2548   gdt1 = g_date_time_new (tz, 2012, 3, 18, 0, 15, 23.0);
2549   gdt2 = g_date_time_new (tz, 2012, 3, 18, 3, 15, 23.0);
2550   g_assert (g_date_time_is_daylight_savings (gdt1));
2551   g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
2552   g_assert (!g_date_time_is_daylight_savings (gdt2));
2553   g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
2554   g_date_time_unref (gdt1);
2555   g_date_time_unref (gdt2);
2556   gdt1 = g_date_time_new (tz, 2012, 10, 7, 3, 15, 23.0);
2557   gdt2 = g_date_time_new (tz, 2012, 10, 7, 1, 15, 23.0);
2558   g_assert (g_date_time_is_daylight_savings (gdt1));
2559   g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
2560   g_assert (!g_date_time_is_daylight_savings (gdt2));
2561   g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
2562   g_date_time_unref (gdt1);
2563   g_date_time_unref (gdt2);
2564   g_time_zone_unref (tz);
2565
2566   tz = g_time_zone_new ("NZST-12:00:00NZDT-13:00:00,J279,J76");
2567   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "NZST-12:00:00NZDT-13:00:00,J279,J76");
2568   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "NZST");
2569   g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 12 * 3600);
2570   g_assert (!g_time_zone_is_dst (tz, 0));
2571   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "NZDT");
2572   g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, 13 * 3600);
2573   g_assert (g_time_zone_is_dst (tz, 1));
2574   gdt1 = g_date_time_new (tz, 2012, 3, 18, 0, 15, 23.0);
2575   gdt2 = g_date_time_new (tz, 2012, 3, 18, 3, 15, 23.0);
2576   g_assert (g_date_time_is_daylight_savings (gdt1));
2577   g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
2578   g_assert (!g_date_time_is_daylight_savings (gdt2));
2579   g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
2580   g_date_time_unref (gdt1);
2581   g_date_time_unref (gdt2);
2582   gdt1 = g_date_time_new (tz, 2012, 10, 7, 3, 15, 23.0);
2583   gdt2 = g_date_time_new (tz, 2012, 10, 7, 1, 15, 23.0);
2584   g_assert (g_date_time_is_daylight_savings (gdt1));
2585   g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
2586   g_assert (!g_date_time_is_daylight_savings (gdt2));
2587   g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
2588   g_date_time_unref (gdt1);
2589   g_date_time_unref (gdt2);
2590   g_time_zone_unref (tz);
2591
2592   tz = g_time_zone_new ("NZST-12:00:00NZDT-13:00:00,M10.1.0/07:00,M3.3.0/07:00");
2593   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "NZST-12:00:00NZDT-13:00:00,M10.1.0/07:00,M3.3.0/07:00");
2594   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "NZST");
2595   g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 12 * 3600);
2596   g_assert (!g_time_zone_is_dst (tz, 0));
2597   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "NZDT");
2598   g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, 13 * 3600);
2599   g_assert (g_time_zone_is_dst (tz, 1));
2600   gdt1 = g_date_time_new (tz, 2012, 3, 18, 5, 15, 23.0);
2601   gdt2 = g_date_time_new (tz, 2012, 3, 18, 8, 15, 23.0);
2602   g_assert (g_date_time_is_daylight_savings (gdt1));
2603   g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
2604   g_assert (!g_date_time_is_daylight_savings (gdt2));
2605   g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
2606   g_date_time_unref (gdt1);
2607   g_date_time_unref (gdt2);
2608   gdt1 = g_date_time_new (tz, 2012, 10, 7, 8, 15, 23.0);
2609   gdt2 = g_date_time_new (tz, 2012, 10, 7, 6, 15, 23.0);
2610   g_assert (g_date_time_is_daylight_savings (gdt1));
2611   g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
2612   g_assert (!g_date_time_is_daylight_savings (gdt2));
2613   g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
2614   g_date_time_unref (gdt1);
2615   g_date_time_unref (gdt2);
2616   gdt1 = g_date_time_new (tz, 1902, 10, 7, 8, 15, 23.0);
2617   gdt2 = g_date_time_new (tz, 1902, 10, 7, 6, 15, 23.0);
2618   g_assert (!g_date_time_is_daylight_savings (gdt1));
2619   g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 43200);
2620   g_assert (!g_date_time_is_daylight_savings (gdt2));
2621   g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
2622   g_date_time_unref (gdt1);
2623   g_date_time_unref (gdt2);
2624   gdt1 = g_date_time_new (tz, 2142, 10, 7, 8, 15, 23.0);
2625   gdt2 = g_date_time_new (tz, 2142, 10, 7, 6, 15, 23.0);
2626   g_assert (g_date_time_is_daylight_savings (gdt1));
2627   g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
2628   g_assert (!g_date_time_is_daylight_savings (gdt2));
2629   g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
2630   g_date_time_unref (gdt1);
2631   g_date_time_unref (gdt2);
2632   gdt1 = g_date_time_new (tz, 3212, 10, 7, 8, 15, 23.0);
2633   gdt2 = g_date_time_new (tz, 3212, 10, 7, 6, 15, 23.0);
2634   g_assert (!g_date_time_is_daylight_savings (gdt1));
2635   g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 43200);
2636   g_assert (!g_date_time_is_daylight_savings (gdt2));
2637   g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
2638   g_date_time_unref (gdt1);
2639   g_date_time_unref (gdt2);
2640   g_time_zone_unref (tz);
2641
2642   tz = g_time_zone_new ("VIR-00:30");
2643   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "VIR-00:30");
2644   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "VIR");
2645   g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, (30 * 60));
2646   g_assert_false (g_time_zone_is_dst (tz, 0));
2647
2648   tz = g_time_zone_new ("VIR-00:30VID,0/00:00:00,365/23:59:59");
2649   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "VIR-00:30VID,0/00:00:00,365/23:59:59");
2650   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "VIR");
2651   g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, (30 * 60));
2652   g_assert_false (g_time_zone_is_dst (tz, 0));
2653   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "VID");
2654   g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, (90 * 60));
2655   g_assert_true (g_time_zone_is_dst (tz, 1));
2656
2657   tz = g_time_zone_new ("VIR-02:30VID,0/00:00:00,365/23:59:59");
2658   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "VIR-02:30VID,0/00:00:00,365/23:59:59");
2659   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "VIR");
2660   g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, (150 * 60));
2661   g_assert_false (g_time_zone_is_dst (tz, 0));
2662   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "VID");
2663   g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, (210 * 60));
2664   g_assert_true (g_time_zone_is_dst (tz, 1));
2665
2666   tz = g_time_zone_new ("VIR-02:30VID-04:30,0/00:00:00,365/23:59:59");
2667   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "VIR-02:30VID-04:30,0/00:00:00,365/23:59:59");
2668   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "VIR");
2669   g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, (150 * 60));
2670   g_assert_false (g_time_zone_is_dst (tz, 0));
2671   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "VID");
2672   g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, (270 * 60));
2673   g_assert_true (g_time_zone_is_dst (tz, 1));
2674
2675   tz = g_time_zone_new ("VIR-12:00VID-13:00,0/00:00:00,365/23:59:59");
2676   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "VIR-12:00VID-13:00,0/00:00:00,365/23:59:59");
2677   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "VIR");
2678   g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, (720 * 60));
2679   g_assert_false (g_time_zone_is_dst (tz, 0));
2680   g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "VID");
2681   g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, (780 * 60));
2682   g_assert_true (g_time_zone_is_dst (tz, 1));
2683 }
2684
2685 static void
2686 test_GDateTime_floating_point (void)
2687 {
2688   GDateTime *dt;
2689   GTimeZone *tz;
2690
2691   g_test_bug ("http://bugzilla.gnome.org/697715");
2692
2693   tz = g_time_zone_new ("-03:00");
2694   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "-03:00");
2695   dt = g_date_time_new (tz, 2010, 5, 24,  8, 0, 1.000001);
2696   g_time_zone_unref (tz);
2697   g_assert_cmpint (g_date_time_get_microsecond (dt), ==, 1);
2698   g_date_time_unref (dt);
2699 }
2700
2701 /* Check that g_time_zone_get_identifier() returns the identifier given to
2702  * g_time_zone_new(), or "UTC" if loading the timezone failed. */
2703 static void
2704 test_identifier (void)
2705 {
2706   GTimeZone *tz;
2707   gchar *old_tz = g_strdup (g_getenv ("TZ"));
2708
2709 #ifdef G_OS_WIN32
2710   const char *recife_tz = "SA Eastern Standard Time";
2711 #else
2712   const char *recife_tz = "America/Recife";
2713 #endif
2714
2715   tz = g_time_zone_new ("UTC");
2716   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
2717   g_time_zone_unref (tz);
2718
2719   tz = g_time_zone_new_utc ();
2720   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
2721   g_time_zone_unref (tz);
2722
2723   tz = g_time_zone_new ("some rubbish");
2724   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
2725   g_time_zone_unref (tz);
2726
2727   tz = g_time_zone_new ("Z");
2728   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "Z");
2729   g_time_zone_unref (tz);
2730
2731   tz = g_time_zone_new ("+03:15");
2732   g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "+03:15");
2733   g_time_zone_unref (tz);
2734
2735   /* System timezone. We can’t change this, but we can at least assert that
2736    * the identifier is non-NULL and non-empty. */
2737   tz = g_time_zone_new (NULL);
2738   g_test_message ("System time zone identifier: %s", g_time_zone_get_identifier (tz));
2739   g_assert_nonnull (g_time_zone_get_identifier (tz));
2740   g_assert_cmpstr (g_time_zone_get_identifier (tz), !=, "");
2741   g_time_zone_unref (tz);
2742
2743   /* Local timezone tests. */
2744   if (g_setenv ("TZ", recife_tz, TRUE))
2745     {
2746       tz = g_time_zone_new_local ();
2747       g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, recife_tz);
2748       g_time_zone_unref (tz);
2749     }
2750
2751   if (g_setenv ("TZ", "some rubbish", TRUE))
2752     {
2753       tz = g_time_zone_new_local ();
2754       g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
2755       g_time_zone_unref (tz);
2756     }
2757
2758   if (old_tz != NULL)
2759     g_assert_true (g_setenv ("TZ", old_tz, TRUE));
2760   else
2761     g_unsetenv ("TZ");
2762
2763   g_free (old_tz);
2764 }
2765
2766 /* Test various calls to g_time_zone_new_offset(). */
2767 static void
2768 test_new_offset (void)
2769 {
2770   const gint32 vectors[] =
2771     {
2772       -10000,
2773       -3600,
2774       -61,
2775       -60,
2776       -59,
2777       0,
2778       59,
2779       60,
2780       61,
2781       3600,
2782       10000,
2783     };
2784   gsize i;
2785
2786   for (i = 0; i < G_N_ELEMENTS (vectors); i++)
2787     {
2788       GTimeZone *tz = NULL;
2789
2790       g_test_message ("Vector %" G_GSIZE_FORMAT ": %d", i, vectors[i]);
2791
2792       tz = g_time_zone_new_offset (vectors[i]);
2793       g_assert_nonnull (tz);
2794       g_assert_cmpstr (g_time_zone_get_identifier (tz), !=, "UTC");
2795       g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, vectors[i]);
2796       g_time_zone_unref (tz);
2797     }
2798 }
2799
2800 static void
2801 test_time_zone_parse_rfc8536 (void)
2802 {
2803   const gchar *test_files[] =
2804     {
2805       /* Generated with `zic -b slim`; see
2806        * https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1533#note_842235 */
2807       "Amsterdam-slim",
2808       /* Generated with `zic -b fat` */
2809       "Amsterdam-fat",
2810     };
2811   gsize i;
2812
2813   g_test_summary ("Test parsing time zone files in RFC 8536 version 3 format");
2814   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2129");
2815
2816   for (i = 0; i < G_N_ELEMENTS (test_files); i++)
2817     {
2818       gchar *path = NULL;
2819       GTimeZone *tz = NULL;
2820
2821       path = g_test_build_filename (G_TEST_DIST, "time-zones", test_files[i], NULL);
2822       g_assert_true (g_path_is_absolute (path));
2823       tz = g_time_zone_new (path);
2824       g_assert_nonnull (tz);
2825       /* UTC will be loaded as a fallback if parsing fails */
2826       g_assert_cmpstr (g_time_zone_get_identifier (tz), !=, "UTC");
2827       g_time_zone_unref (tz);
2828       g_free (path);
2829     }
2830 }
2831
2832 /* Check GTimeZone instances are cached. */
2833 static void
2834 test_time_zone_caching (void)
2835 {
2836   GTimeZone *tz1 = NULL, *tz2 = NULL;
2837
2838   g_test_summary ("GTimeZone instances are cached");
2839
2840   /* Check a specific (arbitrary) timezone. These are only cached while third
2841    * party code holds a ref to at least one instance. */
2842 #ifdef G_OS_UNIX
2843   tz1 = g_time_zone_new ("Europe/London");
2844   tz2 = g_time_zone_new ("Europe/London");
2845   g_time_zone_unref (tz1);
2846   g_time_zone_unref (tz2);
2847 #elif defined G_OS_WIN32
2848   tz1 = g_time_zone_new ("GMT Standard Time");
2849   tz2 = g_time_zone_new ("GMT Standard Time");
2850   g_time_zone_unref (tz1);
2851   g_time_zone_unref (tz2);
2852 #endif
2853
2854   /* Only compare pointers */
2855   g_assert_true (tz1 == tz2);
2856
2857   /* Check the default timezone, local and UTC. These are cached internally in
2858    * GLib, so should persist even after the last third party reference is
2859    * dropped. */
2860   tz1 = g_time_zone_new (NULL);
2861   g_time_zone_unref (tz1);
2862   tz2 = g_time_zone_new (NULL);
2863   g_time_zone_unref (tz2);
2864
2865   g_assert_true (tz1 == tz2);
2866
2867   tz1 = g_time_zone_new_utc ();
2868   g_time_zone_unref (tz1);
2869   tz2 = g_time_zone_new_utc ();
2870   g_time_zone_unref (tz2);
2871
2872   g_assert_true (tz1 == tz2);
2873
2874   tz1 = g_time_zone_new_local ();
2875   g_time_zone_unref (tz1);
2876   tz2 = g_time_zone_new_local ();
2877   g_time_zone_unref (tz2);
2878
2879   g_assert_true (tz1 == tz2);
2880 }
2881
2882
2883 gint
2884 main (gint   argc,
2885       gchar *argv[])
2886 {
2887   /* In glibc, LANGUAGE is used as highest priority guess for category value.
2888    * Unset it to avoid interference with tests using setlocale and translation. */
2889   g_unsetenv ("LANGUAGE");
2890
2891   g_test_init (&argc, &argv, NULL);
2892
2893   /* GDateTime Tests */
2894   bind_textdomain_codeset ("glib20", "UTF-8");
2895
2896   g_test_add_func ("/GDateTime/invalid", test_GDateTime_invalid);
2897   g_test_add_func ("/GDateTime/add_days", test_GDateTime_add_days);
2898   g_test_add_func ("/GDateTime/add_full", test_GDateTime_add_full);
2899   g_test_add_func ("/GDateTime/add_hours", test_GDateTime_add_hours);
2900   g_test_add_func ("/GDateTime/add_minutes", test_GDateTime_add_minutes);
2901   g_test_add_func ("/GDateTime/add_months", test_GDateTime_add_months);
2902   g_test_add_func ("/GDateTime/add_seconds", test_GDateTime_add_seconds);
2903   g_test_add_func ("/GDateTime/add_weeks", test_GDateTime_add_weeks);
2904   g_test_add_func ("/GDateTime/add_years", test_GDateTime_add_years);
2905   g_test_add_func ("/GDateTime/compare", test_GDateTime_compare);
2906   g_test_add_func ("/GDateTime/diff", test_GDateTime_diff);
2907   g_test_add_func ("/GDateTime/equal", test_GDateTime_equal);
2908   g_test_add_func ("/GDateTime/get_day_of_week", test_GDateTime_get_day_of_week);
2909   g_test_add_func ("/GDateTime/get_day_of_month", test_GDateTime_get_day_of_month);
2910   g_test_add_func ("/GDateTime/get_day_of_year", test_GDateTime_get_day_of_year);
2911   g_test_add_func ("/GDateTime/get_hour", test_GDateTime_get_hour);
2912   g_test_add_func ("/GDateTime/get_microsecond", test_GDateTime_get_microsecond);
2913   g_test_add_func ("/GDateTime/get_minute", test_GDateTime_get_minute);
2914   g_test_add_func ("/GDateTime/get_month", test_GDateTime_get_month);
2915   g_test_add_func ("/GDateTime/get_second", test_GDateTime_get_second);
2916   g_test_add_func ("/GDateTime/get_utc_offset", test_GDateTime_get_utc_offset);
2917   g_test_add_func ("/GDateTime/get_year", test_GDateTime_get_year);
2918   g_test_add_func ("/GDateTime/hash", test_GDateTime_hash);
2919   g_test_add_func ("/GDateTime/new_from_unix", test_GDateTime_new_from_unix);
2920   g_test_add_func ("/GDateTime/new_from_unix_utc", test_GDateTime_new_from_unix_utc);
2921   g_test_add_func ("/GDateTime/new_from_unix/overflow", test_GDateTime_new_from_unix_overflow);
2922   g_test_add_func ("/GDateTime/new_from_timeval", test_GDateTime_new_from_timeval);
2923   g_test_add_func ("/GDateTime/new_from_timeval_utc", test_GDateTime_new_from_timeval_utc);
2924   g_test_add_func ("/GDateTime/new_from_timeval/overflow", test_GDateTime_new_from_timeval_overflow);
2925   g_test_add_func ("/GDateTime/new_from_iso8601", test_GDateTime_new_from_iso8601);
2926   g_test_add_func ("/GDateTime/new_from_iso8601/2", test_GDateTime_new_from_iso8601_2);
2927   g_test_add_func ("/GDateTime/new_full", test_GDateTime_new_full);
2928   g_test_add_func ("/GDateTime/now", test_GDateTime_now);
2929   g_test_add_func ("/GDateTime/test-6-days-until-end-of-the-month", test_6_days_until_end_of_the_month);
2930   g_test_add_func ("/GDateTime/printf", test_GDateTime_printf);
2931   g_test_add_func ("/GDateTime/non_utf8_printf", test_non_utf8_printf);
2932   g_test_add_func ("/GDateTime/format_unrepresentable", test_format_unrepresentable);
2933   g_test_add_func ("/GDateTime/format_iso8601", test_format_iso8601);
2934   g_test_add_func ("/GDateTime/strftime", test_strftime);
2935   g_test_add_func ("/GDateTime/strftime/error_handling", test_GDateTime_strftime_error_handling);
2936   g_test_add_func ("/GDateTime/modifiers", test_modifiers);
2937   g_test_add_func ("/GDateTime/month_names", test_month_names);
2938   g_test_add_func ("/GDateTime/to_local", test_GDateTime_to_local);
2939   g_test_add_func ("/GDateTime/to_unix", test_GDateTime_to_unix);
2940   g_test_add_func ("/GDateTime/to_timeval", test_GDateTime_to_timeval);
2941   g_test_add_func ("/GDateTime/to_utc", test_GDateTime_to_utc);
2942   g_test_add_func ("/GDateTime/now_utc", test_GDateTime_now_utc);
2943   g_test_add_func ("/GDateTime/dst", test_GDateTime_dst);
2944   g_test_add_func ("/GDateTime/test_z", test_z);
2945   g_test_add_func ("/GDateTime/test-all-dates", test_all_dates);
2946   g_test_add_func ("/GTimeZone/find-interval", test_find_interval);
2947   g_test_add_func ("/GTimeZone/adjust-time", test_adjust_time);
2948   g_test_add_func ("/GTimeZone/no-header", test_no_header);
2949   g_test_add_func ("/GTimeZone/posix-parse", test_posix_parse);
2950   g_test_add_func ("/GTimeZone/floating-point", test_GDateTime_floating_point);
2951   g_test_add_func ("/GTimeZone/identifier", test_identifier);
2952   g_test_add_func ("/GTimeZone/new-offset", test_new_offset);
2953   g_test_add_func ("/GTimeZone/parse-rfc8536", test_time_zone_parse_rfc8536);
2954   g_test_add_func ("/GTimeZone/caching", test_time_zone_caching);
2955
2956   return g_test_run ();
2957 }