3 * Copyright (C) 2009-2010 Christian Hergert <chris@dronelabs.com>
4 * Copyright 2023 GNOME Foundation Inc.
6 * SPDX-License-Identifier: LGPL-2.1-or-later
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, see <http://www.gnu.org/licenses/>.
22 * - Christian Hergert <chris@dronelabs.com>
23 * - Philip Withnall <pwithnall@gnome.org>
33 #include <glib/gstdio.h>
36 #include "gdatetime-private.h"
39 #define WIN32_LEAN_AND_MEAN
43 #define NAN HUGE_VAL * 0.0f
47 #define ASSERT_DATE(dt,y,m,d) G_STMT_START { \
48 g_assert_nonnull ((dt)); \
49 g_assert_cmpint ((y), ==, g_date_time_get_year ((dt))); \
50 g_assert_cmpint ((m), ==, g_date_time_get_month ((dt))); \
51 g_assert_cmpint ((d), ==, g_date_time_get_day_of_month ((dt))); \
53 #define ASSERT_TIME(dt,H,M,S,U) G_STMT_START { \
54 g_assert_nonnull ((dt)); \
55 g_assert_cmpint ((H), ==, g_date_time_get_hour ((dt))); \
56 g_assert_cmpint ((M), ==, g_date_time_get_minute ((dt))); \
57 g_assert_cmpint ((S), ==, g_date_time_get_second ((dt))); \
58 g_assert_cmpint ((U), ==, g_date_time_get_microsecond ((dt))); \
62 skip_if_running_uninstalled (void)
64 /* If running uninstalled (G_TEST_BUILDDIR is set), skip this test, since we
65 * need the translations to be installed. We can’t mess around with
66 * bindtextdomain() here, as the compiled .gmo files in po/ are not in the
67 * right installed directory hierarchy to be successfully loaded by gettext. */
68 if (g_getenv ("G_TEST_BUILDDIR") != NULL)
70 g_test_skip ("Skipping due to running uninstalled. "
71 "This test can only be run when the translations are installed.");
79 get_localtime_tm (time_t time_,
82 #ifdef HAVE_LOCALTIME_R
83 localtime_r (&time_, retval);
86 struct tm *ptm = localtime (&time_);
90 /* Happens at least in Microsoft's C library if you pass a
91 * negative time_t. Use 2000-01-01 as default date.
93 #ifndef G_DISABLE_CHECKS
94 g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, "ptm != NULL");
99 retval->tm_year = 100;
102 memcpy ((void *) retval, (void *) ptm, sizeof (struct tm));
104 #endif /* HAVE_LOCALTIME_R */
108 test_GDateTime_now (void)
115 /* before <= dt.to_unix() <= after, but the inequalities might not be
116 * equality if we're close to the boundary between seconds.
117 * We loop until before == after (and hence dt.to_unix() should equal both)
118 * to guard against that. */
121 before = g_get_real_time () / G_TIME_SPAN_SECOND;
123 memset (&tm, 0, sizeof (tm));
124 get_localtime_tm (before, &tm);
126 dt = g_date_time_new_now_local ();
128 after = g_get_real_time () / G_TIME_SPAN_SECOND;
130 while (before != after);
132 g_assert_cmpint (g_date_time_get_year (dt), ==, 1900 + tm.tm_year);
133 g_assert_cmpint (g_date_time_get_month (dt), ==, 1 + tm.tm_mon);
134 g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, tm.tm_mday);
135 g_assert_cmpint (g_date_time_get_hour (dt), ==, tm.tm_hour);
136 g_assert_cmpint (g_date_time_get_minute (dt), ==, tm.tm_min);
137 g_assert_cmpint (g_date_time_get_second (dt), ==, tm.tm_sec);
139 g_date_time_unref (dt);
143 test_GDateTime_new_from_unix (void)
149 memset (&tm, 0, sizeof (tm));
151 g_assert_cmpint (t, !=, (time_t) -1);
152 get_localtime_tm (t, &tm);
154 dt = g_date_time_new_from_unix_local (t);
155 g_assert_cmpint (g_date_time_get_year (dt), ==, 1900 + tm.tm_year);
156 g_assert_cmpint (g_date_time_get_month (dt), ==, 1 + tm.tm_mon);
157 g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, tm.tm_mday);
158 g_assert_cmpint (g_date_time_get_hour (dt), ==, tm.tm_hour);
159 g_assert_cmpint (g_date_time_get_minute (dt), ==, tm.tm_min);
160 g_assert_cmpint (g_date_time_get_second (dt), ==, tm.tm_sec);
161 g_date_time_unref (dt);
163 /* Choose 1990-01-01 04:00:00 because no DST leaps happened then. The more
164 * obvious 1990-01-01 00:00:00 was a DST leap in America/Lima (which has,
165 * confusingly, since stopped using DST). */
166 memset (&tm, 0, sizeof (tm));
176 dt = g_date_time_new_from_unix_local (t);
177 g_assert_cmpint (g_date_time_get_year (dt), ==, 1990);
178 g_assert_cmpint (g_date_time_get_month (dt), ==, 1);
179 g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, 1);
180 g_assert_cmpint (g_date_time_get_hour (dt), ==, 4);
181 g_assert_cmpint (g_date_time_get_minute (dt), ==, 0);
182 g_assert_cmpint (g_date_time_get_second (dt), ==, 0);
183 g_date_time_unref (dt);
186 /* Check that trying to create a #GDateTime too far in the future (or past) reliably
187 * fails. Previously, the checks for this overflowed and it silently returned
188 * an incorrect #GDateTime. */
190 test_GDateTime_new_from_unix_overflow (void)
194 g_test_bug ("http://bugzilla.gnome.org/782089");
196 dt = g_date_time_new_from_unix_utc (G_MAXINT64);
199 dt = g_date_time_new_from_unix_local (G_MAXINT64);
202 dt = g_date_time_new_from_unix_utc (G_MININT64);
205 dt = g_date_time_new_from_unix_local (G_MININT64);
210 test_GDateTime_invalid (void)
214 g_test_bug ("http://bugzilla.gnome.org/702674");
216 dt = g_date_time_new_utc (2013, -2147483647, 31, 17, 15, 48);
217 g_assert (dt == NULL);
221 test_GDateTime_compare (void)
223 GDateTime *dt1, *dt2;
226 dt1 = g_date_time_new_utc (2000, 1, 1, 0, 0, 0);
228 for (i = 1; i < 2000; i++)
230 dt2 = g_date_time_new_utc (i, 12, 31, 0, 0, 0);
231 g_assert_cmpint (1, ==, g_date_time_compare (dt1, dt2));
232 g_date_time_unref (dt2);
235 dt2 = g_date_time_new_utc (1999, 12, 31, 23, 59, 59);
236 g_assert_cmpint (1, ==, g_date_time_compare (dt1, dt2));
237 g_date_time_unref (dt2);
239 dt2 = g_date_time_new_utc (2000, 1, 1, 0, 0, 1);
240 g_assert_cmpint (-1, ==, g_date_time_compare (dt1, dt2));
241 g_date_time_unref (dt2);
243 dt2 = g_date_time_new_utc (2000, 1, 1, 0, 0, 0);
244 g_assert_cmpint (0, ==, g_date_time_compare (dt1, dt2));
245 g_date_time_unref (dt2);
246 g_date_time_unref (dt1);
250 test_GDateTime_equal (void)
252 GDateTime *dt1, *dt2;
255 dt1 = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
256 dt2 = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
257 g_assert (g_date_time_equal (dt1, dt2));
258 g_date_time_unref (dt1);
259 g_date_time_unref (dt2);
261 dt1 = g_date_time_new_local (2009, 10, 18, 0, 0, 0);
262 dt2 = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
263 g_assert (!g_date_time_equal (dt1, dt2));
264 g_date_time_unref (dt1);
265 g_date_time_unref (dt2);
267 /* UTC-0300 and not in DST */
268 tz = g_time_zone_new_identifier ("-03:00");
269 g_assert_nonnull (tz);
270 dt1 = g_date_time_new (tz, 2010, 5, 24, 8, 0, 0);
271 g_time_zone_unref (tz);
272 g_assert_cmpint (g_date_time_get_utc_offset (dt1) / G_USEC_PER_SEC, ==, (-3 * 3600));
274 dt2 = g_date_time_new_utc (2010, 5, 24, 11, 0, 0);
275 g_assert_cmpint (g_date_time_get_utc_offset (dt2), ==, 0);
277 g_assert (g_date_time_equal (dt1, dt2));
278 g_date_time_unref (dt1);
280 /* America/Recife is in UTC-0300 */
282 tz = g_time_zone_new_identifier ("America/Recife");
283 #elif defined G_OS_WIN32
284 tz = g_time_zone_new_identifier ("E. South America Standard Time");
286 g_assert_nonnull (tz);
287 dt1 = g_date_time_new (tz, 2010, 5, 24, 8, 0, 0);
288 g_time_zone_unref (tz);
289 g_assert_cmpint (g_date_time_get_utc_offset (dt1) / G_USEC_PER_SEC, ==, (-3 * 3600));
290 g_assert (g_date_time_equal (dt1, dt2));
291 g_date_time_unref (dt1);
292 g_date_time_unref (dt2);
296 test_GDateTime_get_day_of_week (void)
300 dt = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
301 g_assert_cmpint (1, ==, g_date_time_get_day_of_week (dt));
302 g_date_time_unref (dt);
304 dt = g_date_time_new_local (2000, 10, 1, 0, 0, 0);
305 g_assert_cmpint (7, ==, g_date_time_get_day_of_week (dt));
306 g_date_time_unref (dt);
310 test_GDateTime_get_day_of_month (void)
314 dt = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
315 g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, 19);
316 g_date_time_unref (dt);
318 dt = g_date_time_new_local (1400, 3, 12, 0, 0, 0);
319 g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, 12);
320 g_date_time_unref (dt);
322 dt = g_date_time_new_local (1800, 12, 31, 0, 0, 0);
323 g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, 31);
324 g_date_time_unref (dt);
326 dt = g_date_time_new_local (1000, 1, 1, 0, 0, 0);
327 g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, 1);
328 g_date_time_unref (dt);
332 test_GDateTime_get_hour (void)
336 dt = g_date_time_new_utc (2009, 10, 19, 15, 13, 11);
337 g_assert_cmpint (15, ==, g_date_time_get_hour (dt));
338 g_date_time_unref (dt);
340 dt = g_date_time_new_utc (100, 10, 19, 1, 0, 0);
341 g_assert_cmpint (1, ==, g_date_time_get_hour (dt));
342 g_date_time_unref (dt);
344 dt = g_date_time_new_utc (100, 10, 19, 0, 0, 0);
345 g_assert_cmpint (0, ==, g_date_time_get_hour (dt));
346 g_date_time_unref (dt);
348 dt = g_date_time_new_utc (100, 10, 1, 23, 59, 59);
349 g_assert_cmpint (23, ==, g_date_time_get_hour (dt));
350 g_date_time_unref (dt);
353 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
355 test_GDateTime_get_microsecond (void)
360 g_get_current_time (&tv);
361 dt = g_date_time_new_from_timeval_local (&tv);
362 g_assert_cmpint (tv.tv_usec, ==, g_date_time_get_microsecond (dt));
363 g_date_time_unref (dt);
365 G_GNUC_END_IGNORE_DEPRECATIONS
368 test_GDateTime_get_year (void)
372 dt = g_date_time_new_local (2009, 1, 1, 0, 0, 0);
373 g_assert_cmpint (2009, ==, g_date_time_get_year (dt));
374 g_date_time_unref (dt);
376 dt = g_date_time_new_local (1, 1, 1, 0, 0, 0);
377 g_assert_cmpint (1, ==, g_date_time_get_year (dt));
378 g_date_time_unref (dt);
380 dt = g_date_time_new_local (13, 1, 1, 0, 0, 0);
381 g_assert_cmpint (13, ==, g_date_time_get_year (dt));
382 g_date_time_unref (dt);
384 dt = g_date_time_new_local (3000, 1, 1, 0, 0, 0);
385 g_assert_cmpint (3000, ==, g_date_time_get_year (dt));
386 g_date_time_unref (dt);
390 test_GDateTime_hash (void)
394 h = g_hash_table_new_full (g_date_time_hash, g_date_time_equal,
395 (GDestroyNotify)g_date_time_unref,
397 g_hash_table_add (h, g_date_time_new_now_local ());
398 g_hash_table_remove_all (h);
399 g_hash_table_destroy (h);
402 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
404 test_GDateTime_new_from_timeval (void)
409 g_get_current_time (&tv);
410 dt = g_date_time_new_from_timeval_local (&tv);
412 if (g_test_verbose ())
413 g_test_message ("DT%04d-%02d-%02dT%02d:%02d:%02d%s",
414 g_date_time_get_year (dt),
415 g_date_time_get_month (dt),
416 g_date_time_get_day_of_month (dt),
417 g_date_time_get_hour (dt),
418 g_date_time_get_minute (dt),
419 g_date_time_get_second (dt),
420 g_date_time_get_timezone_abbreviation (dt));
422 g_date_time_to_timeval (dt, &tv2);
423 g_assert_cmpint (tv.tv_sec, ==, tv2.tv_sec);
424 g_assert_cmpint (tv.tv_usec, ==, tv2.tv_usec);
425 g_date_time_unref (dt);
429 find_maximum_supported_tv_sec (void)
431 glong highest_success = 0, lowest_failure = G_MAXLONG;
433 GDateTime *dt = NULL;
437 /* Corner case of all glong values being valid. */
438 tv.tv_sec = G_MAXLONG;
439 dt = g_date_time_new_from_timeval_utc (&tv);
442 highest_success = tv.tv_sec;
443 g_date_time_unref (dt);
446 while (highest_success < lowest_failure - 1)
448 tv.tv_sec = highest_success + (lowest_failure - highest_success) / 2;
449 dt = g_date_time_new_from_timeval_utc (&tv);
453 highest_success = tv.tv_sec;
454 g_date_time_unref (dt);
458 lowest_failure = tv.tv_sec;
462 return highest_success;
465 /* Check that trying to create a #GDateTime too far in the future reliably
466 * fails. With a #GTimeVal, this is subtle, as the tv_usec are added into the
467 * calculation part-way through.
469 * This varies a bit between 32- and 64-bit architectures, due to the
470 * differences in the size of glong (tv.tv_sec). */
472 test_GDateTime_new_from_timeval_overflow (void)
477 g_test_bug ("http://bugzilla.gnome.org/782089");
479 tv.tv_sec = find_maximum_supported_tv_sec ();
480 tv.tv_usec = G_USEC_PER_SEC - 1;
482 g_test_message ("Maximum supported GTimeVal.tv_sec = %lu", tv.tv_sec);
484 /* Sanity check: do we support the year 2000? */
485 g_assert_cmpint (tv.tv_sec, >=, 946684800);
487 dt = g_date_time_new_from_timeval_utc (&tv);
488 g_assert_nonnull (dt);
489 g_date_time_unref (dt);
491 if (tv.tv_sec < G_MAXLONG)
496 dt = g_date_time_new_from_timeval_utc (&tv);
502 test_GDateTime_new_from_timeval_utc (void)
507 g_get_current_time (&tv);
508 dt = g_date_time_new_from_timeval_utc (&tv);
510 if (g_test_verbose ())
511 g_test_message ("DT%04d-%02d-%02dT%02d:%02d:%02d%s",
512 g_date_time_get_year (dt),
513 g_date_time_get_month (dt),
514 g_date_time_get_day_of_month (dt),
515 g_date_time_get_hour (dt),
516 g_date_time_get_minute (dt),
517 g_date_time_get_second (dt),
518 g_date_time_get_timezone_abbreviation (dt));
520 g_date_time_to_timeval (dt, &tv2);
521 g_assert_cmpint (tv.tv_sec, ==, tv2.tv_sec);
522 g_assert_cmpint (tv.tv_usec, ==, tv2.tv_usec);
523 g_date_time_unref (dt);
525 G_GNUC_END_IGNORE_DEPRECATIONS
528 test_GDateTime_new_from_iso8601 (void)
533 /* Need non-empty string */
534 dt = g_date_time_new_from_iso8601 ("", NULL);
537 /* Needs to be correctly formatted */
538 dt = g_date_time_new_from_iso8601 ("not a date", NULL);
541 dt = g_date_time_new_from_iso8601 (" +55", NULL);
544 /* Check common case */
545 dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42Z", NULL);
546 ASSERT_DATE (dt, 2016, 8, 24);
547 ASSERT_TIME (dt, 22, 10, 42, 0);
548 g_date_time_unref (dt);
550 /* Timezone is required in text or passed as arg */
551 tz = g_time_zone_new_utc ();
552 dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42", tz);
553 ASSERT_DATE (dt, 2016, 8, 24);
554 g_date_time_unref (dt);
555 g_time_zone_unref (tz);
556 dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42", NULL);
559 /* Can't have whitespace */
560 dt = g_date_time_new_from_iso8601 ("2016 08 24T22:10:42Z", NULL);
562 dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42Z ", NULL);
564 dt = g_date_time_new_from_iso8601 (" 2016-08-24T22:10:42Z", NULL);
567 /* Check lowercase time separator or space allowed */
568 dt = g_date_time_new_from_iso8601 ("2016-08-24t22:10:42Z", NULL);
569 ASSERT_DATE (dt, 2016, 8, 24);
570 ASSERT_TIME (dt, 22, 10, 42, 0);
571 g_date_time_unref (dt);
572 dt = g_date_time_new_from_iso8601 ("2016-08-24 22:10:42Z", NULL);
573 ASSERT_DATE (dt, 2016, 8, 24);
574 ASSERT_TIME (dt, 22, 10, 42, 0);
575 g_date_time_unref (dt);
577 /* Check dates without separators allowed */
578 dt = g_date_time_new_from_iso8601 ("20160824T22:10:42Z", NULL);
579 ASSERT_DATE (dt, 2016, 8, 24);
580 ASSERT_TIME (dt, 22, 10, 42, 0);
581 g_date_time_unref (dt);
583 /* Months are two digits */
584 dt = g_date_time_new_from_iso8601 ("2016-1-01T22:10:42Z", NULL);
587 /* Days are two digits */
588 dt = g_date_time_new_from_iso8601 ("2016-01-1T22:10:42Z", NULL);
591 /* Need consistent usage of separators */
592 dt = g_date_time_new_from_iso8601 ("2016-0824T22:10:42Z", NULL);
594 dt = g_date_time_new_from_iso8601 ("201608-24T22:10:42Z", NULL);
597 /* Check month within valid range */
598 dt = g_date_time_new_from_iso8601 ("2016-00-13T22:10:42Z", NULL);
600 dt = g_date_time_new_from_iso8601 ("2016-13-13T22:10:42Z", NULL);
603 /* Check day within valid range */
604 dt = g_date_time_new_from_iso8601 ("2016-01-00T22:10:42Z", NULL);
606 dt = g_date_time_new_from_iso8601 ("2016-01-31T22:10:42Z", NULL);
607 ASSERT_DATE (dt, 2016, 1, 31);
608 g_date_time_unref (dt);
609 dt = g_date_time_new_from_iso8601 ("2016-01-32T22:10:42Z", NULL);
611 dt = g_date_time_new_from_iso8601 ("2016-02-29T22:10:42Z", NULL);
612 ASSERT_DATE (dt, 2016, 2, 29);
613 g_date_time_unref (dt);
614 dt = g_date_time_new_from_iso8601 ("2016-02-30T22:10:42Z", NULL);
616 dt = g_date_time_new_from_iso8601 ("2017-02-28T22:10:42Z", NULL);
617 ASSERT_DATE (dt, 2017, 2, 28);
618 g_date_time_unref (dt);
619 dt = g_date_time_new_from_iso8601 ("2017-02-29T22:10:42Z", NULL);
621 dt = g_date_time_new_from_iso8601 ("2016-03-31T22:10:42Z", NULL);
622 ASSERT_DATE (dt, 2016, 3, 31);
623 g_date_time_unref (dt);
624 dt = g_date_time_new_from_iso8601 ("2016-03-32T22:10:42Z", NULL);
626 dt = g_date_time_new_from_iso8601 ("2016-04-30T22:10:42Z", NULL);
627 ASSERT_DATE (dt, 2016, 4, 30);
628 g_date_time_unref (dt);
629 dt = g_date_time_new_from_iso8601 ("2016-04-31T22:10:42Z", NULL);
631 dt = g_date_time_new_from_iso8601 ("2016-05-31T22:10:42Z", NULL);
632 ASSERT_DATE (dt, 2016, 5, 31);
633 g_date_time_unref (dt);
634 dt = g_date_time_new_from_iso8601 ("2016-05-32T22:10:42Z", NULL);
636 dt = g_date_time_new_from_iso8601 ("2016-06-30T22:10:42Z", NULL);
637 ASSERT_DATE (dt, 2016, 6, 30);
638 g_date_time_unref (dt);
639 dt = g_date_time_new_from_iso8601 ("2016-06-31T22:10:42Z", NULL);
641 dt = g_date_time_new_from_iso8601 ("2016-07-31T22:10:42Z", NULL);
642 ASSERT_DATE (dt, 2016, 7, 31);
643 g_date_time_unref (dt);
644 dt = g_date_time_new_from_iso8601 ("2016-07-32T22:10:42Z", NULL);
646 dt = g_date_time_new_from_iso8601 ("2016-08-31T22:10:42Z", NULL);
647 ASSERT_DATE (dt, 2016, 8, 31);
648 g_date_time_unref (dt);
649 dt = g_date_time_new_from_iso8601 ("2016-08-32T22:10:42Z", NULL);
651 dt = g_date_time_new_from_iso8601 ("2016-09-30T22:10:42Z", NULL);
652 ASSERT_DATE (dt, 2016, 9, 30);
653 g_date_time_unref (dt);
654 dt = g_date_time_new_from_iso8601 ("2016-09-31T22:10:42Z", NULL);
656 dt = g_date_time_new_from_iso8601 ("2016-10-31T22:10:42Z", NULL);
657 ASSERT_DATE (dt, 2016, 10, 31);
658 g_date_time_unref (dt);
659 dt = g_date_time_new_from_iso8601 ("2016-10-32T22:10:42Z", NULL);
661 dt = g_date_time_new_from_iso8601 ("2016-11-30T22:10:42Z", NULL);
662 ASSERT_DATE (dt, 2016, 11, 30);
663 g_date_time_unref (dt);
664 dt = g_date_time_new_from_iso8601 ("2016-11-31T22:10:42Z", NULL);
666 dt = g_date_time_new_from_iso8601 ("2016-12-31T22:10:42Z", NULL);
667 ASSERT_DATE (dt, 2016, 12, 31);
668 g_date_time_unref (dt);
669 dt = g_date_time_new_from_iso8601 ("2016-12-32T22:10:42Z", NULL);
672 /* Check ordinal days work */
673 dt = g_date_time_new_from_iso8601 ("2016-237T22:10:42Z", NULL);
674 ASSERT_DATE (dt, 2016, 8, 24);
675 ASSERT_TIME (dt, 22, 10, 42, 0);
676 g_date_time_unref (dt);
677 dt = g_date_time_new_from_iso8601 ("2016237T22:10:42Z", NULL);
678 ASSERT_DATE (dt, 2016, 8, 24);
679 ASSERT_TIME (dt, 22, 10, 42, 0);
680 g_date_time_unref (dt);
682 /* Check ordinal leap days */
683 dt = g_date_time_new_from_iso8601 ("2016-366T22:10:42Z", NULL);
684 ASSERT_DATE (dt, 2016, 12, 31);
685 ASSERT_TIME (dt, 22, 10, 42, 0);
686 g_date_time_unref (dt);
687 dt = g_date_time_new_from_iso8601 ("2017-365T22:10:42Z", NULL);
688 ASSERT_DATE (dt, 2017, 12, 31);
689 ASSERT_TIME (dt, 22, 10, 42, 0);
690 g_date_time_unref (dt);
691 dt = g_date_time_new_from_iso8601 ("2017-366T22:10:42Z", NULL);
694 /* Days start at 1 */
695 dt = g_date_time_new_from_iso8601 ("2016-000T22:10:42Z", NULL);
698 /* Limited to number of days in the year (2016 is a leap year) */
699 dt = g_date_time_new_from_iso8601 ("2016-367T22:10:42Z", NULL);
702 /* Days are two digits */
703 dt = g_date_time_new_from_iso8601 ("2016-1T22:10:42Z", NULL);
705 dt = g_date_time_new_from_iso8601 ("2016-12T22:10:42Z", NULL);
708 /* Check week days work */
709 dt = g_date_time_new_from_iso8601 ("2016-W34-3T22:10:42Z", NULL);
710 ASSERT_DATE (dt, 2016, 8, 24);
711 ASSERT_TIME (dt, 22, 10, 42, 0);
712 g_date_time_unref (dt);
713 dt = g_date_time_new_from_iso8601 ("2016W343T22:10:42Z", NULL);
714 ASSERT_DATE (dt, 2016, 8, 24);
715 ASSERT_TIME (dt, 22, 10, 42, 0);
716 g_date_time_unref (dt);
718 /* We don't support weeks without weekdays (valid ISO 8601) */
719 dt = g_date_time_new_from_iso8601 ("2016-W34T22:10:42Z", NULL);
721 dt = g_date_time_new_from_iso8601 ("2016W34T22:10:42Z", NULL);
724 /* Weeks are two digits */
725 dt = g_date_time_new_from_iso8601 ("2016-W3-1T22:10:42Z", NULL);
728 /* Weeks start at 1 */
729 dt = g_date_time_new_from_iso8601 ("2016-W00-1T22:10:42Z", NULL);
732 /* Week one might be in the previous year */
733 dt = g_date_time_new_from_iso8601 ("2015-W01-1T22:10:42Z", NULL);
734 ASSERT_DATE (dt, 2014, 12, 29);
735 g_date_time_unref (dt);
737 /* Last week might be in next year */
738 dt = g_date_time_new_from_iso8601 ("2015-W53-7T22:10:42Z", NULL);
739 ASSERT_DATE (dt, 2016, 1, 3);
740 g_date_time_unref (dt);
742 /* Week 53 doesn't always exist */
743 dt = g_date_time_new_from_iso8601 ("2016-W53-1T22:10:42Z", NULL);
746 /* Limited to number of days in the week */
747 dt = g_date_time_new_from_iso8601 ("2016-W34-0T22:10:42Z", NULL);
749 dt = g_date_time_new_from_iso8601 ("2016-W34-8T22:10:42Z", NULL);
752 /* Days are one digit */
753 dt = g_date_time_new_from_iso8601 ("2016-W34-99T22:10:42Z", NULL);
756 /* Check week day changes depending on year */
757 dt = g_date_time_new_from_iso8601 ("2017-W34-1T22:10:42Z", NULL);
758 ASSERT_DATE (dt, 2017, 8, 21);
759 g_date_time_unref (dt);
761 /* Check week day changes depending on leap years */
762 dt = g_date_time_new_from_iso8601 ("1900-W01-1T22:10:42Z", NULL);
763 ASSERT_DATE (dt, 1900, 1, 1);
764 g_date_time_unref (dt);
766 /* YYYY-MM not allowed (NOT valid ISO 8601) */
767 dt = g_date_time_new_from_iso8601 ("2016-08T22:10:42Z", NULL);
770 /* We don't support omitted year (valid ISO 8601) */
771 dt = g_date_time_new_from_iso8601 ("--08-24T22:10:42Z", NULL);
773 dt = g_date_time_new_from_iso8601 ("--0824T22:10:42Z", NULL);
776 /* Seconds must be two digits. */
777 dt = g_date_time_new_from_iso8601 ("2016-08-10T22:10:4Z", NULL);
780 /* Seconds must all be digits. */
781 dt = g_date_time_new_from_iso8601 ("2016-08-10T22:10:4aZ", NULL);
784 /* Check subseconds work */
785 dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42.123456Z", NULL);
786 ASSERT_DATE (dt, 2016, 8, 24);
787 ASSERT_TIME (dt, 22, 10, 42, 123456);
788 g_date_time_unref (dt);
789 dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42,123456Z", NULL);
790 ASSERT_DATE (dt, 2016, 8, 24);
791 ASSERT_TIME (dt, 22, 10, 42, 123456);
792 g_date_time_unref (dt);
793 dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42.Z", NULL);
795 dt = g_date_time_new_from_iso8601 ("2016-08-24T221042.123456Z", NULL);
796 ASSERT_DATE (dt, 2016, 8, 24);
797 ASSERT_TIME (dt, 22, 10, 42, 123456);
798 g_date_time_unref (dt);
800 /* Subseconds must all be digits. */
801 dt = g_date_time_new_from_iso8601 ("2016-08-10T22:10:42.5aZ", NULL);
804 /* Subseconds can be an arbitrary length, but must not overflow.
805 * The ASSERT_TIME() comparisons are constrained by only comparing up to
806 * microsecond granularity. */
807 dt = g_date_time_new_from_iso8601 ("2016-08-10T22:10:09.222222222222222222Z", NULL);
808 ASSERT_DATE (dt, 2016, 8, 10);
809 ASSERT_TIME (dt, 22, 10, 9, 222222);
810 g_date_time_unref (dt);
811 dt = g_date_time_new_from_iso8601 ("2016-08-10T22:10:09.2222222222222222222Z", NULL);
814 /* Small numerator, large divisor when parsing the subseconds. */
815 dt = g_date_time_new_from_iso8601 ("2016-08-10T22:10:00.0000000000000000001Z", NULL);
816 ASSERT_DATE (dt, 2016, 8, 10);
817 ASSERT_TIME (dt, 22, 10, 0, 0);
818 g_date_time_unref (dt);
819 dt = g_date_time_new_from_iso8601 ("2016-08-10T22:10:00.00000000000000000001Z", NULL);
822 /* We don't support times without minutes / seconds (valid ISO 8601) */
823 dt = g_date_time_new_from_iso8601 ("2016-08-24T22Z", NULL);
825 dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10Z", NULL);
827 dt = g_date_time_new_from_iso8601 ("2016-08-24T2210Z", NULL);
830 /* UTC time uses 'Z' */
831 dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42Z", NULL);
832 ASSERT_DATE (dt, 2016, 8, 24);
833 ASSERT_TIME (dt, 22, 10, 42, 0);
834 g_assert_cmpint (g_date_time_get_utc_offset (dt), ==, 0);
835 g_date_time_unref (dt);
837 /* Check timezone works */
838 dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42+12:00", NULL);
839 ASSERT_DATE (dt, 2016, 8, 24);
840 ASSERT_TIME (dt, 22, 10, 42, 0);
841 g_assert_cmpint (g_date_time_get_utc_offset (dt), ==, 12 * G_TIME_SPAN_HOUR);
842 g_date_time_unref (dt);
843 dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42+12", NULL);
844 ASSERT_DATE (dt, 2016, 8, 24);
845 ASSERT_TIME (dt, 22, 10, 42, 0);
846 g_assert_cmpint (g_date_time_get_utc_offset (dt), ==, 12 * G_TIME_SPAN_HOUR);
847 g_date_time_unref (dt);
848 dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42-02", NULL);
849 ASSERT_DATE (dt, 2016, 8, 24);
850 ASSERT_TIME (dt, 22, 10, 42, 0);
851 g_assert_cmpint (g_date_time_get_utc_offset (dt), ==, -2 * G_TIME_SPAN_HOUR);
852 g_date_time_unref (dt);
854 /* Timezone seconds not allowed */
855 dt = g_date_time_new_from_iso8601 ("2016-08-24T22-12:00:00", NULL);
857 dt = g_date_time_new_from_iso8601 ("2016-08-24T22-12:00:00.000", NULL);
860 /* Timezone hours two digits */
861 dt = g_date_time_new_from_iso8601 ("2016-08-24T22-2Z", NULL);
864 /* Ordinal date (YYYYDDD), space separator, and then time as HHMMSS,SSS
865 * The interesting bit is that the seconds field is so long as to parse as
867 dt = g_date_time_new_from_iso8601 ("0005306 000001,666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666600080000-00", NULL);
875 /* Expected result: */
883 GTimeSpan utc_offset;
887 test_GDateTime_new_from_iso8601_2 (void)
889 const Iso8601ParseTest tests[] = {
890 { TRUE, "1990-11-01T10:21:17Z", 1990, 11, 1, 10, 21, 17, 0, 0 },
891 { TRUE, "19901101T102117Z", 1990, 11, 1, 10, 21, 17, 0, 0 },
892 { TRUE, "1970-01-01T00:00:17.12Z", 1970, 1, 1, 0, 0, 17, 120000, 0 },
893 { TRUE, "1970-01-01T00:00:17.1234Z", 1970, 1, 1, 0, 0, 17, 123400, 0 },
894 { TRUE, "1970-01-01T00:00:17.123456Z", 1970, 1, 1, 0, 0, 17, 123456, 0 },
895 { TRUE, "1980-02-22T12:36:00+02:00", 1980, 2, 22, 12, 36, 0, 0, 2 * G_TIME_SPAN_HOUR },
896 { TRUE, "1990-12-31T15:59:60-08:00", 1990, 12, 31, 15, 59, 59, 0, -8 * G_TIME_SPAN_HOUR },
897 { FALSE, " ", 0, 0, 0, 0, 0, 0, 0, 0 },
898 { FALSE, "x", 0, 0, 0, 0, 0, 0, 0, 0 },
899 { FALSE, "123x", 0, 0, 0, 0, 0, 0, 0, 0 },
900 { FALSE, "2001-10+x", 0, 0, 0, 0, 0, 0, 0, 0 },
901 { FALSE, "1980-02-22T", 0, 0, 0, 0, 0, 0, 0, 0 },
902 { FALSE, "2001-10-08Tx", 0, 0, 0, 0, 0, 0, 0, 0 },
903 { FALSE, "2001-10-08T10:11x", 0, 0, 0, 0, 0, 0, 0, 0 },
904 { FALSE, "Wed Dec 19 17:20:20 GMT 2007", 0, 0, 0, 0, 0, 0, 0, 0 },
905 { FALSE, "1980-02-22T10:36:00Zulu", 0, 0, 0, 0, 0, 0, 0, 0 },
906 { FALSE, "2T0+819855292164632335", 0, 0, 0, 0, 0, 0, 0, 0 },
907 { TRUE, "2018-08-03T14:08:05.446178377+01:00", 2018, 8, 3, 14, 8, 5, 446178, 1 * G_TIME_SPAN_HOUR },
908 { FALSE, "2147483648-08-03T14:08:05.446178377+01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
909 { FALSE, "2018-13-03T14:08:05.446178377+01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
910 { FALSE, "2018-00-03T14:08:05.446178377+01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
911 { FALSE, "2018-08-00T14:08:05.446178377+01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
912 { FALSE, "2018-08-32T14:08:05.446178377+01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
913 { FALSE, "2018-08-03T24:08:05.446178377+01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
914 { FALSE, "2018-08-03T14:60:05.446178377+01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
915 { FALSE, "2018-08-03T14:08:63.446178377+01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
916 { FALSE, "2018-08-03T14:08:05.446178377+100:00", 0, 0, 0, 0, 0, 0, 0, 0 },
917 { TRUE, "20180803T140805.446178377+0100", 2018, 8, 3, 14, 8, 5, 446178, 1 * G_TIME_SPAN_HOUR },
918 { FALSE, "21474836480803T140805.446178377+0100", 0, 0, 0, 0, 0, 0, 0, 0 },
919 { FALSE, "20181303T140805.446178377+0100", 0, 0, 0, 0, 0, 0, 0, 0 },
920 { FALSE, "20180003T140805.446178377+0100", 0, 0, 0, 0, 0, 0, 0, 0 },
921 { FALSE, "20180800T140805.446178377+0100", 0, 0, 0, 0, 0, 0, 0, 0 },
922 { FALSE, "20180832T140805.446178377+0100", 0, 0, 0, 0, 0, 0, 0, 0 },
923 { FALSE, "20180803T240805.446178377+0100", 0, 0, 0, 0, 0, 0, 0, 0 },
924 { FALSE, "20180803T146005.446178377+0100", 0, 0, 0, 0, 0, 0, 0, 0 },
925 { FALSE, "20180803T140863.446178377+0100", 0, 0, 0, 0, 0, 0, 0, 0 },
926 { FALSE, "20180803T140805.446178377+10000", 0, 0, 0, 0, 0, 0, 0, 0 },
927 { FALSE, "-0005-01-01T00:00:00Z", 0, 0, 0, 0, 0, 0, 0, 0 },
928 { FALSE, "2018-08-06", 0, 0, 0, 0, 0, 0, 0, 0 },
929 /* This is not accepted by g_time_val_from_iso8601(), but is accepted by g_date_time_new_from_iso8601():
930 { FALSE, "2018-08-06 13:51:00Z", 0, 0, 0, 0, 0, 0, 0, 0 },
932 { TRUE, "20180803T140805,446178377+0100", 2018, 8, 3, 14, 8, 5, 446178, 1 * G_TIME_SPAN_HOUR },
933 { TRUE, "2018-08-03T14:08:05.446178377-01:00", 2018, 8, 3, 14, 8, 5, 446178, -1 * G_TIME_SPAN_HOUR },
934 { FALSE, "2018-08-03T14:08:05.446178377 01:00", 0, 0, 0, 0, 0, 0, 0, 0 },
935 { TRUE, "1990-11-01T10:21:17", 1990, 11, 1, 10, 21, 17, 0, 0 },
936 /* These are accepted by g_time_val_from_iso8601(), but not by g_date_time_new_from_iso8601():
937 { TRUE, "19901101T102117+5", 1990, 11, 1, 10, 21, 17, 0, 5 * G_TIME_SPAN_HOUR },
938 { TRUE, "19901101T102117+3:15", 1990, 11, 1, 10, 21, 17, 0, 3 * G_TIME_SPAN_HOUR + 15 * G_TIME_SPAN_MINUTE },
939 { TRUE, " 1990-11-01T10:21:17Z ", 1990, 11, 1, 10, 21, 17, 0, 0 },
940 { FALSE, "2018-08-03T14:08:05.446178377+01:60", 0, 0, 0, 0, 0, 0, 0, 0 },
941 { FALSE, "20180803T140805.446178377+0160", 0, 0, 0, 0, 0, 0, 0, 0 },
942 { TRUE, "+1980-02-22T12:36:00+02:00", 1980, 2, 22, 12, 36, 0, 0, 2 * G_TIME_SPAN_HOUR },
943 { TRUE, "1990-11-01T10:21:17 ", 1990, 11, 1, 10, 21, 17, 0, 0 },
945 { FALSE, "1719W462 407777-07", 0, 0, 0, 0, 0, 0, 0, 0 },
946 { FALSE, "4011090 260528Z", 0, 0, 0, 0, 0, 0, 0, 0 },
947 { FALSE, "0000W011 228214-22", 0, 0, 0, 0, 0, 0, 0, 0 },
949 GTimeZone *tz = NULL;
950 GDateTime *dt = NULL;
953 g_test_summary ("Further parser tests for g_date_time_new_from_iso8601(), "
954 "checking success and failure using test vectors.");
956 tz = g_time_zone_new_utc ();
958 for (i = 0; i < G_N_ELEMENTS (tests); i++)
960 g_test_message ("Vector %" G_GSIZE_FORMAT ": %s", i, tests[i].in);
962 dt = g_date_time_new_from_iso8601 (tests[i].in, tz);
963 if (tests[i].success)
965 g_assert_nonnull (dt);
966 ASSERT_DATE (dt, tests[i].year, tests[i].month, tests[i].day);
967 ASSERT_TIME (dt, tests[i].hour, tests[i].minute, tests[i].second, tests[i].microsecond);
968 g_assert_cmpint (g_date_time_get_utc_offset (dt), ==, tests[i].utc_offset);
975 g_clear_pointer (&dt, g_date_time_unref);
978 g_time_zone_unref (tz);
982 test_GDateTime_to_unix (void)
988 g_assert_cmpint (t, !=, (time_t) -1);
989 dt = g_date_time_new_from_unix_local (t);
990 g_assert_cmpint (g_date_time_to_unix (dt), ==, t);
991 g_date_time_unref (dt);
995 test_GDateTime_add_years (void)
999 dt = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
1000 dt2 = g_date_time_add_years (dt, 1);
1001 g_assert_cmpint (2010, ==, g_date_time_get_year (dt2));
1002 g_date_time_unref (dt);
1003 g_date_time_unref (dt2);
1007 test_GDateTime_add_months (void)
1009 #define TEST_ADD_MONTHS(y,m,d,a,ny,nm,nd) G_STMT_START { \
1010 GDateTime *dt, *dt2; \
1011 dt = g_date_time_new_utc (y, m, d, 0, 0, 0); \
1012 dt2 = g_date_time_add_months (dt, a); \
1013 ASSERT_DATE (dt2, ny, nm, nd); \
1014 g_date_time_unref (dt); \
1015 g_date_time_unref (dt2); \
1018 TEST_ADD_MONTHS (2009, 12, 31, 1, 2010, 1, 31);
1019 TEST_ADD_MONTHS (2009, 12, 31, 1, 2010, 1, 31);
1020 TEST_ADD_MONTHS (2009, 6, 15, 1, 2009, 7, 15);
1021 TEST_ADD_MONTHS (1400, 3, 1, 1, 1400, 4, 1);
1022 TEST_ADD_MONTHS (1400, 1, 31, 1, 1400, 2, 28);
1023 TEST_ADD_MONTHS (1400, 1, 31, 7200, 2000, 1, 31);
1024 TEST_ADD_MONTHS (2008, 2, 29, 12, 2009, 2, 28);
1025 TEST_ADD_MONTHS (2000, 8, 16, -5, 2000, 3, 16);
1026 TEST_ADD_MONTHS (2000, 8, 16, -12, 1999, 8, 16);
1027 TEST_ADD_MONTHS (2011, 2, 1, -13, 2010, 1, 1);
1028 TEST_ADD_MONTHS (1776, 7, 4, 1200, 1876, 7, 4);
1032 test_GDateTime_add_days (void)
1034 #define TEST_ADD_DAYS(y,m,d,a,ny,nm,nd) G_STMT_START { \
1035 GDateTime *dt, *dt2; \
1036 dt = g_date_time_new_local (y, m, d, 0, 0, 0); \
1037 dt2 = g_date_time_add_days (dt, a); \
1038 g_assert_cmpint (ny, ==, g_date_time_get_year (dt2)); \
1039 g_assert_cmpint (nm, ==, g_date_time_get_month (dt2)); \
1040 g_assert_cmpint (nd, ==, g_date_time_get_day_of_month (dt2)); \
1041 g_date_time_unref (dt); \
1042 g_date_time_unref (dt2); \
1045 TEST_ADD_DAYS (2009, 1, 31, 1, 2009, 2, 1);
1046 TEST_ADD_DAYS (2009, 2, 1, -1, 2009, 1, 31);
1047 TEST_ADD_DAYS (2008, 2, 28, 1, 2008, 2, 29);
1048 TEST_ADD_DAYS (2008, 12, 31, 1, 2009, 1, 1);
1049 TEST_ADD_DAYS (1, 1, 1, 1, 1, 1, 2);
1050 TEST_ADD_DAYS (1955, 5, 24, 10, 1955, 6, 3);
1051 TEST_ADD_DAYS (1955, 5, 24, -10, 1955, 5, 14);
1055 test_GDateTime_add_weeks (void)
1057 #define TEST_ADD_WEEKS(y,m,d,a,ny,nm,nd) G_STMT_START { \
1058 GDateTime *dt, *dt2; \
1059 dt = g_date_time_new_local (y, m, d, 0, 0, 0); \
1060 dt2 = g_date_time_add_weeks (dt, a); \
1061 g_assert_cmpint (ny, ==, g_date_time_get_year (dt2)); \
1062 g_assert_cmpint (nm, ==, g_date_time_get_month (dt2)); \
1063 g_assert_cmpint (nd, ==, g_date_time_get_day_of_month (dt2)); \
1064 g_date_time_unref (dt); \
1065 g_date_time_unref (dt2); \
1068 TEST_ADD_WEEKS (2009, 1, 1, 1, 2009, 1, 8);
1069 TEST_ADD_WEEKS (2009, 8, 30, 1, 2009, 9, 6);
1070 TEST_ADD_WEEKS (2009, 12, 31, 1, 2010, 1, 7);
1071 TEST_ADD_WEEKS (2009, 1, 1, -1, 2008, 12, 25);
1075 test_GDateTime_add_hours (void)
1077 #define TEST_ADD_HOURS(y,m,d,h,mi,s,a,ny,nm,nd,nh,nmi,ns) G_STMT_START { \
1078 GDateTime *dt, *dt2; \
1079 dt = g_date_time_new_utc (y, m, d, h, mi, s); \
1080 dt2 = g_date_time_add_hours (dt, a); \
1081 g_assert_cmpint (ny, ==, g_date_time_get_year (dt2)); \
1082 g_assert_cmpint (nm, ==, g_date_time_get_month (dt2)); \
1083 g_assert_cmpint (nd, ==, g_date_time_get_day_of_month (dt2)); \
1084 g_assert_cmpint (nh, ==, g_date_time_get_hour (dt2)); \
1085 g_assert_cmpint (nmi, ==, g_date_time_get_minute (dt2)); \
1086 g_assert_cmpint (ns, ==, g_date_time_get_second (dt2)); \
1087 g_date_time_unref (dt); \
1088 g_date_time_unref (dt2); \
1091 TEST_ADD_HOURS (2009, 1, 1, 0, 0, 0, 1, 2009, 1, 1, 1, 0, 0);
1092 TEST_ADD_HOURS (2008, 12, 31, 23, 0, 0, 1, 2009, 1, 1, 0, 0, 0);
1096 test_GDateTime_add_full (void)
1098 #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 { \
1099 GDateTime *dt, *dt2; \
1100 dt = g_date_time_new_utc (y, m, d, h, mi, s); \
1101 dt2 = g_date_time_add_full (dt, ay, am, ad, ah, ami, as); \
1102 g_assert_cmpint (ny, ==, g_date_time_get_year (dt2)); \
1103 g_assert_cmpint (nm, ==, g_date_time_get_month (dt2)); \
1104 g_assert_cmpint (nd, ==, g_date_time_get_day_of_month (dt2)); \
1105 g_assert_cmpint (nh, ==, g_date_time_get_hour (dt2)); \
1106 g_assert_cmpint (nmi, ==, g_date_time_get_minute (dt2)); \
1107 g_assert_cmpint (ns, ==, g_date_time_get_second (dt2)); \
1108 g_date_time_unref (dt); \
1109 g_date_time_unref (dt2); \
1112 TEST_ADD_FULL (2009, 10, 21, 0, 0, 0,
1114 2010, 11, 22, 1, 1, 1);
1115 TEST_ADD_FULL (2000, 1, 1, 1, 1, 1,
1117 2000, 2, 1, 1, 1, 1);
1118 TEST_ADD_FULL (2000, 1, 1, 0, 0, 0,
1120 1999, 2, 1, 0, 0, 0);
1121 TEST_ADD_FULL (2010, 10, 31, 0, 0, 0,
1123 2011, 2, 28, 0, 0, 0);
1124 TEST_ADD_FULL (2010, 8, 25, 22, 45, 0,
1126 2010, 10, 2, 0, 10, 0);
1130 test_GDateTime_add_minutes (void)
1132 #define TEST_ADD_MINUTES(i,o) G_STMT_START { \
1133 GDateTime *dt, *dt2; \
1134 dt = g_date_time_new_local (2000, 1, 1, 0, 0, 0); \
1135 dt2 = g_date_time_add_minutes (dt, i); \
1136 g_assert_cmpint (o, ==, g_date_time_get_minute (dt2)); \
1137 g_date_time_unref (dt); \
1138 g_date_time_unref (dt2); \
1141 TEST_ADD_MINUTES (60, 0);
1142 TEST_ADD_MINUTES (100, 40);
1143 TEST_ADD_MINUTES (5, 5);
1144 TEST_ADD_MINUTES (1441, 1);
1145 TEST_ADD_MINUTES (-1441, 59);
1149 test_GDateTime_add_seconds (void)
1151 #define TEST_ADD_SECONDS(i,o) G_STMT_START { \
1152 GDateTime *dt, *dt2; \
1153 dt = g_date_time_new_local (2000, 1, 1, 0, 0, 0); \
1154 dt2 = g_date_time_add_seconds (dt, i); \
1155 g_assert_cmpint (o, ==, g_date_time_get_second (dt2)); \
1156 g_date_time_unref (dt); \
1157 g_date_time_unref (dt2); \
1160 TEST_ADD_SECONDS (1, 1);
1161 TEST_ADD_SECONDS (60, 0);
1162 TEST_ADD_SECONDS (61, 1);
1163 TEST_ADD_SECONDS (120, 0);
1164 TEST_ADD_SECONDS (-61, 59);
1165 TEST_ADD_SECONDS (86401, 1);
1166 TEST_ADD_SECONDS (-86401, 59);
1167 TEST_ADD_SECONDS (-31, 29);
1168 TEST_ADD_SECONDS (13, 13);
1172 test_GDateTime_diff (void)
1174 #define TEST_DIFF(y,m,d,y2,m2,d2,u) G_STMT_START { \
1175 GDateTime *dt1, *dt2; \
1177 dt1 = g_date_time_new_utc (y, m, d, 0, 0, 0); \
1178 dt2 = g_date_time_new_utc (y2, m2, d2, 0, 0, 0); \
1179 ts = g_date_time_difference (dt2, dt1); \
1180 g_assert_cmpint (ts, ==, u); \
1181 g_date_time_unref (dt1); \
1182 g_date_time_unref (dt2); \
1185 TEST_DIFF (2009, 1, 1, 2009, 2, 1, G_TIME_SPAN_DAY * 31);
1186 TEST_DIFF (2009, 1, 1, 2010, 1, 1, G_TIME_SPAN_DAY * 365);
1187 TEST_DIFF (2008, 2, 28, 2008, 2, 29, G_TIME_SPAN_DAY);
1188 TEST_DIFF (2008, 2, 29, 2008, 2, 28, -G_TIME_SPAN_DAY);
1190 /* TODO: Add usec tests */
1194 test_GDateTime_get_minute (void)
1198 dt = g_date_time_new_utc (2009, 12, 1, 1, 31, 0);
1199 g_assert_cmpint (31, ==, g_date_time_get_minute (dt));
1200 g_date_time_unref (dt);
1204 test_GDateTime_get_month (void)
1208 dt = g_date_time_new_utc (2009, 12, 1, 1, 31, 0);
1209 g_assert_cmpint (12, ==, g_date_time_get_month (dt));
1210 g_date_time_unref (dt);
1214 test_GDateTime_get_second (void)
1218 dt = g_date_time_new_utc (2009, 12, 1, 1, 31, 44);
1219 g_assert_cmpint (44, ==, g_date_time_get_second (dt));
1220 g_date_time_unref (dt);
1224 test_GDateTime_new_full (void)
1226 GTimeZone *tz, *dt_tz;
1230 LCID currLcid = GetThreadLocale ();
1231 LANGID currLangId = LANGIDFROMLCID (currLcid);
1232 LANGID en = MAKELANGID (LANG_ENGLISH, SUBLANG_ENGLISH_US);
1233 SetThreadUILanguage (en);
1236 dt = g_date_time_new_utc (2009, 12, 11, 12, 11, 10);
1237 g_assert_cmpint (2009, ==, g_date_time_get_year (dt));
1238 g_assert_cmpint (12, ==, g_date_time_get_month (dt));
1239 g_assert_cmpint (11, ==, g_date_time_get_day_of_month (dt));
1240 g_assert_cmpint (12, ==, g_date_time_get_hour (dt));
1241 g_assert_cmpint (11, ==, g_date_time_get_minute (dt));
1242 g_assert_cmpint (10, ==, g_date_time_get_second (dt));
1243 g_date_time_unref (dt);
1246 tz = g_time_zone_new_identifier ("America/Tijuana");
1247 #elif defined G_OS_WIN32
1248 tz = g_time_zone_new_identifier ("Pacific Standard Time");
1250 g_assert_nonnull (tz);
1251 dt = g_date_time_new (tz, 2010, 11, 24, 8, 4, 0);
1253 dt_tz = g_date_time_get_timezone (dt);
1254 g_assert_cmpstr (g_time_zone_get_identifier (dt_tz), ==,
1255 g_time_zone_get_identifier (tz));
1257 g_assert_cmpint (2010, ==, g_date_time_get_year (dt));
1258 g_assert_cmpint (11, ==, g_date_time_get_month (dt));
1259 g_assert_cmpint (24, ==, g_date_time_get_day_of_month (dt));
1260 g_assert_cmpint (8, ==, g_date_time_get_hour (dt));
1261 g_assert_cmpint (4, ==, g_date_time_get_minute (dt));
1262 g_assert_cmpint (0, ==, g_date_time_get_second (dt));
1264 g_assert_cmpstr ("PST", ==, g_date_time_get_timezone_abbreviation (dt));
1265 g_assert_cmpstr ("America/Tijuana", ==, g_time_zone_get_identifier (dt_tz));
1266 #elif defined G_OS_WIN32
1267 g_assert_cmpstr ("Pacific Standard Time", ==,
1268 g_date_time_get_timezone_abbreviation (dt));
1269 g_assert_cmpstr ("Pacific Standard Time", ==,
1270 g_time_zone_get_identifier (dt_tz));
1271 SetThreadUILanguage (currLangId);
1273 g_assert (!g_date_time_is_daylight_savings (dt));
1274 g_date_time_unref (dt);
1275 g_time_zone_unref (tz);
1277 /* Check month limits */
1278 dt = g_date_time_new_utc (2016, 1, 31, 22, 10, 42);
1279 ASSERT_DATE (dt, 2016, 1, 31);
1280 g_date_time_unref (dt);
1281 dt = g_date_time_new_utc (2016, 1, 32, 22, 10, 42);
1283 dt = g_date_time_new_utc (2016, 2, 29, 22, 10, 42);
1284 ASSERT_DATE (dt, 2016, 2, 29);
1285 g_date_time_unref (dt);
1286 dt = g_date_time_new_utc (2016, 2, 30, 22, 10, 42);
1288 dt = g_date_time_new_utc (2017, 2, 28, 22, 10, 42);
1289 ASSERT_DATE (dt, 2017, 2, 28);
1290 g_date_time_unref (dt);
1291 dt = g_date_time_new_utc (2017, 2, 29, 22, 10, 42);
1293 dt = g_date_time_new_utc (2016, 3, 31, 22, 10, 42);
1294 ASSERT_DATE (dt, 2016, 3, 31);
1295 g_date_time_unref (dt);
1296 dt = g_date_time_new_utc (2016, 3, 32, 22, 10, 42);
1298 dt = g_date_time_new_utc (2016, 4, 30, 22, 10, 42);
1299 ASSERT_DATE (dt, 2016, 4, 30);
1300 g_date_time_unref (dt);
1301 dt = g_date_time_new_utc (2016, 4, 31, 22, 10, 42);
1303 dt = g_date_time_new_utc (2016, 5, 31, 22, 10, 42);
1304 ASSERT_DATE (dt, 2016, 5, 31);
1305 g_date_time_unref (dt);
1306 dt = g_date_time_new_utc (2016, 5, 32, 22, 10, 42);
1308 dt = g_date_time_new_utc (2016, 6, 30, 22, 10, 42);
1309 ASSERT_DATE (dt, 2016, 6, 30);
1310 g_date_time_unref (dt);
1311 dt = g_date_time_new_utc (2016, 6, 31, 22, 10, 42);
1313 dt = g_date_time_new_utc (2016, 7, 31, 22, 10, 42);
1314 ASSERT_DATE (dt, 2016, 7, 31);
1315 g_date_time_unref (dt);
1316 dt = g_date_time_new_utc (2016, 7, 32, 22, 10, 42);
1318 dt = g_date_time_new_utc (2016, 8, 31, 22, 10, 42);
1319 ASSERT_DATE (dt, 2016, 8, 31);
1320 g_date_time_unref (dt);
1321 dt = g_date_time_new_utc (2016, 8, 32, 22, 10, 42);
1323 dt = g_date_time_new_utc (2016, 9, 30, 22, 10, 42);
1324 ASSERT_DATE (dt, 2016, 9, 30);
1325 g_date_time_unref (dt);
1326 dt = g_date_time_new_utc (2016, 9, 31, 22, 10, 42);
1328 dt = g_date_time_new_utc (2016, 10, 31, 22, 10, 42);
1329 ASSERT_DATE (dt, 2016, 10, 31);
1330 g_date_time_unref (dt);
1331 dt = g_date_time_new_utc (2016, 10, 32, 22, 10, 42);
1333 dt = g_date_time_new_utc (2016, 11, 30, 22, 10, 42);
1334 ASSERT_DATE (dt, 2016, 11, 30);
1335 g_date_time_unref (dt);
1336 dt = g_date_time_new_utc (2016, 11, 31, 22, 10, 42);
1338 dt = g_date_time_new_utc (2016, 12, 31, 22, 10, 42);
1339 ASSERT_DATE (dt, 2016, 12, 31);
1340 g_date_time_unref (dt);
1341 dt = g_date_time_new_utc (2016, 12, 32, 22, 10, 42);
1344 /* Seconds limits. */
1345 dt = g_date_time_new_utc (2020, 12, 9, 14, 49, NAN);
1347 dt = g_date_time_new_utc (2020, 12, 9, 14, 49, -0.1);
1349 dt = g_date_time_new_utc (2020, 12, 9, 14, 49, 60.0);
1353 dt = g_date_time_new_utc (10000, 1, 1, 0, 0, 0);
1354 dt = g_date_time_new_utc (0, 1, 1, 0, 0, 0);
1358 test_GDateTime_now_utc (void)
1365 /* t <= dt.to_unix() <= after, but the inequalities might not be
1366 * equality if we're close to the boundary between seconds.
1367 * We loop until t == after (and hence dt.to_unix() should equal both)
1368 * to guard against that. */
1371 t = g_get_real_time () / G_TIME_SPAN_SECOND;
1372 #ifdef HAVE_GMTIME_R
1376 struct tm *tmp = gmtime (&t);
1377 /* Assume gmtime() can't fail as we got t from time(NULL). (Note
1378 * that on Windows, gmtime() *is* MT-safe, it uses a thread-local
1381 memcpy (&tm, tmp, sizeof (struct tm));
1384 dt = g_date_time_new_now_utc ();
1386 after = g_get_real_time () / G_TIME_SPAN_SECOND;
1390 g_assert_cmpint (tm.tm_year + 1900, ==, g_date_time_get_year (dt));
1391 g_assert_cmpint (tm.tm_mon + 1, ==, g_date_time_get_month (dt));
1392 g_assert_cmpint (tm.tm_mday, ==, g_date_time_get_day_of_month (dt));
1393 g_assert_cmpint (tm.tm_hour, ==, g_date_time_get_hour (dt));
1394 g_assert_cmpint (tm.tm_min, ==, g_date_time_get_minute (dt));
1395 g_assert_cmpint (tm.tm_sec, ==, g_date_time_get_second (dt));
1396 g_date_time_unref (dt);
1400 test_GDateTime_new_from_unix_utc (void)
1405 t = g_get_real_time ();
1408 dt = g_date_time_new_from_unix_utc (t);
1409 g_assert (dt == NULL);
1412 t = t / 1e6; /* oops, this was microseconds */
1414 dt = g_date_time_new_from_unix_utc (t);
1415 g_assert (dt != NULL);
1417 g_assert (dt == g_date_time_ref (dt));
1418 g_date_time_unref (dt);
1419 g_assert_cmpint (g_date_time_to_unix (dt), ==, t);
1420 g_date_time_unref (dt);
1424 test_GDateTime_get_utc_offset (void)
1426 #if defined (HAVE_STRUCT_TM_TM_GMTOFF) || defined (HAVE_STRUCT_TM___TM_GMTOFF)
1431 memset (&tm, 0, sizeof (tm));
1432 get_localtime_tm (g_get_real_time () / G_TIME_SPAN_SECOND, &tm);
1434 dt = g_date_time_new_now_local ();
1435 ts = g_date_time_get_utc_offset (dt);
1436 #ifdef HAVE_STRUCT_TM_TM_GMTOFF
1437 g_assert_cmpint (ts, ==, (tm.tm_gmtoff * G_TIME_SPAN_SECOND));
1439 #ifdef HAVE_STRUCT_TM___TM_GMTOFF
1440 g_assert_cmpint (ts, ==, (tm.__tm_gmtoff * G_TIME_SPAN_SECOND));
1442 g_date_time_unref (dt);
1446 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1448 test_GDateTime_to_timeval (void)
1453 memset (&tv1, 0, sizeof (tv1));
1454 memset (&tv2, 0, sizeof (tv2));
1456 g_get_current_time (&tv1);
1457 dt = g_date_time_new_from_timeval_local (&tv1);
1458 g_date_time_to_timeval (dt, &tv2);
1459 g_assert_cmpint (tv1.tv_sec, ==, tv2.tv_sec);
1460 g_assert_cmpint (tv1.tv_usec, ==, tv2.tv_usec);
1461 g_date_time_unref (dt);
1463 G_GNUC_END_IGNORE_DEPRECATIONS
1466 test_GDateTime_to_local (void)
1468 GDateTime *utc = NULL, *now = NULL, *dt;
1469 time_t before, after;
1471 /* before <= utc.to_unix() <= now.to_unix() <= after, but the inequalities
1472 * might not be equality if we're close to the boundary between seconds.
1473 * We loop until before == after (and hence the GDateTimes should match)
1474 * to guard against that. */
1477 before = g_get_real_time () / G_TIME_SPAN_SECOND;
1478 g_clear_pointer (&utc, g_date_time_unref);
1479 g_clear_pointer (&now, g_date_time_unref);
1480 utc = g_date_time_new_now_utc ();
1481 now = g_date_time_new_now_local ();
1482 after = g_get_real_time () / G_TIME_SPAN_SECOND;
1484 while (before != after);
1486 dt = g_date_time_to_local (utc);
1488 g_assert_cmpint (g_date_time_get_year (now), ==, g_date_time_get_year (dt));
1489 g_assert_cmpint (g_date_time_get_month (now), ==, g_date_time_get_month (dt));
1490 g_assert_cmpint (g_date_time_get_day_of_month (now), ==, g_date_time_get_day_of_month (dt));
1491 g_assert_cmpint (g_date_time_get_hour (now), ==, g_date_time_get_hour (dt));
1492 g_assert_cmpint (g_date_time_get_minute (now), ==, g_date_time_get_minute (dt));
1493 g_assert_cmpint (g_date_time_get_second (now), ==, g_date_time_get_second (dt));
1495 g_date_time_unref (now);
1496 g_date_time_unref (utc);
1497 g_date_time_unref (dt);
1501 test_GDateTime_to_utc (void)
1503 GDateTime *dt, *dt2;
1508 g_assert_cmpint (t, !=, (time_t) -1);
1509 #ifdef HAVE_GMTIME_R
1513 struct tm *tmp = gmtime (&t);
1514 memcpy (&tm, tmp, sizeof (struct tm));
1517 dt2 = g_date_time_new_from_unix_local (t);
1518 dt = g_date_time_to_utc (dt2);
1519 g_assert_cmpint (tm.tm_year + 1900, ==, g_date_time_get_year (dt));
1520 g_assert_cmpint (tm.tm_mon + 1, ==, g_date_time_get_month (dt));
1521 g_assert_cmpint (tm.tm_mday, ==, g_date_time_get_day_of_month (dt));
1522 g_assert_cmpint (tm.tm_hour, ==, g_date_time_get_hour (dt));
1523 g_assert_cmpint (tm.tm_min, ==, g_date_time_get_minute (dt));
1524 g_assert_cmpint (tm.tm_sec, ==, g_date_time_get_second (dt));
1525 g_date_time_unref (dt);
1526 g_date_time_unref (dt2);
1530 test_GDateTime_get_day_of_year (void)
1532 #define TEST_DAY_OF_YEAR(y,m,d,o) G_STMT_START { \
1533 GDateTime *__dt = g_date_time_new_local ((y), (m), (d), 0, 0, 0); \
1534 g_assert_cmpint ((o), ==, g_date_time_get_day_of_year (__dt)); \
1535 g_date_time_unref (__dt); } G_STMT_END
1537 TEST_DAY_OF_YEAR (2009, 1, 1, 1);
1538 TEST_DAY_OF_YEAR (2009, 2, 1, 32);
1539 TEST_DAY_OF_YEAR (2009, 8, 16, 228);
1540 TEST_DAY_OF_YEAR (2008, 8, 16, 229);
1544 test_GDateTime_printf (void)
1547 gchar *old_lc_messages;
1550 gchar *current_tz = NULL;
1551 DYNAMIC_TIME_ZONE_INFORMATION dtz_info;
1554 #define TEST_PRINTF(f,o) G_STMT_START { \
1555 const char *expected = (o); \
1556 GDateTime *__dt = g_date_time_new_utc (2009, 10, 24, 0, 0, 0);\
1557 gchar *actual = g_date_time_format (__dt, (f)); \
1558 g_test_message ("%s -> expected: %s", (f), expected); \
1559 g_test_message ("%s -> actual: %s", (f), actual); \
1560 g_assert_cmpstr (actual, ==, expected); \
1561 g_date_time_unref (__dt); \
1562 g_free (actual); } G_STMT_END
1564 #define TEST_PRINTF_DATE(y,m,d,f,o) G_STMT_START { \
1565 const char *expected = (o); \
1566 GDateTime *dt = g_date_time_new_utc (y, m, d, 0, 0, 0); \
1567 gchar *actual = g_date_time_format (dt, (f)); \
1568 gchar *expected_casefold = g_utf8_casefold (expected, -1); \
1569 gchar *actual_casefold = g_utf8_casefold (actual, -1); \
1570 g_test_message ("%s -> expected: %s", (f), expected); \
1571 g_test_message ("%s -> actual: %s", (f), actual); \
1572 g_assert_cmpstr (expected_casefold, ==, (actual_casefold)); \
1573 g_date_time_unref (dt); \
1574 g_free (expected_casefold); \
1575 g_free (actual_casefold); \
1576 g_free (actual); } G_STMT_END
1578 #define TEST_PRINTF_TIME(h,m,s,f,o) G_STMT_START { \
1579 GDateTime *dt = g_date_time_new_utc (2009, 10, 24, (h), (m), (s)); \
1580 const char *expected = (o); \
1581 gchar *actual = g_date_time_format (dt, (f)); \
1582 g_test_message ("%s -> expected: %s", (f), expected); \
1583 g_test_message ("%s -> actual: %s", (f), actual); \
1584 g_assert_cmpstr (actual, ==, expected); \
1585 g_date_time_unref (dt); \
1586 g_free (actual); } G_STMT_END
1588 old_lc_all = g_strdup (g_getenv ("LC_ALL"));
1589 g_unsetenv ("LC_ALL");
1591 old_lc_messages = g_strdup (g_getenv ("LC_MESSAGES"));
1592 g_setenv ("LC_MESSAGES", "C", TRUE);
1594 TEST_PRINTF ("%a", "Sat");
1595 TEST_PRINTF ("%A", "Saturday");
1596 TEST_PRINTF ("%b", "Oct");
1597 TEST_PRINTF ("%B", "October");
1598 TEST_PRINTF ("%d", "24");
1599 TEST_PRINTF_DATE (2009, 1, 1, "%d", "01");
1600 TEST_PRINTF ("%e", "24");
1601 TEST_PRINTF_DATE (2009, 1, 1, "%e", "\u20071");
1602 TEST_PRINTF_TIME (10, 10, 1.001, "%f", "001000");
1603 TEST_PRINTF ("%h", "Oct");
1604 TEST_PRINTF ("%H", "00");
1605 TEST_PRINTF_TIME (15, 0, 0, "%H", "15");
1606 TEST_PRINTF ("%I", "12");
1607 TEST_PRINTF_TIME (12, 0, 0, "%I", "12");
1608 TEST_PRINTF_TIME (15, 0, 0, "%I", "03");
1609 TEST_PRINTF ("%j", "297");
1610 TEST_PRINTF ("%k", "\u20070");
1611 TEST_PRINTF_TIME (13, 13, 13, "%k", "13");
1612 TEST_PRINTF ("%l", "12");
1613 TEST_PRINTF_TIME (12, 0, 0, "%I", "12");
1614 TEST_PRINTF_TIME (13, 13, 13, "%l", "\u20071");
1615 TEST_PRINTF_TIME (10, 13, 13, "%l", "10");
1616 TEST_PRINTF ("%m", "10");
1617 TEST_PRINTF ("%M", "00");
1618 TEST_PRINTF ("%p", "AM");
1619 TEST_PRINTF_TIME (13, 13, 13, "%p", "PM");
1620 TEST_PRINTF ("%P", "am");
1621 TEST_PRINTF_TIME (13, 13, 13, "%P", "pm");
1622 TEST_PRINTF ("%r", "12:00:00 AM");
1623 TEST_PRINTF_TIME (13, 13, 13, "%r", "01:13:13 PM");
1624 TEST_PRINTF ("%R", "00:00");
1625 TEST_PRINTF_TIME (13, 13, 31, "%R", "13:13");
1626 TEST_PRINTF ("%S", "00");
1627 TEST_PRINTF ("%t", " ");
1628 TEST_PRINTF ("%u", "6");
1629 TEST_PRINTF ("%x", "10/24/09");
1630 TEST_PRINTF ("%X", "00:00:00");
1631 TEST_PRINTF_TIME (13, 14, 15, "%X", "13:14:15");
1632 TEST_PRINTF ("%y", "09");
1633 TEST_PRINTF ("%Y", "2009");
1634 TEST_PRINTF ("%%", "%");
1635 TEST_PRINTF ("%", "");
1636 TEST_PRINTF ("%9", NULL);
1638 TEST_PRINTF ("%Z", "UTC");
1639 #elif defined G_OS_WIN32
1640 g_assert (GetDynamicTimeZoneInformation (&dtz_info) != TIME_ZONE_ID_INVALID);
1641 if (wcscmp (dtz_info.StandardName, L"") != 0)
1642 current_tz = g_utf16_to_utf8 (dtz_info.StandardName, -1, NULL, NULL, NULL);
1644 current_tz = g_utf16_to_utf8 (dtz_info.DaylightName, -1, NULL, NULL, NULL);
1646 TEST_PRINTF ("%Z", current_tz);
1647 g_free (current_tz);
1650 if (old_lc_messages != NULL)
1651 g_setenv ("LC_MESSAGES", old_lc_messages, TRUE);
1653 g_unsetenv ("LC_MESSAGES");
1654 g_free (old_lc_messages);
1656 if (old_lc_all != NULL)
1657 g_setenv ("LC_ALL", old_lc_all, TRUE);
1658 g_free (old_lc_all);
1662 test_non_utf8_printf (void)
1666 if (skip_if_running_uninstalled())
1669 oldlocale = g_strdup (setlocale (LC_ALL, NULL));
1670 setlocale (LC_ALL, "ja_JP.eucjp");
1671 if (strstr (setlocale (LC_ALL, NULL), "ja_JP") == NULL)
1673 g_test_skip ("locale ja_JP.eucjp not available, skipping non-UTF8 tests");
1677 if (g_get_charset (NULL))
1679 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");
1680 setlocale (LC_ALL, oldlocale);
1685 /* These are the outputs that ja_JP.UTF-8 generates; if everything
1686 * is working then ja_JP.eucjp should generate the same.
1688 TEST_PRINTF ("%a", "\345\234\237");
1689 TEST_PRINTF ("%A", "\345\234\237\346\233\234\346\227\245");
1690 #ifndef __APPLE__ /* OSX just returns the number */
1691 TEST_PRINTF ("%b", "10\346\234\210");
1693 TEST_PRINTF ("%B", "10\346\234\210");
1694 TEST_PRINTF ("%c", "2009年10月24日 00時00分00秒");
1695 TEST_PRINTF ("%C", "20");
1696 TEST_PRINTF ("%d", "24");
1697 TEST_PRINTF_DATE (2009, 1, 1, "%d", "01");
1698 TEST_PRINTF ("%e", "24"); // fixme
1699 #ifndef __APPLE__ /* OSX just returns the number */
1700 TEST_PRINTF ("%h", "10\346\234\210");
1702 TEST_PRINTF ("%H", "00");
1703 TEST_PRINTF_TIME (15, 0, 0, "%H", "15");
1704 TEST_PRINTF ("%I", "12");
1705 TEST_PRINTF_TIME (12, 0, 0, "%I", "12");
1706 TEST_PRINTF_TIME (15, 0, 0, "%I", "03");
1707 TEST_PRINTF ("%j", "297");
1708 TEST_PRINTF ("%k", "\u20070");
1709 TEST_PRINTF_TIME (13, 13, 13, "%k", "13");
1710 TEST_PRINTF ("%l", "12");
1711 TEST_PRINTF_TIME (12, 0, 0, "%I", "12");
1712 TEST_PRINTF_TIME (13, 13, 13, "%l", "\u20071");
1713 TEST_PRINTF_TIME (10, 13, 13, "%l", "10");
1714 TEST_PRINTF ("%m", "10");
1715 TEST_PRINTF ("%M", "00");
1716 #ifndef __APPLE__ /* OSX returns latin "AM", not japanese */
1717 TEST_PRINTF ("%p", "\345\215\210\345\211\215");
1718 TEST_PRINTF_TIME (13, 13, 13, "%p", "\345\215\210\345\276\214");
1719 TEST_PRINTF ("%P", "\345\215\210\345\211\215");
1720 TEST_PRINTF_TIME (13, 13, 13, "%P", "\345\215\210\345\276\214");
1721 TEST_PRINTF ("%r", "\345\215\210\345\211\21512\346\231\20200\345\210\20600\347\247\222");
1722 TEST_PRINTF_TIME (13, 13, 13, "%r", "\345\215\210\345\276\21401\346\231\20213\345\210\20613\347\247\222");
1724 TEST_PRINTF ("%R", "00:00");
1725 TEST_PRINTF_TIME (13, 13, 31, "%R", "13:13");
1726 TEST_PRINTF ("%S", "00");
1727 TEST_PRINTF ("%t", " ");
1728 TEST_PRINTF ("%u", "6");
1729 #ifndef __APPLE__ /* OSX returns YYYY/MM/DD in ASCII */
1730 TEST_PRINTF ("%x", "2009\345\271\26410\346\234\21024\346\227\245");
1732 TEST_PRINTF ("%X", "00\346\231\20200\345\210\20600\347\247\222");
1733 TEST_PRINTF_TIME (13, 14, 15, "%X", "13\346\231\20214\345\210\20615\347\247\222");
1734 TEST_PRINTF ("%y", "09");
1735 TEST_PRINTF ("%Y", "2009");
1736 TEST_PRINTF ("%%", "%");
1737 TEST_PRINTF ("%", "");
1738 TEST_PRINTF ("%9", NULL);
1739 #if defined(HAVE_LANGINFO_ERA) && (G_BYTE_ORDER == G_LITTLE_ENDIAN || GLIB_SIZEOF_VOID_P == 4)
1740 TEST_PRINTF ("%Ec", "平成21年10月24日 00時00分00秒");
1741 TEST_PRINTF ("%EC", "平成");
1742 TEST_PRINTF ("%Ex", "平成21年10月24日");
1743 TEST_PRINTF ("%EX", "00時00分00秒");
1744 TEST_PRINTF ("%Ey", "21");
1745 TEST_PRINTF ("%EY", "平成21年");
1747 TEST_PRINTF ("%Ec", "2009年10月24日 00時00分00秒");
1748 TEST_PRINTF ("%EC", "20");
1749 TEST_PRINTF ("%Ex", "2009\345\271\26410\346\234\21024\346\227\245");
1750 TEST_PRINTF ("%EX", "00\346\231\20200\345\210\20600\347\247\222");
1751 TEST_PRINTF ("%Ey", "09");
1752 TEST_PRINTF ("%EY", "2009");
1755 setlocale (LC_ALL, oldlocale);
1759 /* Checks that it is possible to use format string that
1760 * is unrepresentable in current locale charset. */
1762 test_format_unrepresentable (void)
1764 gchar *oldlocale = g_strdup (setlocale (LC_ALL, NULL));
1765 setlocale (LC_ALL, "POSIX");
1767 TEST_PRINTF ("ąśćł", "ąśćł");
1769 /* We are using Unicode ratio symbol here, which is outside ASCII. */
1770 TEST_PRINTF_TIME (23, 15, 0, "%H∶%M", "23∶15");
1772 /* Test again, this time in locale with non ASCII charset. */
1773 if (setlocale (LC_ALL, "pl_PL.ISO-8859-2") != NULL)
1774 TEST_PRINTF_TIME (23, 15, 0, "%H∶%M", "23∶15");
1776 g_test_skip ("locale pl_PL.ISO-8859-2 not available, skipping test");
1778 setlocale (LC_ALL, oldlocale);
1783 test_modifiers (void)
1787 TEST_PRINTF_DATE (2009, 1, 1, "%d", "01");
1788 TEST_PRINTF_DATE (2009, 1, 1, "%_d", " 1");
1789 TEST_PRINTF_DATE (2009, 1, 1, "%-d", "1");
1790 TEST_PRINTF_DATE (2009, 1, 1, "%0d", "01");
1791 TEST_PRINTF_DATE (2009, 1, 21, "%d", "21");
1792 TEST_PRINTF_DATE (2009, 1, 21, "%_d", "21");
1793 TEST_PRINTF_DATE (2009, 1, 21, "%-d", "21");
1794 TEST_PRINTF_DATE (2009, 1, 21, "%0d", "21");
1796 TEST_PRINTF_DATE (2009, 1, 1, "%e", "\u20071");
1797 TEST_PRINTF_DATE (2009, 1, 1, "%_e", " 1");
1798 TEST_PRINTF_DATE (2009, 1, 1, "%-e", "1");
1799 TEST_PRINTF_DATE (2009, 1, 1, "%0e", "01");
1800 TEST_PRINTF_DATE (2009, 1, 21, "%e", "21");
1801 TEST_PRINTF_DATE (2009, 1, 21, "%_e", "21");
1802 TEST_PRINTF_DATE (2009, 1, 21, "%-e", "21");
1803 TEST_PRINTF_DATE (2009, 1, 21, "%0e", "21");
1805 TEST_PRINTF_DATE (2009, 1, 1, "%a", "Thu");
1806 TEST_PRINTF_DATE (2009, 1, 1, "%^a", "THU");
1807 TEST_PRINTF_DATE (2009, 1, 1, "%#a", "THU");
1809 TEST_PRINTF_DATE (2009, 1, 1, "%A", "Thursday");
1810 TEST_PRINTF_DATE (2009, 1, 1, "%^A", "THURSDAY");
1811 TEST_PRINTF_DATE (2009, 1, 1, "%#A", "THURSDAY");
1813 TEST_PRINTF_DATE (2009, 1, 1, "%b", "Jan");
1814 TEST_PRINTF_DATE (2009, 1, 1, "%^b", "JAN");
1815 TEST_PRINTF_DATE (2009, 1, 1, "%#b", "JAN");
1817 TEST_PRINTF_DATE (2009, 1, 1, "%B", "January");
1818 TEST_PRINTF_DATE (2009, 1, 1, "%^B", "JANUARY");
1819 TEST_PRINTF_DATE (2009, 1, 1, "%#B", "JANUARY");
1821 TEST_PRINTF_DATE (2009, 1, 1, "%h", "Jan");
1822 TEST_PRINTF_DATE (2009, 1, 1, "%^h", "JAN");
1823 TEST_PRINTF_DATE (2009, 1, 1, "%#h", "JAN");
1825 TEST_PRINTF_DATE (2009, 1, 1, "%Z", "UTC");
1826 TEST_PRINTF_DATE (2009, 1, 1, "%^Z", "UTC");
1827 TEST_PRINTF_DATE (2009, 1, 1, "%#Z", "utc");
1829 TEST_PRINTF_TIME ( 1, 0, 0, "%H", "01");
1830 TEST_PRINTF_TIME ( 1, 0, 0, "%_H", " 1");
1831 TEST_PRINTF_TIME ( 1, 0, 0, "%-H", "1");
1832 TEST_PRINTF_TIME ( 1, 0, 0, "%0H", "01");
1833 TEST_PRINTF_TIME (21, 0, 0, "%H", "21");
1834 TEST_PRINTF_TIME (21, 0, 0, "%_H", "21");
1835 TEST_PRINTF_TIME (21, 0, 0, "%-H", "21");
1836 TEST_PRINTF_TIME (21, 0, 0, "%0H", "21");
1838 TEST_PRINTF_TIME ( 1, 0, 0, "%I", "01");
1839 TEST_PRINTF_TIME ( 1, 0, 0, "%_I", " 1");
1840 TEST_PRINTF_TIME ( 1, 0, 0, "%-I", "1");
1841 TEST_PRINTF_TIME ( 1, 0, 0, "%0I", "01");
1842 TEST_PRINTF_TIME (23, 0, 0, "%I", "11");
1843 TEST_PRINTF_TIME (23, 0, 0, "%_I", "11");
1844 TEST_PRINTF_TIME (23, 0, 0, "%-I", "11");
1845 TEST_PRINTF_TIME (23, 0, 0, "%0I", "11");
1847 TEST_PRINTF_TIME ( 1, 0, 0, "%k", "\u20071");
1848 TEST_PRINTF_TIME ( 1, 0, 0, "%_k", " 1");
1849 TEST_PRINTF_TIME ( 1, 0, 0, "%-k", "1");
1850 TEST_PRINTF_TIME ( 1, 0, 0, "%0k", "01");
1852 TEST_PRINTF_TIME ( 1, 0, 0, "%l", "\u20071");
1853 TEST_PRINTF_TIME ( 1, 0, 0, "%_l", " 1");
1854 TEST_PRINTF_TIME ( 1, 0, 0, "%-l", "1");
1855 TEST_PRINTF_TIME ( 1, 0, 0, "%0l", "01");
1856 TEST_PRINTF_TIME (23, 0, 0, "%l", "11");
1857 TEST_PRINTF_TIME (23, 0, 0, "%_l", "11");
1858 TEST_PRINTF_TIME (23, 0, 0, "%-l", "11");
1859 TEST_PRINTF_TIME (23, 0, 0, "%0l", "11");
1861 TEST_PRINTF_TIME (1, 0, 0, "%p", "AM");
1862 TEST_PRINTF_TIME (1, 0, 0, "%^p", "AM");
1863 TEST_PRINTF_TIME (1, 0, 0, "%#p", "am");
1865 TEST_PRINTF_TIME (1, 0, 0, "%P", "am");
1866 TEST_PRINTF_TIME (1, 0, 0, "%^P", "AM");
1867 TEST_PRINTF_TIME (1, 0, 0, "%#P", "am");
1869 oldlocale = g_strdup (setlocale (LC_ALL, NULL));
1871 setlocale (LC_ALL, "fa_IR.utf-8");
1872 #ifdef HAVE_LANGINFO_OUTDIGIT
1873 if (strstr (setlocale (LC_ALL, NULL), "fa_IR") != NULL)
1875 TEST_PRINTF_TIME (23, 0, 0, "%OH", "\333\262\333\263"); /* '23' */
1876 TEST_PRINTF_TIME (23, 0, 0, "%OI", "\333\261\333\261"); /* '11' */
1877 TEST_PRINTF_TIME (23, 0, 0, "%OM", "\333\260\333\260"); /* '00' */
1879 TEST_PRINTF_DATE (2011, 7, 1, "%Om", "\333\260\333\267"); /* '07' */
1880 TEST_PRINTF_DATE (2011, 7, 1, "%0Om", "\333\260\333\267"); /* '07' */
1881 TEST_PRINTF_DATE (2011, 7, 1, "%-Om", "\333\267"); /* '7' */
1882 TEST_PRINTF_DATE (2011, 7, 1, "%_Om", " \333\267"); /* ' 7' */
1885 g_test_skip ("locale fa_IR not available, skipping O modifier tests");
1887 g_test_skip ("langinfo not available, skipping O modifier tests");
1890 setlocale (LC_ALL, "gu_IN.utf-8");
1891 #ifdef HAVE_LANGINFO_OUTDIGIT
1892 if (strstr (setlocale (LC_ALL, NULL), "gu_IN") != NULL)
1894 TEST_PRINTF_TIME (23, 0, 0, "%OH", "૨૩"); /* '23' */
1895 TEST_PRINTF_TIME (23, 0, 0, "%OI", "૧૧"); /* '11' */
1896 TEST_PRINTF_TIME (23, 0, 0, "%OM", "૦૦"); /* '00' */
1898 TEST_PRINTF_DATE (2011, 7, 1, "%Om", "૦૭"); /* '07' */
1899 TEST_PRINTF_DATE (2011, 7, 1, "%0Om", "૦૭"); /* '07' */
1900 TEST_PRINTF_DATE (2011, 7, 1, "%-Om", "૭"); /* '7' */
1901 TEST_PRINTF_DATE (2011, 7, 1, "%_Om", " ૭"); /* ' 7' */
1904 g_test_skip ("locale gu_IN not available, skipping O modifier tests");
1906 g_test_skip ("langinfo not available, skipping O modifier tests");
1909 setlocale (LC_ALL, "en_GB.utf-8");
1910 if (strstr (setlocale (LC_ALL, NULL), "en_GB") != NULL)
1913 TEST_PRINTF_DATE (2009, 1, 1, "%c", "thu 01 jan 2009 00:00:00 utc");
1914 TEST_PRINTF_DATE (2009, 1, 1, "%Ec", "thu 01 jan 2009 00:00:00 utc");
1916 /* macOS uses a figure space (U+2007) to pad the day */
1917 TEST_PRINTF_DATE (2009, 1, 1, "%c", "thu " "\xe2\x80\x87" "1 jan 00:00:00 2009");
1918 TEST_PRINTF_DATE (2009, 1, 1, "%Ec", "thu " "\xe2\x80\x87" "1 jan 00:00:00 2009");
1921 TEST_PRINTF_DATE (2009, 1, 1, "%C", "20");
1922 TEST_PRINTF_DATE (2009, 1, 1, "%EC", "20");
1925 TEST_PRINTF_DATE (2009, 1, 2, "%x", "02/01/09");
1926 TEST_PRINTF_DATE (2009, 1, 2, "%Ex", "02/01/09");
1928 TEST_PRINTF_DATE (2009, 1, 2, "%x", "02/01/2009");
1929 TEST_PRINTF_DATE (2009, 1, 2, "%Ex", "02/01/2009");
1932 TEST_PRINTF_TIME (1, 2, 3, "%X", "01:02:03");
1933 TEST_PRINTF_TIME (1, 2, 3, "%EX", "01:02:03");
1935 TEST_PRINTF_DATE (2009, 1, 1, "%y", "09");
1936 TEST_PRINTF_DATE (2009, 1, 1, "%Ey", "09");
1938 TEST_PRINTF_DATE (2009, 1, 1, "%Y", "2009");
1939 TEST_PRINTF_DATE (2009, 1, 1, "%EY", "2009");
1942 g_test_skip ("locale en_GB not available, skipping E modifier tests");
1944 setlocale (LC_ALL, oldlocale);
1948 /* Test that the `O` modifier for g_date_time_format() works with %B, %b and %h;
1949 * i.e. whether genitive month names are supported. */
1951 test_month_names (void)
1955 g_test_bug ("http://bugzilla.gnome.org/749206");
1957 if (skip_if_running_uninstalled())
1960 oldlocale = g_strdup (setlocale (LC_ALL, NULL));
1962 /* Make sure that nothing has been changed in western European languages. */
1963 setlocale (LC_ALL, "en_GB.utf-8");
1964 if (strstr (setlocale (LC_ALL, NULL), "en_GB") != NULL)
1966 TEST_PRINTF_DATE (2018, 1, 1, "%B", "January");
1967 TEST_PRINTF_DATE (2018, 2, 1, "%OB", "February");
1968 TEST_PRINTF_DATE (2018, 3, 1, "%b", "Mar");
1969 TEST_PRINTF_DATE (2018, 4, 1, "%Ob", "Apr");
1970 TEST_PRINTF_DATE (2018, 5, 1, "%h", "May");
1971 TEST_PRINTF_DATE (2018, 6, 1, "%Oh", "Jun");
1974 g_test_skip ("locale en_GB not available, skipping English month names test");
1976 setlocale (LC_ALL, "de_DE.utf-8");
1977 if (strstr (setlocale (LC_ALL, NULL), "de_DE") != NULL)
1979 TEST_PRINTF_DATE (2018, 7, 1, "%B", "Juli");
1980 TEST_PRINTF_DATE (2018, 8, 1, "%OB", "August");
1981 TEST_PRINTF_DATE (2018, 9, 1, "%b", "Sep");
1982 TEST_PRINTF_DATE (2018, 10, 1, "%Ob", "Okt");
1983 TEST_PRINTF_DATE (2018, 11, 1, "%h", "Nov");
1984 TEST_PRINTF_DATE (2018, 12, 1, "%Oh", "Dez");
1987 g_test_skip ("locale de_DE not available, skipping German month names test");
1989 setlocale (LC_ALL, "es_ES.utf-8");
1990 if (strstr (setlocale (LC_ALL, NULL), "es_ES") != NULL)
1992 TEST_PRINTF_DATE (2018, 1, 1, "%B", "enero");
1993 TEST_PRINTF_DATE (2018, 2, 1, "%OB", "febrero");
1994 TEST_PRINTF_DATE (2018, 3, 1, "%b", "mar");
1995 TEST_PRINTF_DATE (2018, 4, 1, "%Ob", "abr");
1996 TEST_PRINTF_DATE (2018, 5, 1, "%h", "may");
1997 TEST_PRINTF_DATE (2018, 6, 1, "%Oh", "jun");
2000 g_test_skip ("locale es_ES not available, skipping Spanish month names test");
2002 setlocale (LC_ALL, "fr_FR.utf-8");
2003 if (strstr (setlocale (LC_ALL, NULL), "fr_FR") != NULL)
2005 TEST_PRINTF_DATE (2018, 7, 1, "%B", "juillet");
2006 TEST_PRINTF_DATE (2018, 8, 1, "%OB", "août");
2007 TEST_PRINTF_DATE (2018, 9, 1, "%b", "sept.");
2008 TEST_PRINTF_DATE (2018, 10, 1, "%Ob", "oct.");
2009 TEST_PRINTF_DATE (2018, 11, 1, "%h", "nov.");
2010 TEST_PRINTF_DATE (2018, 12, 1, "%Oh", "déc.");
2013 g_test_skip ("locale fr_FR not available, skipping French month names test");
2015 /* Make sure that there are visible changes in some European languages. */
2016 setlocale (LC_ALL, "el_GR.utf-8");
2017 if (strstr (setlocale (LC_ALL, NULL), "el_GR") != NULL)
2019 TEST_PRINTF_DATE (2018, 1, 1, "%B", "Ιανουαρίου");
2020 TEST_PRINTF_DATE (2018, 2, 1, "%B", "Φεβρουαρίου");
2021 TEST_PRINTF_DATE (2018, 3, 1, "%B", "Μαρτίου");
2022 TEST_PRINTF_DATE (2018, 4, 1, "%OB", "Απρίλιος");
2023 TEST_PRINTF_DATE (2018, 5, 1, "%OB", "Μάιος");
2024 TEST_PRINTF_DATE (2018, 6, 1, "%OB", "Ιούνιος");
2025 TEST_PRINTF_DATE (2018, 7, 1, "%b", "Ιουλ");
2026 TEST_PRINTF_DATE (2018, 8, 1, "%Ob", "Αύγ");
2029 g_test_skip ("locale el_GR not available, skipping Greek month names test");
2031 setlocale (LC_ALL, "hr_HR.utf-8");
2032 if (strstr (setlocale (LC_ALL, NULL), "hr_HR") != NULL)
2034 TEST_PRINTF_DATE (2018, 5, 1, "%B", "svibnja");
2035 TEST_PRINTF_DATE (2018, 6, 1, "%B", "lipnja");
2036 TEST_PRINTF_DATE (2018, 7, 1, "%B", "srpnja");
2037 TEST_PRINTF_DATE (2018, 8, 1, "%OB", "Kolovoz");
2038 TEST_PRINTF_DATE (2018, 9, 1, "%OB", "Rujan");
2039 TEST_PRINTF_DATE (2018, 10, 1, "%OB", "Listopad");
2040 TEST_PRINTF_DATE (2018, 11, 1, "%b", "Stu");
2041 TEST_PRINTF_DATE (2018, 12, 1, "%Ob", "Pro");
2044 g_test_skip ("locale hr_HR not available, skipping Croatian month names test");
2046 setlocale (LC_ALL, "lt_LT.utf-8");
2047 if (strstr (setlocale (LC_ALL, NULL), "lt_LT") != NULL)
2049 TEST_PRINTF_DATE (2018, 1, 1, "%B", "sausio");
2050 TEST_PRINTF_DATE (2018, 2, 1, "%B", "vasario");
2051 TEST_PRINTF_DATE (2018, 3, 1, "%B", "kovo");
2052 TEST_PRINTF_DATE (2018, 4, 1, "%OB", "balandis");
2053 TEST_PRINTF_DATE (2018, 5, 1, "%OB", "gegužė");
2054 TEST_PRINTF_DATE (2018, 6, 1, "%OB", "birželis");
2055 TEST_PRINTF_DATE (2018, 7, 1, "%b", "liep.");
2056 TEST_PRINTF_DATE (2018, 8, 1, "%Ob", "rugp.");
2059 g_test_skip ("locale lt_LT not available, skipping Lithuanian month names test");
2061 setlocale (LC_ALL, "pl_PL.utf-8");
2062 if (strstr (setlocale (LC_ALL, NULL), "pl_PL") != NULL)
2064 TEST_PRINTF_DATE (2018, 5, 1, "%B", "maja");
2065 TEST_PRINTF_DATE (2018, 6, 1, "%B", "czerwca");
2066 TEST_PRINTF_DATE (2018, 7, 1, "%B", "lipca");
2067 TEST_PRINTF_DATE (2018, 8, 1, "%OB", "sierpień");
2068 TEST_PRINTF_DATE (2018, 9, 1, "%OB", "wrzesień");
2069 TEST_PRINTF_DATE (2018, 10, 1, "%OB", "październik");
2070 TEST_PRINTF_DATE (2018, 11, 1, "%b", "lis");
2071 TEST_PRINTF_DATE (2018, 12, 1, "%Ob", "gru");
2074 g_test_skip ("locale pl_PL not available, skipping Polish month names test");
2076 setlocale (LC_ALL, "ru_RU.utf-8");
2077 if (strstr (setlocale (LC_ALL, NULL), "ru_RU") != NULL)
2079 TEST_PRINTF_DATE (2018, 1, 1, "%B", "января");
2080 TEST_PRINTF_DATE (2018, 2, 1, "%B", "февраля");
2081 TEST_PRINTF_DATE (2018, 3, 1, "%B", "марта");
2082 TEST_PRINTF_DATE (2018, 4, 1, "%OB", "Апрель");
2083 TEST_PRINTF_DATE (2018, 5, 1, "%OB", "Май");
2084 TEST_PRINTF_DATE (2018, 6, 1, "%OB", "Июнь");
2085 TEST_PRINTF_DATE (2018, 7, 1, "%b", "июл");
2086 TEST_PRINTF_DATE (2018, 8, 1, "%Ob", "авг");
2087 /* This difference is very important in Russian: */
2088 TEST_PRINTF_DATE (2018, 5, 1, "%b", "мая");
2089 TEST_PRINTF_DATE (2018, 5, 1, "%Ob", "май");
2092 g_test_skip ("locale ru_RU not available, skipping Russian month names test");
2094 setlocale (LC_ALL, oldlocale);
2099 test_GDateTime_dst (void)
2101 GDateTime *dt1, *dt2;
2104 /* this date has the DST state set for Europe/London */
2106 tz = g_time_zone_new_identifier ("Europe/London");
2107 #elif defined G_OS_WIN32
2108 tz = g_time_zone_new_identifier ("GMT Standard Time");
2110 g_assert_nonnull (tz);
2111 dt1 = g_date_time_new (tz, 2009, 8, 15, 3, 0, 1);
2112 g_assert (g_date_time_is_daylight_savings (dt1));
2113 g_assert_cmpint (g_date_time_get_utc_offset (dt1) / G_USEC_PER_SEC, ==, 3600);
2114 g_assert_cmpint (g_date_time_get_hour (dt1), ==, 3);
2116 /* add 6 months to clear the DST flag but keep the same time */
2117 dt2 = g_date_time_add_months (dt1, 6);
2118 g_assert (!g_date_time_is_daylight_savings (dt2));
2119 g_assert_cmpint (g_date_time_get_utc_offset (dt2) / G_USEC_PER_SEC, ==, 0);
2120 g_assert_cmpint (g_date_time_get_hour (dt2), ==, 3);
2122 g_date_time_unref (dt2);
2123 g_date_time_unref (dt1);
2125 /* now do the reverse: start with a non-DST state and move to DST */
2126 dt1 = g_date_time_new (tz, 2009, 2, 15, 2, 0, 1);
2127 g_assert (!g_date_time_is_daylight_savings (dt1));
2128 g_assert_cmpint (g_date_time_get_hour (dt1), ==, 2);
2130 dt2 = g_date_time_add_months (dt1, 6);
2131 g_assert (g_date_time_is_daylight_savings (dt2));
2132 g_assert_cmpint (g_date_time_get_hour (dt2), ==, 2);
2134 g_date_time_unref (dt2);
2135 g_date_time_unref (dt1);
2136 g_time_zone_unref (tz);
2139 static inline gboolean
2140 is_leap_year (gint year)
2142 g_assert (1 <= year && year <= 9999);
2144 return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
2148 days_in_month (gint year, gint month)
2150 const gint table[2][13] = {
2151 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
2152 {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
2155 g_assert (1 <= month && month <= 12);
2157 return table[is_leap_year (year)][month];
2161 test_all_dates (void)
2163 gint year, month, day;
2164 GTimeZone *timezone;
2171 /* save some time by hanging on to this. */
2172 timezone = g_time_zone_new_utc ();
2174 unix_time = G_GINT64_CONSTANT(-62135596800);
2176 /* 0001-01-01 is 0001-W01-1 */
2182 /* The calendar makes a full cycle every 400 years, so we could
2183 * theoretically just test years 1 through 400. That assumes that our
2184 * software has no bugs, so probably we should just test them all. :)
2186 for (year = 1; year <= 9999; year++)
2190 for (month = 1; month <= 12; month++)
2191 for (day = 1; day <= days_in_month (year, month); day++)
2195 dt = g_date_time_new (timezone, year, month, day, 0, 0, 0);
2198 g_test_message ("%04d-%02d-%02d = %04d-W%02d-%d = %04d-%03d",
2200 week_year, week_num, weekday,
2205 if G_UNLIKELY (g_date_time_get_year (dt) != year ||
2206 g_date_time_get_month (dt) != month ||
2207 g_date_time_get_day_of_month (dt) != day)
2208 g_error ("%04d-%02d-%02d comes out as %04d-%02d-%02d",
2210 g_date_time_get_year (dt),
2211 g_date_time_get_month (dt),
2212 g_date_time_get_day_of_month (dt));
2214 if G_UNLIKELY (g_date_time_get_week_numbering_year (dt) != week_year ||
2215 g_date_time_get_week_of_year (dt) != week_num ||
2216 g_date_time_get_day_of_week (dt) != weekday)
2217 g_error ("%04d-%02d-%02d should be %04d-W%02d-%d but "
2218 "comes out as %04d-W%02d-%d", year, month, day,
2219 week_year, week_num, weekday,
2220 g_date_time_get_week_numbering_year (dt),
2221 g_date_time_get_week_of_year (dt),
2222 g_date_time_get_day_of_week (dt));
2224 if G_UNLIKELY (g_date_time_to_unix (dt) != unix_time)
2225 g_error ("%04d-%02d-%02d 00:00:00 UTC should have unix time %"
2226 G_GINT64_FORMAT " but comes out as %"G_GINT64_FORMAT,
2227 year, month, day, unix_time, g_date_time_to_unix (dt));
2229 if G_UNLIKELY (g_date_time_get_day_of_year (dt) != day_of_year)
2230 g_error ("%04d-%02d-%02d should be day of year %d"
2231 " but comes out as %d", year, month, day,
2232 day_of_year, g_date_time_get_day_of_year (dt));
2234 if G_UNLIKELY (g_date_time_get_hour (dt) != 0 ||
2235 g_date_time_get_minute (dt) != 0 ||
2236 g_date_time_get_seconds (dt) != 0)
2237 g_error ("%04d-%02d-%02d 00:00:00 UTC comes out "
2238 "as %02d:%02d:%02.6f", year, month, day,
2239 g_date_time_get_hour (dt),
2240 g_date_time_get_minute (dt),
2241 g_date_time_get_seconds (dt));
2244 /* add 24 hours to unix time */
2245 unix_time += 24 * 60 * 60;
2247 /* move day of year forward */
2250 /* move the week date forward */
2253 weekday = 1; /* Sunday -> Monday */
2255 /* NOTE: year/month/day is the final day of the week we
2258 * If we just finished the last week of last year then
2259 * we are definitely starting the first week of this
2262 * Otherwise, if we're still in this year, but Sunday
2263 * fell on or after December 28 then December 29, 30, 31
2264 * could be days within the next year's first year.
2266 if (year != week_year || (month == 12 && day >= 28))
2268 /* first week of the new year */
2276 g_date_time_unref (dt);
2280 g_time_zone_unref (timezone);
2284 test_date_time_eras_japan (void)
2286 #if defined(HAVE_LANGINFO_ERA) && (G_BYTE_ORDER == G_LITTLE_ENDIAN || GLIB_SIZEOF_VOID_P == 4)
2289 oldlocale = g_strdup (setlocale (LC_ALL, NULL));
2290 setlocale (LC_ALL, "ja_JP.utf-8");
2291 if (strstr (setlocale (LC_ALL, NULL), "ja_JP") == NULL)
2293 g_test_skip ("locale ja_JP.utf-8 not available, skipping Japanese era tests");
2298 /* See https://en.wikipedia.org/wiki/Japanese_era_name
2299 * First test the Reiwa era (令和) */
2300 TEST_PRINTF_DATE (2023, 06, 01, "%Ec", "令和05年06月01日 00時00分00秒");
2301 TEST_PRINTF_DATE (2023, 06, 01, "%EC", "令和");
2302 TEST_PRINTF_DATE (2023, 06, 01, "%Ex", "令和05年06月01日");
2303 TEST_PRINTF_DATE (2023, 06, 01, "%EX", "00時00分00秒");
2304 TEST_PRINTF_DATE (2023, 06, 01, "%Ey", "05");
2305 TEST_PRINTF_DATE (2023, 06, 01, "%EY", "令和05年");
2307 /* Heisei era (平成) */
2308 TEST_PRINTF_DATE (2019, 04, 30, "%Ec", "平成31年04月30日 00時00分00秒");
2309 TEST_PRINTF_DATE (2019, 04, 30, "%EC", "平成");
2310 TEST_PRINTF_DATE (2019, 04, 30, "%Ex", "平成31年04月30日");
2311 TEST_PRINTF_DATE (2019, 04, 30, "%EX", "00時00分00秒");
2312 TEST_PRINTF_DATE (2019, 04, 30, "%Ey", "31");
2313 TEST_PRINTF_DATE (2019, 04, 30, "%EY", "平成31年");
2315 /* Shōwa era (昭和) */
2316 TEST_PRINTF_DATE (1926, 12, 25, "%Ec", "昭和元年12月25日 00時00分00秒");
2317 TEST_PRINTF_DATE (1926, 12, 25, "%EC", "昭和");
2318 TEST_PRINTF_DATE (1926, 12, 25, "%Ex", "昭和元年12月25日");
2319 TEST_PRINTF_DATE (1926, 12, 25, "%EX", "00時00分00秒");
2320 TEST_PRINTF_DATE (1926, 12, 25, "%Ey", "01");
2321 TEST_PRINTF_DATE (1926, 12, 25, "%EY", "昭和元年");
2323 setlocale (LC_ALL, oldlocale);
2326 g_test_skip ("nl_langinfo(ERA) not supported, skipping era tests");
2331 test_date_time_eras_thailand (void)
2333 #if defined(HAVE_LANGINFO_ERA) && (G_BYTE_ORDER == G_LITTLE_ENDIAN || GLIB_SIZEOF_VOID_P == 4)
2336 oldlocale = g_strdup (setlocale (LC_ALL, NULL));
2337 setlocale (LC_ALL, "th_TH.utf-8");
2338 if (strstr (setlocale (LC_ALL, NULL), "th_TH") == NULL)
2340 g_test_skip ("locale th_TH.utf-8 not available, skipping Thai era tests");
2345 /* See https://en.wikipedia.org/wiki/Thai_solar_calendar */
2346 TEST_PRINTF_DATE (2023, 06, 01, "%Ec", "วันพฤหัสบดีที่ 1 มิถุนายน พ.ศ. 2566, 00.00.00 น.");
2347 TEST_PRINTF_DATE (2023, 06, 01, "%EC", "พ.ศ.");
2348 TEST_PRINTF_DATE (2023, 06, 01, "%Ex", " 1 มิ.ย. 2566");
2349 TEST_PRINTF_DATE (2023, 06, 01, "%EX", "00.00.00 น.");
2350 TEST_PRINTF_DATE (2023, 06, 01, "%Ey", "2566");
2351 TEST_PRINTF_DATE (2023, 06, 01, "%EY", "พ.ศ. 2566");
2353 TEST_PRINTF_DATE (01, 06, 01, "%Ex", " 1 มิ.ย. 544");
2355 setlocale (LC_ALL, oldlocale);
2358 g_test_skip ("nl_langinfo(ERA) not supported, skipping era tests");
2363 test_date_time_eras_parsing (void)
2368 gboolean expected_success;
2369 size_t expected_n_segments;
2373 /* Some successful parsing: */
2375 /* From https://github.com/bminor/glibc/blob/9fd3409842b3e2d31cff5dbd6f96066c430f0aa2/localedata/locales/th_TH#L233: */
2376 { "+:1:-543/01/01:+*:พ.ศ.:%EC %Ey", TRUE, 1 },
2377 /* From https://github.com/bminor/glibc/blob/9fd3409842b3e2d31cff5dbd6f96066c430f0aa2/localedata/locales/ja_JP#L14967C5-L14977C60: */
2378 { "+:2:2020/01/01:+*:令和:%EC%Ey年;"
2379 "+:1:2019/05/01:2019/12/31:令和:%EC元年;"
2380 "+:2:1990/01/01:2019/04/30:平成:%EC%Ey年;"
2381 "+:1:1989/01/08:1989/12/31:平成:%EC元年;"
2382 "+:2:1927/01/01:1989/01/07:昭和:%EC%Ey年;"
2383 "+:1:1926/12/25:1926/12/31:昭和:%EC元年;"
2384 "+:2:1913/01/01:1926/12/24:大正:%EC%Ey年;"
2385 "+:1:1912/07/30:1912/12/31:大正:%EC元年;"
2386 "+:6:1873/01/01:1912/07/29:明治:%EC%Ey年;"
2387 "+:1:0001/01/01:1872/12/31:西暦:%EC%Ey年;"
2388 "+:1:-0001/12/31:-*:紀元前:%EC%Ey年", TRUE, 11 },
2389 { "-:2:2020/01/01:-*:令和:%EC%Ey年", TRUE, 1 },
2390 { "+:2:2020/01/01:2020/01/01:令和:%EC%Ey年", TRUE, 1 },
2391 { "+:2:+2020/01/01:+*:令和:%EC%Ey年", TRUE, 1 },
2393 { ".:2:2020/01/01:+*:令和:%EC%Ey年", FALSE, 0 },
2394 { "+.2:2020/01/01:+*:令和:%EC%Ey年", FALSE, 0 },
2397 { "+::", FALSE, 0 },
2398 { "+:200", FALSE, 0 },
2399 { "+:2nonsense", FALSE, 0 },
2400 { "+:2nonsense:", FALSE, 0 },
2401 { "+:2:", FALSE, 0 },
2402 { "+:2::", FALSE, 0 },
2403 { "+:2:2020-01/01:+*:令和:%EC%Ey年", FALSE, 0 },
2404 { "+:2:2020nonsense/01/01:+*:令和:%EC%Ey年", FALSE, 0 },
2405 { "+:2:2020:+*:令和:%EC%Ey年", FALSE, 0 },
2406 { "+:2:18446744073709551615/01/01:+*:令和:%EC%Ey年", FALSE, 0 },
2407 { "+:2:2020/01-01:+*:令和:%EC%Ey年", FALSE, 0 },
2408 { "+:2:2020/01nonsense/01:+*:令和:%EC%Ey年", FALSE, 0 },
2409 { "+:2:2020/01:+*:令和:%EC%Ey年", FALSE, 0 },
2410 { "+:2:2020/00/01:+*:令和:%EC%Ey年", FALSE, 0 },
2411 { "+:2:2020/13/01:+*:令和:%EC%Ey年", FALSE, 0 },
2412 { "+:2:2020/01/00:+*:令和:%EC%Ey年", FALSE, 0 },
2413 { "+:2:2020/01/32:+*:令和:%EC%Ey年", FALSE, 0 },
2414 { "+:2:2020/01/01nonsense:+*:令和:%EC%Ey年", FALSE, 0 },
2415 { "+:2:2020/01/01", FALSE, 0 },
2416 { "+:2:2020/01/01:", FALSE, 0 },
2417 { "+:2:2020/01/01::", FALSE, 0 },
2418 { "+:2:2020/01/01:2021-01-01:令和:%EC%Ey年", FALSE, 0 },
2419 { "+:2:2020/01/01:+*", FALSE, 0 },
2420 { "+:2:2020/01/01:+*:", FALSE, 0 },
2421 { "+:2:2020/01/01:+*::", FALSE, 0 },
2422 { "+:2:2020/01/01:+*:令和", FALSE, 0 },
2423 { "+:2:2020/01/01:+*:令和:", FALSE, 0 },
2424 { "+:2:2020/01/01:+*:令和:;", FALSE, 0 },
2427 for (size_t i = 0; i < G_N_ELEMENTS (vectors); i++)
2429 GPtrArray *segments = NULL;
2431 g_test_message ("Vector %" G_GSIZE_FORMAT ": %s", i, vectors[i].desc);
2433 segments = _g_era_description_parse (vectors[i].desc);
2435 if (vectors[i].expected_success)
2437 g_assert_nonnull (segments);
2438 g_assert_cmpuint (segments->len, ==, vectors[i].expected_n_segments);
2442 g_assert_null (segments);
2445 g_clear_pointer (&segments, g_ptr_array_unref);
2456 g_test_bug ("http://bugzilla.gnome.org/642935");
2458 tz = g_time_zone_new_identifier ("-08:00");
2459 g_assert_nonnull (tz);
2460 dt = g_date_time_new (tz, 1, 1, 1, 0, 0, 0);
2462 p = g_date_time_format (dt, "%z");
2463 g_assert_cmpstr (p, ==, "-0800");
2466 p = g_date_time_format (dt, "%:z");
2467 g_assert_cmpstr (p, ==, "-08:00");
2470 p = g_date_time_format (dt, "%::z");
2471 g_assert_cmpstr (p, ==, "-08:00:00");
2474 p = g_date_time_format (dt, "%:::z");
2475 g_assert_cmpstr (p, ==, "-08");
2478 g_date_time_unref (dt);
2479 g_time_zone_unref (tz);
2481 tz = g_time_zone_new_identifier ("+00:00");
2482 g_assert_nonnull (tz);
2483 dt = g_date_time_new (tz, 1, 1, 1, 0, 0, 0);
2484 p = g_date_time_format (dt, "%:::z");
2485 g_assert_cmpstr (p, ==, "+00");
2487 g_date_time_unref (dt);
2488 g_time_zone_unref (tz);
2490 tz = g_time_zone_new_identifier ("+08:23");
2491 g_assert_nonnull (tz);
2492 dt = g_date_time_new (tz, 1, 1, 1, 0, 0, 0);
2493 p = g_date_time_format (dt, "%:::z");
2494 g_assert_cmpstr (p, ==, "+08:23");
2496 g_date_time_unref (dt);
2497 g_time_zone_unref (tz);
2499 tz = g_time_zone_new_identifier ("+08:23:45");
2500 g_assert_nonnull (tz);
2501 dt = g_date_time_new (tz, 1, 1, 1, 0, 0, 0);
2502 p = g_date_time_format (dt, "%:::z");
2503 g_assert_cmpstr (p, ==, "+08:23:45");
2505 g_date_time_unref (dt);
2506 g_time_zone_unref (tz);
2508 tz = g_time_zone_new_identifier ("-00:15");
2509 g_assert_nonnull (tz);
2510 dt = g_date_time_new (tz, 1, 1, 1, 0, 0, 0);
2512 p = g_date_time_format (dt, "%z");
2513 g_assert_cmpstr (p, ==, "-0015");
2516 p = g_date_time_format (dt, "%:z");
2517 g_assert_cmpstr (p, ==, "-00:15");
2520 p = g_date_time_format (dt, "%::z");
2521 g_assert_cmpstr (p, ==, "-00:15:00");
2524 p = g_date_time_format (dt, "%:::z");
2525 g_assert_cmpstr (p, ==, "-00:15");
2528 g_date_time_unref (dt);
2529 g_time_zone_unref (tz);
2533 test_6_days_until_end_of_the_month (void)
2539 g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2215");
2542 /* This is the footertz string from `Europe/Paris` from tzdata 2020b. It’s
2543 * used by GLib when the tzdata file was compiled with `zic -b slim`, which is
2544 * the default in tzcode ≥2020b.
2546 * The `M10.5.0` part indicates that the summer time end transition happens on
2547 * the Sunday (`0`) in the last week (`5`) of October (`10`). That’s 6 days
2548 * before the end of the month, and hence was triggering issue #2215.
2551 * - https://tools.ietf.org/id/draft-murchison-tzdist-tzif-15.html#rfc.section.3.3
2552 * - https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03
2554 tz = g_time_zone_new_identifier ("CET-1CEST,M3.5.0,M10.5.0/3");
2555 #elif defined (G_OS_WIN32)
2556 tz = g_time_zone_new_identifier ("Romance Standard Time");
2558 g_assert_nonnull (tz);
2559 dt = g_date_time_new (tz, 2020, 10, 5, 1, 1, 1);
2561 p = g_date_time_format (dt, "%Y-%m-%d %H:%M:%S%z");
2562 /* Incorrect output is "2020-10-05 01:01:01+0100" */
2563 g_assert_cmpstr (p, ==, "2020-10-05 01:01:01+0200");
2566 g_date_time_unref (dt);
2567 g_time_zone_unref (tz);
2571 test_format_iso8601 (void)
2573 GTimeZone *tz = NULL;
2574 GDateTime *dt = NULL;
2577 tz = g_time_zone_new_utc ();
2578 dt = g_date_time_new (tz, 2019, 6, 26, 15, 1, 5);
2579 p = g_date_time_format_iso8601 (dt);
2580 g_assert_cmpstr (p, ==, "2019-06-26T15:01:05Z");
2582 g_date_time_unref (dt);
2583 g_time_zone_unref (tz);
2585 tz = g_time_zone_new_offset (-60 * 60);
2586 dt = g_date_time_new (tz, 2019, 6, 26, 15, 1, 5);
2587 p = g_date_time_format_iso8601 (dt);
2588 g_assert_cmpstr (p, ==, "2019-06-26T15:01:05-01");
2590 g_date_time_unref (dt);
2591 g_time_zone_unref (tz);
2593 tz = g_time_zone_new_utc ();
2594 dt = g_date_time_new (tz, 2020, 8, 5, 12, 30, 55.000001);
2595 p = g_date_time_format_iso8601 (dt);
2596 g_assert_cmpstr (p, ==, "2020-08-05T12:30:55.000001Z");
2598 g_date_time_unref (dt);
2599 g_time_zone_unref (tz);
2601 tz = g_time_zone_new_utc ();
2602 dt = g_date_time_new (tz, 9, 1, 2, 3, 4, 55);
2603 p = g_date_time_format_iso8601 (dt);
2604 g_assert_cmpstr (p, ==, "0009-01-02T03:04:55Z");
2606 g_date_time_unref (dt);
2607 g_time_zone_unref (tz);
2609 tz = g_time_zone_new_utc ();
2610 dt = g_date_time_new (tz, 9990, 1, 2, 3, 4, 55.000001);
2611 p = g_date_time_format_iso8601 (dt);
2612 g_assert_cmpstr (p, ==, "9990-01-02T03:04:55.000001Z");
2614 g_date_time_unref (dt);
2615 g_time_zone_unref (tz);
2620 gboolean utf8_messages;
2622 } MixedUtf8TestData;
2624 static const MixedUtf8TestData utf8_time_non_utf8_messages = {
2625 .utf8_messages = FALSE,
2629 static const MixedUtf8TestData non_utf8_time_utf8_messages = {
2630 .utf8_messages = TRUE,
2634 static const MixedUtf8TestData utf8_time_utf8_messages = {
2635 .utf8_messages = TRUE,
2639 static const MixedUtf8TestData non_utf8_time_non_utf8_messages = {
2640 .utf8_messages = FALSE,
2645 check_and_set_locale (int category,
2648 setlocale (category, name);
2649 if (strstr (setlocale (category, NULL), name) == NULL)
2651 g_test_message ("Unavailable '%s' locale", name);
2652 g_test_skip ("required locale not available, skipping tests");
2659 test_format_time_mixed_utf8 (gconstpointer data)
2662 g_test_skip ("setlocale (LC_MESSAGES) asserts on ucrt");
2664 const MixedUtf8TestData *test_data;
2665 gchar *old_time_locale;
2666 gchar *old_messages_locale;
2667 g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2055");
2669 test_data = (MixedUtf8TestData *) data;
2670 old_time_locale = g_strdup (setlocale (LC_TIME, NULL));
2671 old_messages_locale = g_strdup (setlocale (LC_MESSAGES, NULL));
2672 if (test_data->utf8_time)
2674 if (!check_and_set_locale (LC_TIME, "C.UTF-8"))
2676 g_free (old_time_locale);
2677 setlocale (LC_MESSAGES, old_messages_locale);
2678 g_free (old_messages_locale);
2684 if (!check_and_set_locale (LC_TIME, "de_DE.iso88591"))
2686 g_free (old_time_locale);
2687 setlocale (LC_MESSAGES, old_messages_locale);
2688 g_free (old_messages_locale);
2692 if (test_data->utf8_messages)
2694 if (!check_and_set_locale (LC_MESSAGES, "C.UTF-8"))
2696 g_free (old_messages_locale);
2697 setlocale (LC_TIME, old_time_locale);
2698 g_free (old_time_locale);
2704 if (!check_and_set_locale (LC_MESSAGES, "de_DE.iso88591"))
2706 g_free (old_messages_locale);
2707 setlocale (LC_TIME, old_time_locale);
2708 g_free (old_time_locale);
2713 if (!test_data->utf8_time)
2715 /* March to have März in german */
2716 TEST_PRINTF_DATE (2020, 3, 1, "%b", "Mär");
2717 TEST_PRINTF_DATE (2020, 3, 1, "%B", "März");
2721 TEST_PRINTF_DATE (2020, 3, 1, "%b", "mar");
2722 TEST_PRINTF_DATE (2020, 3, 1, "%B", "march");
2725 setlocale (LC_TIME, old_time_locale);
2726 setlocale (LC_MESSAGES, old_messages_locale);
2727 g_free (old_time_locale);
2728 g_free (old_messages_locale);
2734 str_utf8_replace (const gchar *str,
2738 GString *str_out = g_string_new ("");
2740 for (; *str != '\0'; str = g_utf8_next_char (str))
2742 gunichar c = g_utf8_get_char (str);
2743 g_string_append_unichar (str_out, (c == from) ? to : c);
2746 return g_string_free (g_steal_pointer (&str_out), FALSE);
2750 #pragma GCC diagnostic push
2751 #pragma GCC diagnostic ignored "-Wformat-y2k"
2753 test_strftime (void)
2756 #define TEST_FORMAT \
2757 "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 " \
2758 "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 %%"
2761 /* 127997 is prime, 1315005118 is now */
2762 for (t = 0; t < 1315005118; t += 127997)
2764 GDateTime *date_time;
2767 gchar *dt_str_replaced = NULL, *c_str_replaced = NULL;
2769 date_time = g_date_time_new_from_unix_local (t);
2770 dt_str = g_date_time_format (date_time, TEST_FORMAT);
2771 strftime (c_str, sizeof c_str, TEST_FORMAT, localtime (&t));
2773 /* Ensure the comparison is done insensitively to spaces.
2774 * g_date_time_format() sometimes uses figure spaces (U+2007) whereas
2775 * strftime() currently doesn’t, and that’s fine. */
2776 dt_str_replaced = str_utf8_replace (dt_str, 0x2007, 0x20);
2777 c_str_replaced = str_utf8_replace (c_str, 0x2007, 0x20);
2779 g_assert_cmpstr (c_str_replaced, ==, dt_str_replaced);
2781 g_date_time_unref (date_time);
2783 g_free (dt_str_replaced);
2784 g_free (c_str_replaced);
2788 #pragma GCC diagnostic pop
2790 /* Check that g_date_time_format() correctly returns %NULL for format
2791 * placeholders which are not supported in the current locale. */
2793 test_GDateTime_strftime_error_handling (void)
2800 if (skip_if_running_uninstalled())
2804 old_lcid = GetThreadLocale ();
2805 SetThreadLocale (MAKELCID (MAKELANGID (LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT));
2808 oldlocale = g_strdup (setlocale (LC_ALL, NULL));
2809 setlocale (LC_ALL, "de_DE.utf-8");
2810 if (strstr (setlocale (LC_ALL, NULL), "de_DE") != NULL)
2812 /* de_DE doesn’t ever write time in 12-hour notation, so %r is
2813 * unsupported for it. */
2814 TEST_PRINTF_TIME (23, 0, 0, "%r", NULL);
2817 g_test_skip ("locale de_DE not available, skipping error handling tests");
2818 setlocale (LC_ALL, oldlocale);
2822 SetThreadLocale (old_lcid);
2827 test_find_interval (void)
2835 tz = g_time_zone_new_identifier ("America/Toronto");
2836 #elif defined G_OS_WIN32
2837 tz = g_time_zone_new_identifier ("Eastern Standard Time");
2839 g_assert_nonnull (tz);
2840 dt = g_date_time_new_utc (2010, 11, 7, 1, 30, 0);
2841 u = g_date_time_to_unix (dt);
2843 i1 = g_time_zone_find_interval (tz, G_TIME_TYPE_STANDARD, u);
2844 i2 = g_time_zone_find_interval (tz, G_TIME_TYPE_DAYLIGHT, u);
2846 g_assert_cmpint (i1, !=, i2);
2848 g_date_time_unref (dt);
2850 dt = g_date_time_new_utc (2010, 3, 14, 2, 0, 0);
2851 u = g_date_time_to_unix (dt);
2853 i1 = g_time_zone_find_interval (tz, G_TIME_TYPE_STANDARD, u);
2854 g_assert_cmpint (i1, ==, -1);
2856 g_date_time_unref (dt);
2857 g_time_zone_unref (tz);
2861 test_adjust_time (void)
2869 tz = g_time_zone_new_identifier ("America/Toronto");
2870 #elif defined G_OS_WIN32
2871 tz = g_time_zone_new_identifier ("Eastern Standard Time");
2873 g_assert_nonnull (tz);
2874 dt = g_date_time_new_utc (2010, 11, 7, 1, 30, 0);
2875 u = g_date_time_to_unix (dt);
2878 i1 = g_time_zone_find_interval (tz, G_TIME_TYPE_DAYLIGHT, u);
2879 i2 = g_time_zone_adjust_time (tz, G_TIME_TYPE_DAYLIGHT, &u2);
2881 g_assert_cmpint (i1, ==, i2);
2884 g_date_time_unref (dt);
2886 dt = g_date_time_new_utc (2010, 3, 14, 2, 30, 0);
2887 u2 = g_date_time_to_unix (dt);
2888 g_date_time_unref (dt);
2890 dt = g_date_time_new_utc (2010, 3, 14, 3, 0, 0);
2891 u = g_date_time_to_unix (dt);
2892 g_date_time_unref (dt);
2894 i1 = g_time_zone_adjust_time (tz, G_TIME_TYPE_DAYLIGHT, &u2);
2895 g_assert_cmpint (i1, >=, 0);
2898 g_time_zone_unref (tz);
2902 test_no_header (void)
2906 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
2907 tz = g_time_zone_new ("blabla");
2908 G_GNUC_END_IGNORE_DEPRECATIONS
2910 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
2911 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "UTC");
2912 g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 0);
2913 g_assert (!g_time_zone_is_dst (tz, 0));
2915 g_time_zone_unref (tz);
2919 test_no_header_identifier (void)
2923 tz = g_time_zone_new_identifier ("blabla");
2929 test_posix_parse (void)
2932 GDateTime *gdt1, *gdt2;
2934 /* Check that an unknown zone name falls back to UTC. */
2935 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
2936 tz = g_time_zone_new ("nonexistent");
2937 G_GNUC_END_IGNORE_DEPRECATIONS
2938 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
2939 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "UTC");
2940 g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 0);
2941 g_assert (!g_time_zone_is_dst (tz, 0));
2942 g_time_zone_unref (tz);
2944 /* An existent zone name should not fall back to UTC. */
2945 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
2946 tz = g_time_zone_new ("PST8");
2947 G_GNUC_END_IGNORE_DEPRECATIONS
2948 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "PST8");
2949 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "PST");
2950 g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, - 8 * 3600);
2951 g_assert (!g_time_zone_is_dst (tz, 0));
2952 g_time_zone_unref (tz);
2954 /* This fails rules_from_identifier on Unix (though not on Windows)
2955 * but passes anyway because PST8PDT is a zone name.
2957 tz = g_time_zone_new_identifier ("PST8PDT");
2958 g_assert_nonnull (tz);
2959 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "PST8PDT");
2960 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "PST");
2961 g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, - 8 * 3600);
2962 g_assert (!g_time_zone_is_dst (tz, 0));
2963 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "PDT");
2964 g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==,- 7 * 3600);
2965 g_assert (g_time_zone_is_dst (tz, 1));
2966 g_time_zone_unref (tz);
2968 tz = g_time_zone_new_identifier ("PST8PDT6:32:15");
2970 g_assert_nonnull (tz);
2971 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "PST8PDT6:32:15");
2972 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "PST");
2973 g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, - 8 * 3600);
2974 g_assert (!g_time_zone_is_dst (tz, 0));
2975 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "PDT");
2976 g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, - 6 * 3600 - 32 *60 - 15);
2977 g_assert (g_time_zone_is_dst (tz, 1));
2978 gdt1 = g_date_time_new (tz, 2012, 12, 6, 11, 15, 23.0);
2979 gdt2 = g_date_time_new (tz, 2012, 6, 6, 11, 15, 23.0);
2980 g_assert (!g_date_time_is_daylight_savings (gdt1));
2981 g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, -28800);
2982 g_assert (g_date_time_is_daylight_savings (gdt2));
2983 g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, -23535);
2984 g_date_time_unref (gdt1);
2985 g_date_time_unref (gdt2);
2989 g_clear_pointer (&tz, g_time_zone_unref);
2991 tz = g_time_zone_new_identifier ("NZST-12:00:00NZDT-13:00:00,M10.1.0,M3.3.0");
2992 g_assert_nonnull (tz);
2993 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "NZST-12:00:00NZDT-13:00:00,M10.1.0,M3.3.0");
2994 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "NZST");
2995 g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 12 * 3600);
2996 g_assert (!g_time_zone_is_dst (tz, 0));
2997 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "NZDT");
2998 g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, 13 * 3600);
2999 g_assert (g_time_zone_is_dst (tz, 1));
3000 gdt1 = g_date_time_new (tz, 2012, 3, 18, 0, 15, 23.0);
3001 gdt2 = g_date_time_new (tz, 2012, 3, 18, 3, 15, 23.0);
3002 g_assert (g_date_time_is_daylight_savings (gdt1));
3003 g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
3004 g_assert (!g_date_time_is_daylight_savings (gdt2));
3005 g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
3006 g_date_time_unref (gdt1);
3007 g_date_time_unref (gdt2);
3008 gdt1 = g_date_time_new (tz, 2012, 10, 7, 3, 15, 23.0);
3009 gdt2 = g_date_time_new (tz, 2012, 10, 7, 1, 15, 23.0);
3010 g_assert (g_date_time_is_daylight_savings (gdt1));
3011 g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
3012 g_assert (!g_date_time_is_daylight_savings (gdt2));
3013 g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
3014 g_date_time_unref (gdt1);
3015 g_date_time_unref (gdt2);
3016 g_time_zone_unref (tz);
3018 tz = g_time_zone_new_identifier ("NZST-12:00:00NZDT-13:00:00,279,76");
3019 g_assert_nonnull (tz);
3020 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "NZST-12:00:00NZDT-13:00:00,279,76");
3021 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "NZST");
3022 g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 12 * 3600);
3023 g_assert (!g_time_zone_is_dst (tz, 0));
3024 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "NZDT");
3025 g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, 13 * 3600);
3026 g_assert (g_time_zone_is_dst (tz, 1));
3027 gdt1 = g_date_time_new (tz, 2012, 3, 18, 0, 15, 23.0);
3028 gdt2 = g_date_time_new (tz, 2012, 3, 18, 3, 15, 23.0);
3029 g_assert (g_date_time_is_daylight_savings (gdt1));
3030 g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
3031 g_assert (!g_date_time_is_daylight_savings (gdt2));
3032 g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
3033 g_date_time_unref (gdt1);
3034 g_date_time_unref (gdt2);
3035 gdt1 = g_date_time_new (tz, 2012, 10, 7, 3, 15, 23.0);
3036 gdt2 = g_date_time_new (tz, 2012, 10, 7, 1, 15, 23.0);
3037 g_assert (g_date_time_is_daylight_savings (gdt1));
3038 g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
3039 g_assert (!g_date_time_is_daylight_savings (gdt2));
3040 g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
3041 g_date_time_unref (gdt1);
3042 g_date_time_unref (gdt2);
3043 g_time_zone_unref (tz);
3045 tz = g_time_zone_new_identifier ("NZST-12:00:00NZDT-13:00:00,J279,J76");
3046 g_assert_nonnull (tz);
3047 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "NZST-12:00:00NZDT-13:00:00,J279,J76");
3048 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "NZST");
3049 g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 12 * 3600);
3050 g_assert (!g_time_zone_is_dst (tz, 0));
3051 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "NZDT");
3052 g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, 13 * 3600);
3053 g_assert (g_time_zone_is_dst (tz, 1));
3054 gdt1 = g_date_time_new (tz, 2012, 3, 18, 0, 15, 23.0);
3055 gdt2 = g_date_time_new (tz, 2012, 3, 18, 3, 15, 23.0);
3056 g_assert (g_date_time_is_daylight_savings (gdt1));
3057 g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
3058 g_assert (!g_date_time_is_daylight_savings (gdt2));
3059 g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
3060 g_date_time_unref (gdt1);
3061 g_date_time_unref (gdt2);
3062 gdt1 = g_date_time_new (tz, 2012, 10, 7, 3, 15, 23.0);
3063 gdt2 = g_date_time_new (tz, 2012, 10, 7, 1, 15, 23.0);
3064 g_assert (g_date_time_is_daylight_savings (gdt1));
3065 g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
3066 g_assert (!g_date_time_is_daylight_savings (gdt2));
3067 g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
3068 g_date_time_unref (gdt1);
3069 g_date_time_unref (gdt2);
3070 g_time_zone_unref (tz);
3072 tz = g_time_zone_new_identifier ("NZST-12:00:00NZDT-13:00:00,M10.1.0/07:00,M3.3.0/07:00");
3073 g_assert_nonnull (tz);
3074 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");
3075 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "NZST");
3076 g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, 12 * 3600);
3077 g_assert (!g_time_zone_is_dst (tz, 0));
3078 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "NZDT");
3079 g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, 13 * 3600);
3080 g_assert (g_time_zone_is_dst (tz, 1));
3081 gdt1 = g_date_time_new (tz, 2012, 3, 18, 5, 15, 23.0);
3082 gdt2 = g_date_time_new (tz, 2012, 3, 18, 8, 15, 23.0);
3083 g_assert (g_date_time_is_daylight_savings (gdt1));
3084 g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
3085 g_assert (!g_date_time_is_daylight_savings (gdt2));
3086 g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
3087 g_date_time_unref (gdt1);
3088 g_date_time_unref (gdt2);
3089 gdt1 = g_date_time_new (tz, 2012, 10, 7, 8, 15, 23.0);
3090 gdt2 = g_date_time_new (tz, 2012, 10, 7, 6, 15, 23.0);
3091 g_assert (g_date_time_is_daylight_savings (gdt1));
3092 g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
3093 g_assert (!g_date_time_is_daylight_savings (gdt2));
3094 g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
3095 g_date_time_unref (gdt1);
3096 g_date_time_unref (gdt2);
3097 gdt1 = g_date_time_new (tz, 1902, 10, 7, 8, 15, 23.0);
3098 gdt2 = g_date_time_new (tz, 1902, 10, 7, 6, 15, 23.0);
3099 g_assert (!g_date_time_is_daylight_savings (gdt1));
3100 g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 43200);
3101 g_assert (!g_date_time_is_daylight_savings (gdt2));
3102 g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
3103 g_date_time_unref (gdt1);
3104 g_date_time_unref (gdt2);
3105 gdt1 = g_date_time_new (tz, 2142, 10, 7, 8, 15, 23.0);
3106 gdt2 = g_date_time_new (tz, 2142, 10, 7, 6, 15, 23.0);
3107 g_assert (g_date_time_is_daylight_savings (gdt1));
3108 g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 46800);
3109 g_assert (!g_date_time_is_daylight_savings (gdt2));
3110 g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
3111 g_date_time_unref (gdt1);
3112 g_date_time_unref (gdt2);
3113 gdt1 = g_date_time_new (tz, 3212, 10, 7, 8, 15, 23.0);
3114 gdt2 = g_date_time_new (tz, 3212, 10, 7, 6, 15, 23.0);
3115 g_assert (!g_date_time_is_daylight_savings (gdt1));
3116 g_assert_cmpint (g_date_time_get_utc_offset (gdt1) / 1000000, ==, 43200);
3117 g_assert (!g_date_time_is_daylight_savings (gdt2));
3118 g_assert_cmpint (g_date_time_get_utc_offset (gdt2) / 1000000, ==, 43200);
3119 g_date_time_unref (gdt1);
3120 g_date_time_unref (gdt2);
3121 g_time_zone_unref (tz);
3123 tz = g_time_zone_new_identifier ("VIR-00:30");
3124 g_assert_nonnull (tz);
3125 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "VIR-00:30");
3126 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "VIR");
3127 g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, (30 * 60));
3128 g_assert_false (g_time_zone_is_dst (tz, 0));
3130 tz = g_time_zone_new_identifier ("VIR-00:30VID,0/00:00:00,365/23:59:59");
3131 g_assert_nonnull (tz);
3132 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "VIR-00:30VID,0/00:00:00,365/23:59:59");
3133 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "VIR");
3134 g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, (30 * 60));
3135 g_assert_false (g_time_zone_is_dst (tz, 0));
3136 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "VID");
3137 g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, (90 * 60));
3138 g_assert_true (g_time_zone_is_dst (tz, 1));
3140 tz = g_time_zone_new_identifier ("VIR-02:30VID,0/00:00:00,365/23:59:59");
3141 g_assert_nonnull (tz);
3142 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "VIR-02:30VID,0/00:00:00,365/23:59:59");
3143 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "VIR");
3144 g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, (150 * 60));
3145 g_assert_false (g_time_zone_is_dst (tz, 0));
3146 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "VID");
3147 g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, (210 * 60));
3148 g_assert_true (g_time_zone_is_dst (tz, 1));
3150 tz = g_time_zone_new_identifier ("VIR-02:30VID-04:30,0/00:00:00,365/23:59:59");
3151 g_assert_nonnull (tz);
3152 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "VIR-02:30VID-04:30,0/00:00:00,365/23:59:59");
3153 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "VIR");
3154 g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, (150 * 60));
3155 g_assert_false (g_time_zone_is_dst (tz, 0));
3156 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "VID");
3157 g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, (270 * 60));
3158 g_assert_true (g_time_zone_is_dst (tz, 1));
3160 tz = g_time_zone_new_identifier ("VIR-12:00VID-13:00,0/00:00:00,365/23:59:59");
3161 g_assert_nonnull (tz);
3162 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "VIR-12:00VID-13:00,0/00:00:00,365/23:59:59");
3163 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "VIR");
3164 g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, (720 * 60));
3165 g_assert_false (g_time_zone_is_dst (tz, 0));
3166 g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "VID");
3167 g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==, (780 * 60));
3168 g_assert_true (g_time_zone_is_dst (tz, 1));
3172 test_GDateTime_floating_point (void)
3177 g_test_bug ("http://bugzilla.gnome.org/697715");
3179 tz = g_time_zone_new_identifier ("-03:00");
3180 g_assert_nonnull (tz);
3181 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "-03:00");
3182 dt = g_date_time_new (tz, 2010, 5, 24, 8, 0, 1.000001);
3183 g_time_zone_unref (tz);
3184 g_assert_cmpint (g_date_time_get_microsecond (dt), ==, 1);
3185 g_date_time_unref (dt);
3188 /* Check that g_time_zone_get_identifier() returns the identifier given to
3189 * g_time_zone_new(), or "UTC" if loading the timezone failed. */
3191 test_identifier (void)
3194 gchar *old_tz = g_strdup (g_getenv ("TZ"));
3197 const char *recife_tz = "SA Eastern Standard Time";
3199 const char *recife_tz = "America/Recife";
3202 tz = g_time_zone_new_identifier ("UTC");
3203 g_assert_nonnull (tz);
3204 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
3205 g_time_zone_unref (tz);
3207 tz = g_time_zone_new_utc ();
3208 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
3209 g_time_zone_unref (tz);
3211 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
3212 tz = g_time_zone_new ("some rubbish");
3213 G_GNUC_END_IGNORE_DEPRECATIONS
3214 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
3215 g_time_zone_unref (tz);
3217 tz = g_time_zone_new_identifier ("Z");
3218 g_assert_nonnull (tz);
3219 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "Z");
3220 g_time_zone_unref (tz);
3222 tz = g_time_zone_new_identifier ("+03:15");
3223 g_assert_nonnull (tz);
3224 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "+03:15");
3225 g_time_zone_unref (tz);
3227 /* System timezone. We can’t change this, but we can at least assert that
3228 * the identifier is non-NULL and non-empty. */
3229 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
3230 tz = g_time_zone_new (NULL);
3231 G_GNUC_END_IGNORE_DEPRECATIONS
3232 g_test_message ("System time zone identifier: %s", g_time_zone_get_identifier (tz));
3233 g_assert_nonnull (g_time_zone_get_identifier (tz));
3234 g_assert_cmpstr (g_time_zone_get_identifier (tz), !=, "");
3235 g_time_zone_unref (tz);
3237 /* Local timezone tests. */
3238 if (g_setenv ("TZ", recife_tz, TRUE))
3240 tz = g_time_zone_new_local ();
3241 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, recife_tz);
3242 g_time_zone_unref (tz);
3245 if (g_setenv ("TZ", "some rubbish", TRUE))
3247 tz = g_time_zone_new_local ();
3248 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
3249 g_time_zone_unref (tz);
3253 g_assert_true (g_setenv ("TZ", old_tz, TRUE));
3260 /* Test various calls to g_time_zone_new_offset(). */
3262 test_new_offset (void)
3267 gboolean expected_success;
3287 for (i = 0; i < G_N_ELEMENTS (vectors); i++)
3289 GTimeZone *tz = NULL;
3291 g_test_message ("Vector %" G_GSIZE_FORMAT ": %d", i, vectors[i].offset);
3293 tz = g_time_zone_new_offset (vectors[i].offset);
3294 g_assert_nonnull (tz);
3296 if (vectors[i].expected_success)
3298 g_assert_cmpstr (g_time_zone_get_identifier (tz), !=, "UTC");
3299 g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, vectors[i].offset);
3303 g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
3306 g_time_zone_unref (tz);
3311 test_time_zone_parse_rfc8536 (void)
3314 const gchar *test_files[] =
3316 /* Generated with `zic -b slim`; see
3317 * https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1533#note_842235 */
3319 /* Generated with `zic -b fat` */
3324 g_test_summary ("Test parsing time zone files in RFC 8536 version 3 format");
3325 g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2129");
3327 for (i = 0; i < G_N_ELEMENTS (test_files); i++)
3330 GTimeZone *tz = NULL;
3332 path = g_test_build_filename (G_TEST_DIST, "time-zones", test_files[i], NULL);
3333 g_assert_true (g_path_is_absolute (path));
3334 tz = g_time_zone_new_identifier (path);
3335 g_assert_nonnull (tz);
3336 g_time_zone_unref (tz);
3340 g_test_skip ("RFC 8536 format time zone files are not available on Windows");
3344 /* Check GTimeZone instances are cached. */
3346 test_time_zone_caching (void)
3348 GTimeZone *tz1 = NULL, *tz2 = NULL;
3350 g_test_summary ("GTimeZone instances are cached");
3352 /* Check a specific (arbitrary) timezone. These are only cached while third
3353 * party code holds a ref to at least one instance. */
3355 tz1 = g_time_zone_new_identifier ("Europe/London");
3356 g_assert_nonnull (tz1);
3357 tz2 = g_time_zone_new_identifier ("Europe/London");
3358 g_assert_nonnull (tz2);
3359 g_time_zone_unref (tz1);
3360 g_time_zone_unref (tz2);
3361 #elif defined G_OS_WIN32
3362 tz1 = g_time_zone_new_identifier ("GMT Standard Time");
3363 g_assert_nonnull (tz1);
3364 tz2 = g_time_zone_new_identifier ("GMT Standard Time");
3365 g_assert_nonnull (tz2);
3366 g_time_zone_unref (tz1);
3367 g_time_zone_unref (tz2);
3370 /* Only compare pointers */
3371 g_assert_true (tz1 == tz2);
3373 /* Check the default timezone, local and UTC. These are cached internally in
3374 * GLib, so should persist even after the last third party reference is
3377 * The default timezone could be NULL on some platforms (FreeBSD) if
3378 * `/etc/localtime` is not set correctly. */
3379 tz1 = g_time_zone_new_identifier (NULL);
3382 g_assert_nonnull (tz1);
3383 g_time_zone_unref (tz1);
3384 tz2 = g_time_zone_new_identifier (NULL);
3385 g_assert_nonnull (tz2);
3386 g_time_zone_unref (tz2);
3388 g_assert_true (tz1 == tz2);
3391 tz1 = g_time_zone_new_utc ();
3392 g_time_zone_unref (tz1);
3393 tz2 = g_time_zone_new_utc ();
3394 g_time_zone_unref (tz2);
3396 g_assert_true (tz1 == tz2);
3398 tz1 = g_time_zone_new_local ();
3399 g_time_zone_unref (tz1);
3400 tz2 = g_time_zone_new_local ();
3401 g_time_zone_unref (tz2);
3403 g_assert_true (tz1 == tz2);
3407 test_date_time_unix_usec (void)
3409 gint64 usecs = g_get_real_time ();
3410 gint64 secs = usecs / G_USEC_PER_SEC;
3414 dt = g_date_time_new_from_unix_utc (secs);
3415 g_assert_cmpint (g_date_time_to_unix_usec (dt), ==, secs * G_USEC_PER_SEC);
3416 g_assert_cmpint (g_date_time_to_unix (dt), ==, secs);
3417 g_date_time_unref (dt);
3419 dt = g_date_time_new_from_unix_utc_usec (usecs);
3420 g_assert_cmpint (g_date_time_to_unix_usec (dt), ==, usecs);
3421 g_assert_cmpint (g_date_time_to_unix (dt), ==, secs);
3422 g_date_time_unref (dt);
3424 local = g_date_time_new_from_unix_local (secs);
3425 dt = g_date_time_to_utc (local);
3426 g_assert_cmpint (g_date_time_to_unix_usec (dt), ==, secs * G_USEC_PER_SEC);
3427 g_assert_cmpint (g_date_time_to_unix (dt), ==, secs);
3428 g_date_time_unref (dt);
3429 g_date_time_unref (local);
3431 local = g_date_time_new_from_unix_local_usec (usecs);
3432 dt = g_date_time_to_utc (local);
3433 g_assert_cmpint (g_date_time_to_unix_usec (dt), ==, usecs);
3434 g_assert_cmpint (g_date_time_to_unix (dt), ==, secs);
3435 g_date_time_unref (dt);
3436 g_date_time_unref (local);
3443 /* In glibc, LANGUAGE is used as highest priority guess for category value.
3444 * Unset it to avoid interference with tests using setlocale and translation. */
3445 g_unsetenv ("LANGUAGE");
3447 /* GLib uses CHARSET to allow overriding the character set used for all locale
3448 * categories. Unset it to avoid interference with tests. */
3449 g_unsetenv ("CHARSET");
3451 setlocale (LC_ALL, "C.UTF-8");
3452 g_test_init (&argc, &argv, NULL);
3454 /* GDateTime Tests */
3455 bind_textdomain_codeset ("glib20", "UTF-8");
3457 g_test_add_func ("/GDateTime/invalid", test_GDateTime_invalid);
3458 g_test_add_func ("/GDateTime/add_days", test_GDateTime_add_days);
3459 g_test_add_func ("/GDateTime/add_full", test_GDateTime_add_full);
3460 g_test_add_func ("/GDateTime/add_hours", test_GDateTime_add_hours);
3461 g_test_add_func ("/GDateTime/add_minutes", test_GDateTime_add_minutes);
3462 g_test_add_func ("/GDateTime/add_months", test_GDateTime_add_months);
3463 g_test_add_func ("/GDateTime/add_seconds", test_GDateTime_add_seconds);
3464 g_test_add_func ("/GDateTime/add_weeks", test_GDateTime_add_weeks);
3465 g_test_add_func ("/GDateTime/add_years", test_GDateTime_add_years);
3466 g_test_add_func ("/GDateTime/compare", test_GDateTime_compare);
3467 g_test_add_func ("/GDateTime/diff", test_GDateTime_diff);
3468 g_test_add_func ("/GDateTime/equal", test_GDateTime_equal);
3469 g_test_add_func ("/GDateTime/get_day_of_week", test_GDateTime_get_day_of_week);
3470 g_test_add_func ("/GDateTime/get_day_of_month", test_GDateTime_get_day_of_month);
3471 g_test_add_func ("/GDateTime/get_day_of_year", test_GDateTime_get_day_of_year);
3472 g_test_add_func ("/GDateTime/get_hour", test_GDateTime_get_hour);
3473 g_test_add_func ("/GDateTime/get_microsecond", test_GDateTime_get_microsecond);
3474 g_test_add_func ("/GDateTime/get_minute", test_GDateTime_get_minute);
3475 g_test_add_func ("/GDateTime/get_month", test_GDateTime_get_month);
3476 g_test_add_func ("/GDateTime/get_second", test_GDateTime_get_second);
3477 g_test_add_func ("/GDateTime/get_utc_offset", test_GDateTime_get_utc_offset);
3478 g_test_add_func ("/GDateTime/get_year", test_GDateTime_get_year);
3479 g_test_add_func ("/GDateTime/hash", test_GDateTime_hash);
3480 g_test_add_func ("/GDateTime/new_from_unix", test_GDateTime_new_from_unix);
3481 g_test_add_func ("/GDateTime/new_from_unix_utc", test_GDateTime_new_from_unix_utc);
3482 g_test_add_func ("/GDateTime/new_from_unix/overflow", test_GDateTime_new_from_unix_overflow);
3483 g_test_add_func ("/GDateTime/new_from_timeval", test_GDateTime_new_from_timeval);
3484 g_test_add_func ("/GDateTime/new_from_timeval_utc", test_GDateTime_new_from_timeval_utc);
3485 g_test_add_func ("/GDateTime/new_from_timeval/overflow", test_GDateTime_new_from_timeval_overflow);
3486 g_test_add_func ("/GDateTime/new_from_iso8601", test_GDateTime_new_from_iso8601);
3487 g_test_add_func ("/GDateTime/new_from_iso8601/2", test_GDateTime_new_from_iso8601_2);
3488 g_test_add_func ("/GDateTime/new_full", test_GDateTime_new_full);
3489 g_test_add_func ("/GDateTime/now", test_GDateTime_now);
3490 g_test_add_func ("/GDateTime/test-6-days-until-end-of-the-month", test_6_days_until_end_of_the_month);
3491 g_test_add_func ("/GDateTime/printf", test_GDateTime_printf);
3492 g_test_add_func ("/GDateTime/non_utf8_printf", test_non_utf8_printf);
3493 g_test_add_func ("/GDateTime/format_unrepresentable", test_format_unrepresentable);
3494 g_test_add_func ("/GDateTime/format_iso8601", test_format_iso8601);
3495 g_test_add_data_func ("/GDateTime/format_mixed/utf8_time_non_utf8_messages",
3496 &utf8_time_non_utf8_messages,
3497 test_format_time_mixed_utf8);
3498 g_test_add_data_func ("/GDateTime/format_mixed/utf8_time_utf8_messages",
3499 &utf8_time_utf8_messages,
3500 test_format_time_mixed_utf8);
3501 g_test_add_data_func ("/GDateTime/format_mixed/non_utf8_time_non_utf8_messages",
3502 &non_utf8_time_non_utf8_messages,
3503 test_format_time_mixed_utf8);
3504 g_test_add_data_func ("/GDateTime/format_mixed/non_utf8_time_utf8_messages",
3505 &non_utf8_time_utf8_messages,
3506 test_format_time_mixed_utf8);
3507 g_test_add_func ("/GDateTime/strftime", test_strftime);
3508 g_test_add_func ("/GDateTime/strftime/error_handling", test_GDateTime_strftime_error_handling);
3509 g_test_add_func ("/GDateTime/modifiers", test_modifiers);
3510 g_test_add_func ("/GDateTime/month_names", test_month_names);
3511 g_test_add_func ("/GDateTime/to_local", test_GDateTime_to_local);
3512 g_test_add_func ("/GDateTime/to_unix", test_GDateTime_to_unix);
3513 g_test_add_func ("/GDateTime/to_timeval", test_GDateTime_to_timeval);
3514 g_test_add_func ("/GDateTime/to_utc", test_GDateTime_to_utc);
3515 g_test_add_func ("/GDateTime/now_utc", test_GDateTime_now_utc);
3516 g_test_add_func ("/GDateTime/dst", test_GDateTime_dst);
3517 g_test_add_func ("/GDateTime/test_z", test_z);
3518 g_test_add_func ("/GDateTime/test-all-dates", test_all_dates);
3519 g_test_add_func ("/GDateTime/eras/japan", test_date_time_eras_japan);
3520 g_test_add_func ("/GDateTime/eras/thailand", test_date_time_eras_thailand);
3521 g_test_add_func ("/GDateTime/eras/parsing", test_date_time_eras_parsing);
3522 g_test_add_func ("/GDateTime/unix_usec", test_date_time_unix_usec);
3524 g_test_add_func ("/GTimeZone/find-interval", test_find_interval);
3525 g_test_add_func ("/GTimeZone/adjust-time", test_adjust_time);
3526 g_test_add_func ("/GTimeZone/no-header", test_no_header);
3527 g_test_add_func ("/GTimeZone/no-header-identifier", test_no_header_identifier);
3528 g_test_add_func ("/GTimeZone/posix-parse", test_posix_parse);
3529 g_test_add_func ("/GTimeZone/floating-point", test_GDateTime_floating_point);
3530 g_test_add_func ("/GTimeZone/identifier", test_identifier);
3531 g_test_add_func ("/GTimeZone/new-offset", test_new_offset);
3532 g_test_add_func ("/GTimeZone/parse-rfc8536", test_time_zone_parse_rfc8536);
3533 g_test_add_func ("/GTimeZone/caching", test_time_zone_caching);
3535 return g_test_run ();