3 * Copyright (C) 2009-2010 Christian Hergert <chris@dronelabs.com>
4 * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
5 * Copyright (C) 2010 Emmanuele Bassi <ebassi@linux.intel.com>
6 * Copyright © 2010 Codethink Limited
7 * Copyright © 2018 Tomasz Miąsko
8 * Copyright 2023 GNOME Foundation Inc.
10 * SPDX-License-Identifier: LGPL-2.1-or-later
12 * This library is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License as
14 * published by the Free Software Foundation; either version 2.1 of the
15 * licence, or (at your option) any later version.
17 * This is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
20 * License for more details.
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this library; if not, see <http://www.gnu.org/licenses/>.
25 * Authors: Christian Hergert <chris@dronelabs.com>
26 * Thiago Santos <thiago.sousa.santos@collabora.co.uk>
27 * Emmanuele Bassi <ebassi@linux.intel.com>
28 * Ryan Lortie <desrt@desrt.ca>
29 * Robert Ancell <robert.ancell@canonical.com>
30 * Philip Withnall <pwithnall@gnome.org>
33 /* Algorithms within this file are based on the Calendar FAQ by
34 * Claus Tondering. It can be found at
35 * http://www.tondering.dk/claus/cal/calendar29.txt
37 * Copyright and disclaimer
38 * ------------------------
39 * This document is Copyright (C) 2008 by Claus Tondering.
40 * E-mail: claus@tondering.dk. (Please include the word
41 * "calendar" in the subject line.)
42 * The document may be freely distributed, provided this
43 * copyright notice is included and no money is charged for
46 * This document is provided "as is". No warranties are made as
54 /* langinfo.h in glibc 2.27 defines ALTMON_* only if _GNU_SOURCE is defined. */
64 #ifdef HAVE_LANGINFO_TIME
70 #include "gcharsetprivate.h"
72 #include "gconvertprivate.h"
73 #include "gdatetime.h"
74 #include "gdatetime-private.h"
75 #include "gfileutils.h"
79 #include "gmappedfile.h"
81 #include "gstrfuncs.h"
82 #include "gtestutils.h"
84 #include "gtimezone.h"
90 #if defined (_MSC_VER) && (_MSC_VER < 1800)
91 /* fallback implementation for isnan() on VS2012 and earlier */
94 #endif /* !G_OS_WIN32 */
98 /* Microsecond timekeeping within Day */
101 /* TimeZone information */
105 /* 1 is 0001-01-01 in Proleptic Gregorian */
108 gint ref_count; /* (atomic) */
111 /* Time conversion {{{1 */
113 #define UNIX_EPOCH_START 719163
114 #define INSTANT_TO_UNIX(instant) \
115 ((instant)/USEC_PER_SECOND - UNIX_EPOCH_START * SEC_PER_DAY)
116 #define INSTANT_TO_UNIX_USECS(instant) \
117 ((instant) - UNIX_EPOCH_START * SEC_PER_DAY * USEC_PER_SECOND)
118 #define UNIX_TO_INSTANT(unix) \
119 (((gint64) (unix) + UNIX_EPOCH_START * SEC_PER_DAY) * USEC_PER_SECOND)
120 #define UNIX_USECS_TO_INSTANT(unix_usecs) \
121 ((gint64) (unix_usecs) + UNIX_EPOCH_START * SEC_PER_DAY * USEC_PER_SECOND)
122 #define UNIX_TO_INSTANT_IS_VALID(unix) \
123 ((gint64) (unix) <= INSTANT_TO_UNIX (G_MAXINT64))
124 #define UNIX_USECS_TO_INSTANT_IS_VALID(unix_usecs) \
125 ((gint64) (unix_usecs) <= INSTANT_TO_UNIX_USECS (G_MAXINT64))
127 #define DAYS_IN_4YEARS 1461 /* days in 4 years */
128 #define DAYS_IN_100YEARS 36524 /* days in 100 years */
129 #define DAYS_IN_400YEARS 146097 /* days in 400 years */
131 #define USEC_PER_SECOND (G_GINT64_CONSTANT (1000000))
132 #define USEC_PER_MINUTE (G_GINT64_CONSTANT (60000000))
133 #define USEC_PER_HOUR (G_GINT64_CONSTANT (3600000000))
134 #define USEC_PER_MILLISECOND (G_GINT64_CONSTANT (1000))
135 #define USEC_PER_DAY (G_GINT64_CONSTANT (86400000000))
136 #define SEC_PER_DAY (G_GINT64_CONSTANT (86400))
138 #define SECS_PER_MINUTE (60)
139 #define SECS_PER_HOUR (60 * SECS_PER_MINUTE)
140 #define SECS_PER_DAY (24 * SECS_PER_HOUR)
141 #define SECS_PER_YEAR (365 * SECS_PER_DAY)
142 #define SECS_PER_JULIAN (DAYS_PER_PERIOD * SECS_PER_DAY)
144 #define GREGORIAN_LEAP(y) ((((y) % 4) == 0) && (!((((y) % 100) == 0) && (((y) % 400) != 0))))
145 #define JULIAN_YEAR(d) ((d)->julian / 365.25)
146 #define DAYS_PER_PERIOD (G_GINT64_CONSTANT (2914695))
148 static const guint16 days_in_months[2][13] =
150 { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
151 { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
154 static const guint16 days_in_year[2][13] =
156 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
157 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
160 #ifdef HAVE_LANGINFO_TIME
162 #define GET_AMPM(d) ((g_date_time_get_hour (d) < 12) ? \
163 nl_langinfo (AM_STR) : \
164 nl_langinfo (PM_STR))
165 #define GET_AMPM_IS_LOCALE TRUE
167 #define PREFERRED_DATE_TIME_FMT nl_langinfo (D_T_FMT)
168 #define PREFERRED_DATE_FMT nl_langinfo (D_FMT)
169 #define PREFERRED_TIME_FMT nl_langinfo (T_FMT)
170 #define PREFERRED_12HR_TIME_FMT nl_langinfo (T_FMT_AMPM)
172 static const gint weekday_item[2][7] =
174 { ABDAY_2, ABDAY_3, ABDAY_4, ABDAY_5, ABDAY_6, ABDAY_7, ABDAY_1 },
175 { DAY_2, DAY_3, DAY_4, DAY_5, DAY_6, DAY_7, DAY_1 }
178 static const gint month_item[2][12] =
180 { ABMON_1, ABMON_2, ABMON_3, ABMON_4, ABMON_5, ABMON_6, ABMON_7, ABMON_8, ABMON_9, ABMON_10, ABMON_11, ABMON_12 },
181 { MON_1, MON_2, MON_3, MON_4, MON_5, MON_6, MON_7, MON_8, MON_9, MON_10, MON_11, MON_12 },
184 #define WEEKDAY_ABBR(d) nl_langinfo (weekday_item[0][g_date_time_get_day_of_week (d) - 1])
185 #define WEEKDAY_ABBR_IS_LOCALE TRUE
186 #define WEEKDAY_FULL(d) nl_langinfo (weekday_item[1][g_date_time_get_day_of_week (d) - 1])
187 #define WEEKDAY_FULL_IS_LOCALE TRUE
188 #define MONTH_ABBR(d) nl_langinfo (month_item[0][g_date_time_get_month (d) - 1])
189 #define MONTH_ABBR_IS_LOCALE TRUE
190 #define MONTH_FULL(d) nl_langinfo (month_item[1][g_date_time_get_month (d) - 1])
191 #define MONTH_FULL_IS_LOCALE TRUE
195 #define GET_AMPM(d) (get_fallback_ampm (g_date_time_get_hour (d)))
196 #define GET_AMPM_IS_LOCALE FALSE
198 /* Translators: this is the preferred format for expressing the date and the time */
199 #define PREFERRED_DATE_TIME_FMT C_("GDateTime", "%a %b %e %H:%M:%S %Y")
201 /* Translators: this is the preferred format for expressing the date */
202 #define PREFERRED_DATE_FMT C_("GDateTime", "%m/%d/%y")
204 /* Translators: this is the preferred format for expressing the time */
205 #define PREFERRED_TIME_FMT C_("GDateTime", "%H:%M:%S")
207 /* Translators: this is the preferred format for expressing 12 hour time */
208 #define PREFERRED_12HR_TIME_FMT C_("GDateTime", "%I:%M:%S %p")
210 #define WEEKDAY_ABBR(d) (get_weekday_name_abbr (g_date_time_get_day_of_week (d)))
211 #define WEEKDAY_ABBR_IS_LOCALE FALSE
212 #define WEEKDAY_FULL(d) (get_weekday_name (g_date_time_get_day_of_week (d)))
213 #define WEEKDAY_FULL_IS_LOCALE FALSE
214 /* We don't yet know if nl_langinfo (MON_n) returns standalone or complete-date
215 * format forms but if nl_langinfo (ALTMON_n) is not supported then we will
216 * have to use MONTH_FULL as standalone. The same if nl_langinfo () does not
217 * exist at all. MONTH_ABBR is similar: if nl_langinfo (_NL_ABALTMON_n) is not
218 * supported then we will use MONTH_ABBR as standalone.
220 #define MONTH_ABBR(d) (get_month_name_abbr_standalone (g_date_time_get_month (d)))
221 #define MONTH_ABBR_IS_LOCALE FALSE
222 #define MONTH_FULL(d) (get_month_name_standalone (g_date_time_get_month (d)))
223 #define MONTH_FULL_IS_LOCALE FALSE
226 get_month_name_standalone (gint month)
231 /* Translators: Some languages (Baltic, Slavic, Greek, and some more)
232 * need different grammatical forms of month names depending on whether
233 * they are standalone or in a complete date context, with the day
234 * number. Some other languages may prefer starting with uppercase when
235 * they are standalone and with lowercase when they are in a complete
236 * date context. Here are full month names in a form appropriate when
237 * they are used standalone. If your system is Linux with the glibc
238 * version 2.27 (released Feb 1, 2018) or newer or if it is from the BSD
239 * family (which includes OS X) then you can refer to the date command
240 * line utility and see what the command `date +%OB' produces. Also in
241 * the latest Linux the command `locale alt_mon' in your native locale
242 * produces a complete list of month names almost ready to copy and
243 * paste here. Note that in most of the languages (western European,
244 * non-European) there is no difference between the standalone and
245 * complete date form.
247 return C_("full month name", "January");
249 return C_("full month name", "February");
251 return C_("full month name", "March");
253 return C_("full month name", "April");
255 return C_("full month name", "May");
257 return C_("full month name", "June");
259 return C_("full month name", "July");
261 return C_("full month name", "August");
263 return C_("full month name", "September");
265 return C_("full month name", "October");
267 return C_("full month name", "November");
269 return C_("full month name", "December");
272 g_warning ("Invalid month number %d", month);
279 get_month_name_abbr_standalone (gint month)
284 /* Translators: Some languages need different grammatical forms of
285 * month names depending on whether they are standalone or in a complete
286 * date context, with the day number. Some may prefer starting with
287 * uppercase when they are standalone and with lowercase when they are
288 * in a full date context. However, as these names are abbreviated
289 * the grammatical difference is visible probably only in Belarusian
290 * and Russian. In other languages there is no difference between
291 * the standalone and complete date form when they are abbreviated.
292 * If your system is Linux with the glibc version 2.27 (released
293 * Feb 1, 2018) or newer then you can refer to the date command line
294 * utility and see what the command `date +%Ob' produces. Also in
295 * the latest Linux the command `locale ab_alt_mon' in your native
296 * locale produces a complete list of month names almost ready to copy
297 * and paste here. Note that this feature is not yet supported by any
298 * other platform. Here are abbreviated month names in a form
299 * appropriate when they are used standalone.
301 return C_("abbreviated month name", "Jan");
303 return C_("abbreviated month name", "Feb");
305 return C_("abbreviated month name", "Mar");
307 return C_("abbreviated month name", "Apr");
309 return C_("abbreviated month name", "May");
311 return C_("abbreviated month name", "Jun");
313 return C_("abbreviated month name", "Jul");
315 return C_("abbreviated month name", "Aug");
317 return C_("abbreviated month name", "Sep");
319 return C_("abbreviated month name", "Oct");
321 return C_("abbreviated month name", "Nov");
323 return C_("abbreviated month name", "Dec");
326 g_warning ("Invalid month number %d", month);
333 get_weekday_name (gint day)
338 return C_("full weekday name", "Monday");
340 return C_("full weekday name", "Tuesday");
342 return C_("full weekday name", "Wednesday");
344 return C_("full weekday name", "Thursday");
346 return C_("full weekday name", "Friday");
348 return C_("full weekday name", "Saturday");
350 return C_("full weekday name", "Sunday");
353 g_warning ("Invalid week day number %d", day);
360 get_weekday_name_abbr (gint day)
365 return C_("abbreviated weekday name", "Mon");
367 return C_("abbreviated weekday name", "Tue");
369 return C_("abbreviated weekday name", "Wed");
371 return C_("abbreviated weekday name", "Thu");
373 return C_("abbreviated weekday name", "Fri");
375 return C_("abbreviated weekday name", "Sat");
377 return C_("abbreviated weekday name", "Sun");
380 g_warning ("Invalid week day number %d", day);
386 #endif /* HAVE_LANGINFO_TIME */
388 #ifdef HAVE_LANGINFO_ALTMON
390 /* If nl_langinfo () supports ALTMON_n then MON_n returns full date format
391 * forms and ALTMON_n returns standalone forms.
394 #define MONTH_FULL_WITH_DAY(d) MONTH_FULL(d)
395 #define MONTH_FULL_WITH_DAY_IS_LOCALE MONTH_FULL_IS_LOCALE
397 static const gint alt_month_item[12] =
399 ALTMON_1, ALTMON_2, ALTMON_3, ALTMON_4, ALTMON_5, ALTMON_6,
400 ALTMON_7, ALTMON_8, ALTMON_9, ALTMON_10, ALTMON_11, ALTMON_12
403 #define MONTH_FULL_STANDALONE(d) nl_langinfo (alt_month_item[g_date_time_get_month (d) - 1])
404 #define MONTH_FULL_STANDALONE_IS_LOCALE TRUE
408 /* If nl_langinfo () does not support ALTMON_n then either MON_n returns
409 * standalone forms or nl_langinfo (MON_n) does not work so we have defined
410 * it as standalone form.
413 #define MONTH_FULL_STANDALONE(d) MONTH_FULL(d)
414 #define MONTH_FULL_STANDALONE_IS_LOCALE MONTH_FULL_IS_LOCALE
415 #define MONTH_FULL_WITH_DAY(d) (get_month_name_with_day (g_date_time_get_month (d)))
416 #define MONTH_FULL_WITH_DAY_IS_LOCALE FALSE
419 get_month_name_with_day (gint month)
424 /* Translators: Some languages need different grammatical forms of
425 * month names depending on whether they are standalone or in a full
426 * date context, with the day number. Some may prefer starting with
427 * uppercase when they are standalone and with lowercase when they are
428 * in a full date context. Here are full month names in a form
429 * appropriate when they are used in a full date context, with the
430 * day number. If your system is Linux with the glibc version 2.27
431 * (released Feb 1, 2018) or newer or if it is from the BSD family
432 * (which includes OS X) then you can refer to the date command line
433 * utility and see what the command `date +%B' produces. Also in
434 * the latest Linux the command `locale mon' in your native locale
435 * produces a complete list of month names almost ready to copy and
436 * paste here. In older Linux systems due to a bug the result is
437 * incorrect in some languages. Note that in most of the languages
438 * (western European, non-European) there is no difference between the
439 * standalone and complete date form.
441 return C_("full month name with day", "January");
443 return C_("full month name with day", "February");
445 return C_("full month name with day", "March");
447 return C_("full month name with day", "April");
449 return C_("full month name with day", "May");
451 return C_("full month name with day", "June");
453 return C_("full month name with day", "July");
455 return C_("full month name with day", "August");
457 return C_("full month name with day", "September");
459 return C_("full month name with day", "October");
461 return C_("full month name with day", "November");
463 return C_("full month name with day", "December");
466 g_warning ("Invalid month number %d", month);
472 #endif /* HAVE_LANGINFO_ALTMON */
474 #ifdef HAVE_LANGINFO_ABALTMON
476 /* If nl_langinfo () supports _NL_ABALTMON_n then ABMON_n returns full
477 * date format forms and _NL_ABALTMON_n returns standalone forms.
480 #define MONTH_ABBR_WITH_DAY(d) MONTH_ABBR(d)
481 #define MONTH_ABBR_WITH_DAY_IS_LOCALE MONTH_ABBR_IS_LOCALE
483 static const gint ab_alt_month_item[12] =
485 _NL_ABALTMON_1, _NL_ABALTMON_2, _NL_ABALTMON_3, _NL_ABALTMON_4,
486 _NL_ABALTMON_5, _NL_ABALTMON_6, _NL_ABALTMON_7, _NL_ABALTMON_8,
487 _NL_ABALTMON_9, _NL_ABALTMON_10, _NL_ABALTMON_11, _NL_ABALTMON_12
490 #define MONTH_ABBR_STANDALONE(d) nl_langinfo (ab_alt_month_item[g_date_time_get_month (d) - 1])
491 #define MONTH_ABBR_STANDALONE_IS_LOCALE TRUE
495 /* If nl_langinfo () does not support _NL_ABALTMON_n then either ABMON_n
496 * returns standalone forms or nl_langinfo (ABMON_n) does not work so we
497 * have defined it as standalone form. Now it's time to swap.
500 #define MONTH_ABBR_STANDALONE(d) MONTH_ABBR(d)
501 #define MONTH_ABBR_STANDALONE_IS_LOCALE MONTH_ABBR_IS_LOCALE
502 #define MONTH_ABBR_WITH_DAY(d) (get_month_name_abbr_with_day (g_date_time_get_month (d)))
503 #define MONTH_ABBR_WITH_DAY_IS_LOCALE FALSE
506 get_month_name_abbr_with_day (gint month)
511 /* Translators: Some languages need different grammatical forms of
512 * month names depending on whether they are standalone or in a full
513 * date context, with the day number. Some may prefer starting with
514 * uppercase when they are standalone and with lowercase when they are
515 * in a full date context. Here are abbreviated month names in a form
516 * appropriate when they are used in a full date context, with the
517 * day number. However, as these names are abbreviated the grammatical
518 * difference is visible probably only in Belarusian and Russian.
519 * In other languages there is no difference between the standalone
520 * and complete date form when they are abbreviated. If your system
521 * is Linux with the glibc version 2.27 (released Feb 1, 2018) or newer
522 * then you can refer to the date command line utility and see what the
523 * command `date +%b' produces. Also in the latest Linux the command
524 * `locale abmon' in your native locale produces a complete list of
525 * month names almost ready to copy and paste here. In other systems
526 * due to a bug the result is incorrect in some languages.
528 return C_("abbreviated month name with day", "Jan");
530 return C_("abbreviated month name with day", "Feb");
532 return C_("abbreviated month name with day", "Mar");
534 return C_("abbreviated month name with day", "Apr");
536 return C_("abbreviated month name with day", "May");
538 return C_("abbreviated month name with day", "Jun");
540 return C_("abbreviated month name with day", "Jul");
542 return C_("abbreviated month name with day", "Aug");
544 return C_("abbreviated month name with day", "Sep");
546 return C_("abbreviated month name with day", "Oct");
548 return C_("abbreviated month name with day", "Nov");
550 return C_("abbreviated month name with day", "Dec");
553 g_warning ("Invalid month number %d", month);
559 #endif /* HAVE_LANGINFO_ABALTMON */
561 /* FIXME: It doesn’t seem to be possible to use ERA on 64-bit big-endian platforms with glibc
562 * in a POSIX-compliant way right now.
563 * See https://gitlab.gnome.org/GNOME/glib/-/issues/3225 */
564 #if defined(HAVE_LANGINFO_ERA) && (G_BYTE_ORDER == G_LITTLE_ENDIAN || GLIB_SIZEOF_VOID_P == 4)
566 #define PREFERRED_ERA_DATE_TIME_FMT nl_langinfo (ERA_D_T_FMT)
567 #define PREFERRED_ERA_DATE_FMT nl_langinfo (ERA_D_FMT)
568 #define PREFERRED_ERA_TIME_FMT nl_langinfo (ERA_T_FMT)
570 #define ERA_DESCRIPTION nl_langinfo (ERA)
571 #define ERA_DESCRIPTION_IS_LOCALE TRUE
572 #define ERA_DESCRIPTION_N_SEGMENTS (int) (gintptr) nl_langinfo (_NL_TIME_ERA_NUM_ENTRIES)
574 #else /* if !HAVE_LANGINFO_ERA */
576 #define PREFERRED_ERA_DATE_TIME_FMT PREFERRED_DATE_TIME_FMT
577 #define PREFERRED_ERA_DATE_FMT PREFERRED_DATE_FMT
578 #define PREFERRED_ERA_TIME_FMT PREFERRED_TIME_FMT
580 #define ERA_DESCRIPTION NULL
581 #define ERA_DESCRIPTION_IS_LOCALE FALSE
582 #define ERA_DESCRIPTION_N_SEGMENTS 0
584 #endif /* !HAVE_LANGINFO_ERA */
586 /* Format AM/PM indicator if the locale does not have a localized version. */
588 get_fallback_ampm (gint hour)
591 /* Translators: 'before midday' indicator */
592 return C_("GDateTime", "AM");
594 /* Translators: 'after midday' indicator */
595 return C_("GDateTime", "PM");
599 ymd_to_days (gint year,
605 days = ((gint64) year - 1) * 365 + ((year - 1) / 4) - ((year - 1) / 100)
606 + ((year - 1) / 400);
608 days += days_in_year[0][month - 1];
609 if (GREGORIAN_LEAP (year) && month > 2)
618 g_date_time_get_week_number (GDateTime *datetime,
623 gint a, b, c, d, e, f, g, n, s, month = -1, day = -1, year = -1;
625 g_date_time_get_ymd (datetime, &year, &month, &day);
629 a = g_date_time_get_year (datetime) - 1;
630 b = (a / 4) - (a / 100) + (a / 400);
631 c = ((a - 1) / 4) - ((a - 1) / 100) + ((a - 1) / 400);
634 f = day - 1 + (31 * (month - 1));
639 b = (a / 4) - (a / 100) + (a / 400);
640 c = ((a - 1) / 4) - ((a - 1) / 100) + ((a - 1) / 400);
643 f = day + (((153 * (month - 3)) + 2) / 5) + 58 + s;
653 *week_number = 53 - ((g - s) / 5);
654 else if (n > 364 + s)
657 *week_number = (n / 7) + 1;
661 *day_of_week = d + 1;
664 *day_of_year = f + 1;
670 g_date_time_alloc (GTimeZone *tz)
674 datetime = g_slice_new0 (GDateTime);
675 datetime->tz = g_time_zone_ref (tz);
676 datetime->ref_count = 1;
683 * @datetime: a #GDateTime
685 * Atomically increments the reference count of @datetime by one.
687 * Returns: the #GDateTime with the reference count increased
692 g_date_time_ref (GDateTime *datetime)
694 g_return_val_if_fail (datetime != NULL, NULL);
695 g_return_val_if_fail (datetime->ref_count > 0, NULL);
697 g_atomic_int_inc (&datetime->ref_count);
704 * @datetime: a #GDateTime
706 * Atomically decrements the reference count of @datetime by one.
708 * When the reference count reaches zero, the resources allocated by
709 * @datetime are freed
714 g_date_time_unref (GDateTime *datetime)
716 g_return_if_fail (datetime != NULL);
717 g_return_if_fail (datetime->ref_count > 0);
719 if (g_atomic_int_dec_and_test (&datetime->ref_count))
721 g_time_zone_unref (datetime->tz);
722 g_slice_free (GDateTime, datetime);
726 /* Internal state transformers {{{1 */
728 * g_date_time_to_instant:
729 * @datetime: a #GDateTime
731 * Convert a @datetime into an instant.
733 * An instant is a number that uniquely describes a particular
734 * microsecond in time, taking time zone considerations into account.
735 * (ie: "03:00 -0400" is the same instant as "02:00 -0500").
737 * An instant is always positive but we use a signed return value to
738 * avoid troubles with C.
741 g_date_time_to_instant (GDateTime *datetime)
745 offset = g_time_zone_get_offset (datetime->tz, datetime->interval);
746 offset *= USEC_PER_SECOND;
748 return datetime->days * USEC_PER_DAY + datetime->usec - offset;
752 * g_date_time_from_instant:
754 * @instant: an instant in time
756 * Creates a #GDateTime from a time zone and an instant.
758 * This might fail if the time ends up being out of range.
761 g_date_time_from_instant (GTimeZone *tz,
767 if (instant < 0 || instant > G_GINT64_CONSTANT (1000000000000000000))
770 datetime = g_date_time_alloc (tz);
771 datetime->interval = g_time_zone_find_interval (tz,
772 G_TIME_TYPE_UNIVERSAL,
773 INSTANT_TO_UNIX (instant));
774 offset = g_time_zone_get_offset (datetime->tz, datetime->interval);
775 offset *= USEC_PER_SECOND;
779 datetime->days = instant / USEC_PER_DAY;
780 datetime->usec = instant % USEC_PER_DAY;
782 if (datetime->days < 1 || 3652059 < datetime->days)
784 g_date_time_unref (datetime);
793 * g_date_time_deal_with_date_change:
794 * @datetime: a #GDateTime
796 * This function should be called whenever the date changes by adding
797 * days, months or years. It does three things.
799 * First, we ensure that the date falls between 0001-01-01 and
800 * 9999-12-31 and return %FALSE if it does not.
802 * Next we update the ->interval field.
804 * Finally, we ensure that the resulting date and time pair exists (by
805 * ensuring that our time zone has an interval containing it) and
806 * adjusting as required. For example, if we have the time 02:30:00 on
807 * March 13 2010 in Toronto and we add 1 day to it, we would end up with
808 * 2:30am on March 14th, which doesn't exist. In that case, we bump the
812 g_date_time_deal_with_date_change (GDateTime *datetime)
818 if (datetime->days < 1 || datetime->days > 3652059)
821 was_dst = g_time_zone_is_dst (datetime->tz, datetime->interval);
823 full_time = datetime->days * USEC_PER_DAY + datetime->usec;
826 usec = full_time % USEC_PER_SECOND;
827 full_time /= USEC_PER_SECOND;
828 full_time -= UNIX_EPOCH_START * SEC_PER_DAY;
830 datetime->interval = g_time_zone_adjust_time (datetime->tz,
833 full_time += UNIX_EPOCH_START * SEC_PER_DAY;
834 full_time *= USEC_PER_SECOND;
837 datetime->days = full_time / USEC_PER_DAY;
838 datetime->usec = full_time % USEC_PER_DAY;
840 /* maybe daylight time caused us to shift to a different day,
841 * but it definitely didn't push us into a different year */
846 g_date_time_replace_days (GDateTime *datetime,
851 new = g_date_time_alloc (datetime->tz);
852 new->interval = datetime->interval;
853 new->usec = datetime->usec;
856 if (!g_date_time_deal_with_date_change (new))
858 g_date_time_unref (new);
865 /* now/unix/timeval Constructors {{{1 */
867 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
869 * g_date_time_new_from_timeval:
873 * Creates a #GDateTime corresponding to the given #GTimeVal @tv in the
874 * given time zone @tz.
876 * The time contained in a #GTimeVal is always stored in the form of
877 * seconds elapsed since 1970-01-01 00:00:00 UTC, regardless of the
880 * This call can fail (returning %NULL) if @tv represents a time outside
881 * of the supported range of #GDateTime.
883 * You should release the return value by calling g_date_time_unref()
884 * when you are done with it.
886 * Returns: a new #GDateTime, or %NULL
891 g_date_time_new_from_timeval (GTimeZone *tz,
894 gint64 tv_sec = tv->tv_sec;
896 if (tv_sec > G_MAXINT64 - 1 || !UNIX_TO_INSTANT_IS_VALID (tv_sec + 1))
899 return g_date_time_from_instant (tz, tv->tv_usec +
900 UNIX_TO_INSTANT (tv->tv_sec));
902 G_GNUC_END_IGNORE_DEPRECATIONS
905 * g_date_time_new_from_unix:
907 * @usecs: the Unix time, in microseconds since the epoch
909 * Creates a #GDateTime corresponding to the given Unix time @t_us in the
910 * given time zone @tz.
912 * Unix time is the number of seconds that have elapsed since 1970-01-01
913 * 00:00:00 UTC, regardless of the time zone given.
915 * This call can fail (returning %NULL) if @t represents a time outside
916 * of the supported range of #GDateTime.
918 * You should release the return value by calling g_date_time_unref()
919 * when you are done with it.
921 * Returns: a new #GDateTime, or %NULL
926 g_date_time_new_from_unix (GTimeZone *tz,
929 if (!UNIX_USECS_TO_INSTANT_IS_VALID (usecs))
932 return g_date_time_from_instant (tz, UNIX_USECS_TO_INSTANT (usecs));
936 * g_date_time_new_now: (constructor)
939 * Creates a #GDateTime corresponding to this exact instant in the given
940 * time zone @tz. The time is as accurate as the system allows, to a
941 * maximum accuracy of 1 microsecond.
943 * This function will always succeed unless GLib is still being used after the
946 * You should release the return value by calling g_date_time_unref()
947 * when you are done with it.
949 * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
954 g_date_time_new_now (GTimeZone *tz)
958 g_return_val_if_fail (tz != NULL, NULL);
960 now_us = g_get_real_time ();
962 return g_date_time_new_from_unix (tz, now_us);
966 * g_date_time_new_now_local: (constructor)
968 * Creates a #GDateTime corresponding to this exact instant in the local
971 * This is equivalent to calling g_date_time_new_now() with the time
972 * zone returned by g_time_zone_new_local().
974 * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
979 g_date_time_new_now_local (void)
984 local = g_time_zone_new_local ();
985 datetime = g_date_time_new_now (local);
986 g_time_zone_unref (local);
992 * g_date_time_new_now_utc: (constructor)
994 * Creates a #GDateTime corresponding to this exact instant in UTC.
996 * This is equivalent to calling g_date_time_new_now() with the time
997 * zone returned by g_time_zone_new_utc().
999 * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
1004 g_date_time_new_now_utc (void)
1006 GDateTime *datetime;
1009 utc = g_time_zone_new_utc ();
1010 datetime = g_date_time_new_now (utc);
1011 g_time_zone_unref (utc);
1017 * g_date_time_new_from_unix_local: (constructor)
1020 * Creates a #GDateTime corresponding to the given Unix time @t in the
1023 * Unix time is the number of seconds that have elapsed since 1970-01-01
1024 * 00:00:00 UTC, regardless of the local time offset.
1026 * This call can fail (returning %NULL) if @t represents a time outside
1027 * of the supported range of #GDateTime.
1029 * You should release the return value by calling g_date_time_unref()
1030 * when you are done with it.
1032 * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
1037 g_date_time_new_from_unix_local (gint64 t)
1039 if (t > G_MAXINT64 / USEC_PER_SECOND ||
1040 t < G_MININT64 / USEC_PER_SECOND)
1043 return g_date_time_new_from_unix_local_usec (t * USEC_PER_SECOND);
1047 * g_date_time_new_from_unix_local_usec: (constructor)
1048 * @usecs: the Unix time in microseconds
1050 * Creates a [struct@GLib.DateTime] corresponding to the given Unix time @t in the
1053 * Unix time is the number of microseconds that have elapsed since 1970-01-01
1054 * 00:00:00 UTC, regardless of the local time offset.
1056 * This call can fail (returning `NULL`) if @t represents a time outside
1057 * of the supported range of #GDateTime.
1059 * You should release the return value by calling [method@GLib.DateTime.unref]
1060 * when you are done with it.
1062 * Returns: (transfer full) (nullable): a new [struct@GLib.DateTime], or `NULL`
1067 g_date_time_new_from_unix_local_usec (gint64 usecs)
1069 GDateTime *datetime;
1072 local = g_time_zone_new_local ();
1073 datetime = g_date_time_new_from_unix (local, usecs);
1074 g_time_zone_unref (local);
1080 * g_date_time_new_from_unix_utc: (constructor)
1083 * Creates a #GDateTime corresponding to the given Unix time @t in UTC.
1085 * Unix time is the number of seconds that have elapsed since 1970-01-01
1088 * This call can fail (returning %NULL) if @t represents a time outside
1089 * of the supported range of #GDateTime.
1091 * You should release the return value by calling g_date_time_unref()
1092 * when you are done with it.
1094 * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
1099 g_date_time_new_from_unix_utc (gint64 t)
1101 if (t > G_MAXINT64 / USEC_PER_SECOND ||
1102 t < G_MININT64 / USEC_PER_SECOND)
1105 return g_date_time_new_from_unix_utc_usec (t * USEC_PER_SECOND);
1109 * g_date_time_new_from_unix_utc_usec: (constructor)
1110 * @usecs: the Unix time in microseconds
1112 * Creates a [struct@GLib.DateTime] corresponding to the given Unix time @t in UTC.
1114 * Unix time is the number of microseconds that have elapsed since 1970-01-01
1117 * This call can fail (returning `NULL`) if @t represents a time outside
1118 * of the supported range of #GDateTime.
1120 * You should release the return value by calling [method@GLib.DateTime.unref]
1121 * when you are done with it.
1123 * Returns: (transfer full) (nullable): a new [struct@GLib.DateTime], or `NULL`
1128 g_date_time_new_from_unix_utc_usec (gint64 usecs)
1130 GDateTime *datetime;
1133 utc = g_time_zone_new_utc ();
1134 datetime = g_date_time_new_from_unix (utc, usecs);
1135 g_time_zone_unref (utc);
1141 * g_date_time_new_from_timeval_local: (constructor)
1144 * Creates a #GDateTime corresponding to the given #GTimeVal @tv in the
1147 * The time contained in a #GTimeVal is always stored in the form of
1148 * seconds elapsed since 1970-01-01 00:00:00 UTC, regardless of the
1149 * local time offset.
1151 * This call can fail (returning %NULL) if @tv represents a time outside
1152 * of the supported range of #GDateTime.
1154 * You should release the return value by calling g_date_time_unref()
1155 * when you are done with it.
1157 * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
1160 * Deprecated: 2.62: #GTimeVal is not year-2038-safe. Use
1161 * g_date_time_new_from_unix_local() instead.
1163 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1165 g_date_time_new_from_timeval_local (const GTimeVal *tv)
1167 GDateTime *datetime;
1170 local = g_time_zone_new_local ();
1171 datetime = g_date_time_new_from_timeval (local, tv);
1172 g_time_zone_unref (local);
1176 G_GNUC_END_IGNORE_DEPRECATIONS
1179 * g_date_time_new_from_timeval_utc: (constructor)
1182 * Creates a #GDateTime corresponding to the given #GTimeVal @tv in UTC.
1184 * The time contained in a #GTimeVal is always stored in the form of
1185 * seconds elapsed since 1970-01-01 00:00:00 UTC.
1187 * This call can fail (returning %NULL) if @tv represents a time outside
1188 * of the supported range of #GDateTime.
1190 * You should release the return value by calling g_date_time_unref()
1191 * when you are done with it.
1193 * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
1196 * Deprecated: 2.62: #GTimeVal is not year-2038-safe. Use
1197 * g_date_time_new_from_unix_utc() instead.
1199 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1201 g_date_time_new_from_timeval_utc (const GTimeVal *tv)
1203 GDateTime *datetime;
1206 utc = g_time_zone_new_utc ();
1207 datetime = g_date_time_new_from_timeval (utc, tv);
1208 g_time_zone_unref (utc);
1212 G_GNUC_END_IGNORE_DEPRECATIONS
1214 /* Parse integers in the form d (week days), dd (hours etc), ddd (ordinal days) or dddd (years) */
1216 get_iso8601_int (const gchar *text, gsize length, gint *value)
1221 if (length < 1 || length > 4)
1224 for (i = 0; i < length; i++)
1226 const gchar c = text[i];
1227 if (c < '0' || c > '9')
1229 v = v * 10 + (c - '0');
1236 /* Parse seconds in the form ss or ss.sss (variable length decimal) */
1238 get_iso8601_seconds (const gchar *text, gsize length, gdouble *value)
1241 guint64 divisor = 1, v = 0;
1246 for (i = 0; i < 2; i++)
1248 const gchar c = text[i];
1249 if (c < '0' || c > '9')
1251 v = v * 10 + (c - '0');
1254 if (length > 2 && !(text[i] == '.' || text[i] == ','))
1257 /* Ignore leap seconds, see g_date_time_new_from_iso8601() */
1258 if (v >= 60.0 && v <= 61.0)
1265 for (; i < length; i++)
1267 const gchar c = text[i];
1268 if (c < '0' || c > '9' ||
1269 v > (G_MAXUINT64 - (c - '0')) / 10 ||
1270 divisor > G_MAXUINT64 / 10)
1272 v = v * 10 + (c - '0');
1276 *value = (gdouble) v / divisor;
1281 g_date_time_new_ordinal (GTimeZone *tz, gint year, gint ordinal_day, gint hour, gint minute, gdouble seconds)
1285 if (ordinal_day < 1 || ordinal_day > (GREGORIAN_LEAP (year) ? 366 : 365))
1288 dt = g_date_time_new (tz, year, 1, 1, hour, minute, seconds);
1291 dt->days += ordinal_day - 1;
1297 g_date_time_new_week (GTimeZone *tz, gint year, gint week, gint week_day, gint hour, gint minute, gdouble seconds)
1300 gint max_week, jan4_week_day, ordinal_day;
1303 p = (year * 365 + (year / 4) - (year / 100) + (year / 400)) % 7;
1304 max_week = p == 4 ? 53 : 52;
1306 if (week < 1 || week > max_week || week_day < 1 || week_day > 7)
1309 dt = g_date_time_new (tz, year, 1, 4, 0, 0, 0);
1312 g_date_time_get_week_number (dt, NULL, &jan4_week_day, NULL);
1313 g_date_time_unref (dt);
1315 ordinal_day = (week * 7) + week_day - (jan4_week_day + 3);
1316 if (ordinal_day < 0)
1319 ordinal_day += GREGORIAN_LEAP (year) ? 366 : 365;
1321 else if (ordinal_day > (GREGORIAN_LEAP (year) ? 366 : 365))
1323 ordinal_day -= (GREGORIAN_LEAP (year) ? 366 : 365);
1327 return g_date_time_new_ordinal (tz, year, ordinal_day, hour, minute, seconds);
1331 parse_iso8601_date (const gchar *text, gsize length,
1332 gint hour, gint minute, gdouble seconds, GTimeZone *tz)
1335 if (length == 10 && text[4] == '-' && text[7] == '-')
1337 int year, month, day;
1338 if (!get_iso8601_int (text, 4, &year) ||
1339 !get_iso8601_int (text + 5, 2, &month) ||
1340 !get_iso8601_int (text + 8, 2, &day))
1342 return g_date_time_new (tz, year, month, day, hour, minute, seconds);
1345 else if (length == 8 && text[4] == '-')
1347 gint year, ordinal_day;
1348 if (!get_iso8601_int (text, 4, &year) ||
1349 !get_iso8601_int (text + 5, 3, &ordinal_day))
1351 return g_date_time_new_ordinal (tz, year, ordinal_day, hour, minute, seconds);
1354 else if (length == 10 && text[4] == '-' && text[5] == 'W' && text[8] == '-')
1356 gint year, week, week_day;
1357 if (!get_iso8601_int (text, 4, &year) ||
1358 !get_iso8601_int (text + 6, 2, &week) ||
1359 !get_iso8601_int (text + 9, 1, &week_day))
1361 return g_date_time_new_week (tz, year, week, week_day, hour, minute, seconds);
1364 else if (length == 8 && text[4] == 'W')
1366 gint year, week, week_day;
1367 if (!get_iso8601_int (text, 4, &year) ||
1368 !get_iso8601_int (text + 5, 2, &week) ||
1369 !get_iso8601_int (text + 7, 1, &week_day))
1371 return g_date_time_new_week (tz, year, week, week_day, hour, minute, seconds);
1374 else if (length == 8)
1376 int year, month, day;
1377 if (!get_iso8601_int (text, 4, &year) ||
1378 !get_iso8601_int (text + 4, 2, &month) ||
1379 !get_iso8601_int (text + 6, 2, &day))
1381 return g_date_time_new (tz, year, month, day, hour, minute, seconds);
1384 else if (length == 7)
1386 gint year, ordinal_day;
1387 if (!get_iso8601_int (text, 4, &year) ||
1388 !get_iso8601_int (text + 4, 3, &ordinal_day))
1390 return g_date_time_new_ordinal (tz, year, ordinal_day, hour, minute, seconds);
1397 parse_iso8601_timezone (const gchar *text, gsize length, gssize *tz_offset)
1399 gint i, tz_length, offset_hours, offset_minutes;
1400 gint offset_sign = 1;
1403 /* UTC uses Z suffix */
1404 if (length > 0 && text[length - 1] == 'Z')
1406 *tz_offset = length - 1;
1407 return g_time_zone_new_utc ();
1410 /* Look for '+' or '-' of offset */
1411 for (i = length - 1; i >= 0; i--)
1412 if (text[i] == '+' || text[i] == '-')
1414 offset_sign = text[i] == '-' ? -1 : 1;
1419 tz_length = length - i;
1421 /* +hh:mm or -hh:mm */
1422 if (tz_length == 6 && text[i+3] == ':')
1424 if (!get_iso8601_int (text + i + 1, 2, &offset_hours) ||
1425 !get_iso8601_int (text + i + 4, 2, &offset_minutes))
1428 /* +hhmm or -hhmm */
1429 else if (tz_length == 5)
1431 if (!get_iso8601_int (text + i + 1, 2, &offset_hours) ||
1432 !get_iso8601_int (text + i + 3, 2, &offset_minutes))
1436 else if (tz_length == 3)
1438 if (!get_iso8601_int (text + i + 1, 2, &offset_hours))
1446 tz = g_time_zone_new_identifier (text + i);
1448 /* Double-check that the GTimeZone matches our interpretation of the timezone.
1449 * This can fail because our interpretation is less strict than (for example)
1450 * parse_time() in gtimezone.c, which restricts the range of the parsed
1452 if (tz == NULL || g_time_zone_get_offset (tz, 0) != offset_sign * (offset_hours * 3600 + offset_minutes * 60))
1454 g_clear_pointer (&tz, g_time_zone_unref);
1462 parse_iso8601_time (const gchar *text, gsize length,
1463 gint *hour, gint *minute, gdouble *seconds, GTimeZone **tz)
1465 gssize tz_offset = -1;
1467 /* Check for timezone suffix */
1468 *tz = parse_iso8601_timezone (text, length, &tz_offset);
1472 /* hh:mm:ss(.sss) */
1473 if (length >= 8 && text[2] == ':' && text[5] == ':')
1475 return get_iso8601_int (text, 2, hour) &&
1476 get_iso8601_int (text + 3, 2, minute) &&
1477 get_iso8601_seconds (text + 6, length - 6, seconds);
1480 else if (length >= 6)
1482 return get_iso8601_int (text, 2, hour) &&
1483 get_iso8601_int (text + 2, 2, minute) &&
1484 get_iso8601_seconds (text + 4, length - 4, seconds);
1491 * g_date_time_new_from_iso8601: (constructor)
1492 * @text: an ISO 8601 formatted time string.
1493 * @default_tz: (nullable): a #GTimeZone to use if the text doesn't contain a
1494 * timezone, or %NULL.
1496 * Creates a #GDateTime corresponding to the given
1497 * [ISO 8601 formatted string](https://en.wikipedia.org/wiki/ISO_8601)
1498 * @text. ISO 8601 strings of the form <date><sep><time><tz> are supported, with
1499 * some extensions from [RFC 3339](https://tools.ietf.org/html/rfc3339) as
1502 * Note that as #GDateTime "is oblivious to leap seconds", leap seconds information
1503 * in an ISO-8601 string will be ignored, so a `23:59:60` time would be parsed as
1506 * <sep> is the separator and can be either 'T', 't' or ' '. The latter two
1507 * separators are an extension from
1508 * [RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6).
1510 * <date> is in the form:
1512 * - `YYYY-MM-DD` - Year/month/day, e.g. 2016-08-24.
1513 * - `YYYYMMDD` - Same as above without dividers.
1514 * - `YYYY-DDD` - Ordinal day where DDD is from 001 to 366, e.g. 2016-237.
1515 * - `YYYYDDD` - Same as above without dividers.
1516 * - `YYYY-Www-D` - Week day where ww is from 01 to 52 and D from 1-7,
1518 * - `YYYYWwwD` - Same as above without dividers.
1520 * <time> is in the form:
1522 * - `hh:mm:ss(.sss)` - Hours, minutes, seconds (subseconds), e.g. 22:10:42.123.
1523 * - `hhmmss(.sss)` - Same as above without dividers.
1525 * <tz> is an optional timezone suffix of the form:
1528 * - `+hh:mm` or `-hh:mm` - Offset from UTC in hours and minutes, e.g. +12:00.
1529 * - `+hh` or `-hh` - Offset from UTC in hours, e.g. +12.
1531 * If the timezone is not provided in @text it must be provided in @default_tz
1532 * (this field is otherwise ignored).
1534 * This call can fail (returning %NULL) if @text is not a valid ISO 8601
1537 * You should release the return value by calling g_date_time_unref()
1538 * when you are done with it.
1540 * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
1545 g_date_time_new_from_iso8601 (const gchar *text, GTimeZone *default_tz)
1547 gint length, date_length = -1;
1548 gint hour = 0, minute = 0;
1549 gdouble seconds = 0.0;
1550 GTimeZone *tz = NULL;
1551 GDateTime *datetime = NULL;
1553 g_return_val_if_fail (text != NULL, NULL);
1555 /* Count length of string and find date / time separator ('T', 't', or ' ') */
1556 for (length = 0; text[length] != '\0'; length++)
1558 if (date_length < 0 && (text[length] == 'T' || text[length] == 't' || text[length] == ' '))
1559 date_length = length;
1562 if (date_length < 0)
1565 if (!parse_iso8601_time (text + date_length + 1, length - (date_length + 1),
1566 &hour, &minute, &seconds, &tz))
1568 if (tz == NULL && default_tz == NULL)
1571 datetime = parse_iso8601_date (text, date_length, hour, minute, seconds, tz ? tz : default_tz);
1575 g_time_zone_unref (tz);
1579 /* full new functions {{{1 */
1582 * g_date_time_new: (constructor)
1584 * @year: the year component of the date
1585 * @month: the month component of the date
1586 * @day: the day component of the date
1587 * @hour: the hour component of the date
1588 * @minute: the minute component of the date
1589 * @seconds: the number of seconds past the minute
1591 * Creates a new #GDateTime corresponding to the given date and time in
1592 * the time zone @tz.
1594 * The @year must be between 1 and 9999, @month between 1 and 12 and @day
1595 * between 1 and 28, 29, 30 or 31 depending on the month and the year.
1597 * @hour must be between 0 and 23 and @minute must be between 0 and 59.
1599 * @seconds must be at least 0.0 and must be strictly less than 60.0.
1600 * It will be rounded down to the nearest microsecond.
1602 * If the given time is not representable in the given time zone (for
1603 * example, 02:30 on March 14th 2010 in Toronto, due to daylight savings
1604 * time) then the time will be rounded up to the nearest existing time
1605 * (in this case, 03:00). If this matters to you then you should verify
1606 * the return value for containing the same as the numbers you gave.
1608 * In the case that the given time is ambiguous in the given time zone
1609 * (for example, 01:30 on November 7th 2010 in Toronto, due to daylight
1610 * savings time) then the time falling within standard (ie:
1611 * non-daylight) time is taken.
1613 * It not considered a programmer error for the values to this function
1614 * to be out of range, but in the case that they are, the function will
1617 * You should release the return value by calling g_date_time_unref()
1618 * when you are done with it.
1620 * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
1625 g_date_time_new (GTimeZone *tz,
1633 GDateTime *datetime;
1635 /* keep these variables as volatile. We do not want them ending up in
1636 * registers - them doing so may cause us to hit precision problems on i386.
1637 * See: https://bugzilla.gnome.org/show_bug.cgi?id=792410 */
1638 volatile gint64 usec;
1639 volatile gdouble usecd;
1641 g_return_val_if_fail (tz != NULL, NULL);
1643 if (year < 1 || year > 9999 ||
1644 month < 1 || month > 12 ||
1645 day < 1 || day > days_in_months[GREGORIAN_LEAP (year)][month] ||
1646 hour < 0 || hour > 23 ||
1647 minute < 0 || minute > 59 ||
1649 seconds < 0.0 || seconds >= 60.0)
1652 datetime = g_date_time_alloc (tz);
1653 datetime->days = ymd_to_days (year, month, day);
1654 datetime->usec = (hour * USEC_PER_HOUR)
1655 + (minute * USEC_PER_MINUTE)
1656 + (gint64) (seconds * USEC_PER_SECOND);
1658 full_time = SEC_PER_DAY *
1659 (ymd_to_days (year, month, day) - UNIX_EPOCH_START) +
1660 SECS_PER_HOUR * hour +
1661 SECS_PER_MINUTE * minute +
1664 datetime->interval = g_time_zone_adjust_time (datetime->tz,
1665 G_TIME_TYPE_STANDARD,
1668 /* This is the correct way to convert a scaled FP value to integer.
1669 * If this surprises you, please observe that (int)(1.000001 * 1e6)
1670 * is 1000000. This is not a problem with precision, it's just how
1672 * See https://bugzilla.gnome.org/show_bug.cgi?id=697715. */
1673 usec = seconds * USEC_PER_SECOND;
1674 usecd = (usec + 1) * 1e-6;
1675 if (usecd <= seconds) {
1679 full_time += UNIX_EPOCH_START * SEC_PER_DAY;
1680 datetime->days = full_time / SEC_PER_DAY;
1681 datetime->usec = (full_time % SEC_PER_DAY) * USEC_PER_SECOND;
1682 datetime->usec += usec % USEC_PER_SECOND;
1688 * g_date_time_new_local: (constructor)
1689 * @year: the year component of the date
1690 * @month: the month component of the date
1691 * @day: the day component of the date
1692 * @hour: the hour component of the date
1693 * @minute: the minute component of the date
1694 * @seconds: the number of seconds past the minute
1696 * Creates a new #GDateTime corresponding to the given date and time in
1697 * the local time zone.
1699 * This call is equivalent to calling g_date_time_new() with the time
1700 * zone returned by g_time_zone_new_local().
1702 * Returns: (transfer full) (nullable): a #GDateTime, or %NULL
1707 g_date_time_new_local (gint year,
1714 GDateTime *datetime;
1717 local = g_time_zone_new_local ();
1718 datetime = g_date_time_new (local, year, month, day, hour, minute, seconds);
1719 g_time_zone_unref (local);
1725 * g_date_time_new_utc: (constructor)
1726 * @year: the year component of the date
1727 * @month: the month component of the date
1728 * @day: the day component of the date
1729 * @hour: the hour component of the date
1730 * @minute: the minute component of the date
1731 * @seconds: the number of seconds past the minute
1733 * Creates a new #GDateTime corresponding to the given date and time in
1736 * This call is equivalent to calling g_date_time_new() with the time
1737 * zone returned by g_time_zone_new_utc().
1739 * Returns: (transfer full) (nullable): a #GDateTime, or %NULL
1744 g_date_time_new_utc (gint year,
1751 GDateTime *datetime;
1754 utc = g_time_zone_new_utc ();
1755 datetime = g_date_time_new (utc, year, month, day, hour, minute, seconds);
1756 g_time_zone_unref (utc);
1765 * @datetime: a #GDateTime
1766 * @timespan: a #GTimeSpan
1768 * Creates a copy of @datetime and adds the specified timespan to the copy.
1770 * Returns: (transfer full) (nullable): the newly created #GDateTime which
1771 * should be freed with g_date_time_unref(), or %NULL
1776 g_date_time_add (GDateTime *datetime,
1779 g_return_val_if_fail (datetime != NULL, NULL);
1781 return g_date_time_from_instant (datetime->tz, timespan +
1782 g_date_time_to_instant (datetime));
1786 * g_date_time_add_years:
1787 * @datetime: a #GDateTime
1788 * @years: the number of years
1790 * Creates a copy of @datetime and adds the specified number of years to the
1791 * copy. Add negative values to subtract years.
1793 * As with g_date_time_add_months(), if the resulting date would be 29th
1794 * February on a non-leap year, the day will be clamped to 28th February.
1796 * Returns: (transfer full) (nullable): the newly created #GDateTime which
1797 * should be freed with g_date_time_unref(), or %NULL
1802 g_date_time_add_years (GDateTime *datetime,
1805 gint year, month, day;
1807 g_return_val_if_fail (datetime != NULL, NULL);
1809 if (years < -10000 || years > 10000)
1812 g_date_time_get_ymd (datetime, &year, &month, &day);
1815 /* only possible issue is if we've entered a year with no February 29
1817 if (month == 2 && day == 29 && !GREGORIAN_LEAP (year))
1820 return g_date_time_replace_days (datetime, ymd_to_days (year, month, day));
1824 * g_date_time_add_months:
1825 * @datetime: a #GDateTime
1826 * @months: the number of months
1828 * Creates a copy of @datetime and adds the specified number of months to the
1829 * copy. Add negative values to subtract months.
1831 * The day of the month of the resulting #GDateTime is clamped to the number
1832 * of days in the updated calendar month. For example, if adding 1 month to
1833 * 31st January 2018, the result would be 28th February 2018. In 2020 (a leap
1834 * year), the result would be 29th February.
1836 * Returns: (transfer full) (nullable): the newly created #GDateTime which
1837 * should be freed with g_date_time_unref(), or %NULL
1842 g_date_time_add_months (GDateTime *datetime,
1845 gint year, month, day;
1847 g_return_val_if_fail (datetime != NULL, NULL);
1848 g_date_time_get_ymd (datetime, &year, &month, &day);
1850 if (months < -120000 || months > 120000)
1853 year += months / 12;
1854 month += months % 12;
1860 else if (month > 12)
1866 day = MIN (day, days_in_months[GREGORIAN_LEAP (year)][month]);
1868 return g_date_time_replace_days (datetime, ymd_to_days (year, month, day));
1872 * g_date_time_add_weeks:
1873 * @datetime: a #GDateTime
1874 * @weeks: the number of weeks
1876 * Creates a copy of @datetime and adds the specified number of weeks to the
1877 * copy. Add negative values to subtract weeks.
1879 * Returns: (transfer full) (nullable): the newly created #GDateTime which
1880 * should be freed with g_date_time_unref(), or %NULL
1885 g_date_time_add_weeks (GDateTime *datetime,
1888 g_return_val_if_fail (datetime != NULL, NULL);
1890 return g_date_time_add_days (datetime, weeks * 7);
1894 * g_date_time_add_days:
1895 * @datetime: a #GDateTime
1896 * @days: the number of days
1898 * Creates a copy of @datetime and adds the specified number of days to the
1899 * copy. Add negative values to subtract days.
1901 * Returns: (transfer full) (nullable): the newly created #GDateTime which
1902 * should be freed with g_date_time_unref(), or %NULL
1907 g_date_time_add_days (GDateTime *datetime,
1910 g_return_val_if_fail (datetime != NULL, NULL);
1912 if (days < -3660000 || days > 3660000)
1915 return g_date_time_replace_days (datetime, datetime->days + days);
1919 * g_date_time_add_hours:
1920 * @datetime: a #GDateTime
1921 * @hours: the number of hours to add
1923 * Creates a copy of @datetime and adds the specified number of hours.
1924 * Add negative values to subtract hours.
1926 * Returns: (transfer full) (nullable): the newly created #GDateTime which
1927 * should be freed with g_date_time_unref(), or %NULL
1932 g_date_time_add_hours (GDateTime *datetime,
1935 return g_date_time_add (datetime, hours * USEC_PER_HOUR);
1939 * g_date_time_add_minutes:
1940 * @datetime: a #GDateTime
1941 * @minutes: the number of minutes to add
1943 * Creates a copy of @datetime adding the specified number of minutes.
1944 * Add negative values to subtract minutes.
1946 * Returns: (transfer full) (nullable): the newly created #GDateTime which
1947 * should be freed with g_date_time_unref(), or %NULL
1952 g_date_time_add_minutes (GDateTime *datetime,
1955 return g_date_time_add (datetime, minutes * USEC_PER_MINUTE);
1960 * g_date_time_add_seconds:
1961 * @datetime: a #GDateTime
1962 * @seconds: the number of seconds to add
1964 * Creates a copy of @datetime and adds the specified number of seconds.
1965 * Add negative values to subtract seconds.
1967 * Returns: (transfer full) (nullable): the newly created #GDateTime which
1968 * should be freed with g_date_time_unref(), or %NULL
1973 g_date_time_add_seconds (GDateTime *datetime,
1976 return g_date_time_add (datetime, seconds * USEC_PER_SECOND);
1980 * g_date_time_add_full:
1981 * @datetime: a #GDateTime
1982 * @years: the number of years to add
1983 * @months: the number of months to add
1984 * @days: the number of days to add
1985 * @hours: the number of hours to add
1986 * @minutes: the number of minutes to add
1987 * @seconds: the number of seconds to add
1989 * Creates a new #GDateTime adding the specified values to the current date and
1990 * time in @datetime. Add negative values to subtract.
1992 * Returns: (transfer full) (nullable): the newly created #GDateTime which
1993 * should be freed with g_date_time_unref(), or %NULL
1998 g_date_time_add_full (GDateTime *datetime,
2006 gint year, month, day;
2011 g_return_val_if_fail (datetime != NULL, NULL);
2012 g_date_time_get_ymd (datetime, &year, &month, &day);
2014 months += years * 12;
2016 if (months < -120000 || months > 120000)
2019 if (days < -3660000 || days > 3660000)
2022 year += months / 12;
2023 month += months % 12;
2029 else if (month > 12)
2035 day = MIN (day, days_in_months[GREGORIAN_LEAP (year)][month]);
2037 /* full_time is now in unix (local) time */
2038 full_time = datetime->usec / USEC_PER_SECOND + SEC_PER_DAY *
2039 (ymd_to_days (year, month, day) + days - UNIX_EPOCH_START);
2041 interval = g_time_zone_adjust_time (datetime->tz,
2042 g_time_zone_is_dst (datetime->tz,
2043 datetime->interval),
2046 /* move to UTC unix time */
2047 full_time -= g_time_zone_get_offset (datetime->tz, interval);
2049 /* convert back to an instant, add back fractional seconds */
2050 full_time += UNIX_EPOCH_START * SEC_PER_DAY;
2051 full_time = full_time * USEC_PER_SECOND +
2052 datetime->usec % USEC_PER_SECOND;
2054 /* do the actual addition now */
2055 full_time += (hours * USEC_PER_HOUR) +
2056 (minutes * USEC_PER_MINUTE) +
2057 (gint64) (seconds * USEC_PER_SECOND);
2059 /* find the new interval */
2060 interval = g_time_zone_find_interval (datetime->tz,
2061 G_TIME_TYPE_UNIVERSAL,
2062 INSTANT_TO_UNIX (full_time));
2064 /* convert back into local time */
2065 full_time += USEC_PER_SECOND *
2066 g_time_zone_get_offset (datetime->tz, interval);
2068 /* split into days and usec of a new datetime */
2069 new = g_date_time_alloc (datetime->tz);
2070 new->interval = interval;
2071 new->days = full_time / USEC_PER_DAY;
2072 new->usec = full_time % USEC_PER_DAY;
2079 /* Compare, difference, hash, equal {{{1 */
2081 * g_date_time_compare:
2082 * @dt1: (type GDateTime) (not nullable): first #GDateTime to compare
2083 * @dt2: (type GDateTime) (not nullable): second #GDateTime to compare
2085 * A comparison function for #GDateTimes that is suitable
2086 * as a #GCompareFunc. Both #GDateTimes must be non-%NULL.
2088 * Returns: -1, 0 or 1 if @dt1 is less than, equal to or greater
2094 g_date_time_compare (gconstpointer dt1,
2099 difference = g_date_time_difference ((GDateTime *) dt1, (GDateTime *) dt2);
2104 else if (difference > 0)
2112 * g_date_time_difference:
2113 * @end: a #GDateTime
2114 * @begin: a #GDateTime
2116 * Calculates the difference in time between @end and @begin. The
2117 * #GTimeSpan that is returned is effectively @end - @begin (ie:
2118 * positive if the first parameter is larger).
2120 * Returns: the difference between the two #GDateTime, as a time
2121 * span expressed in microseconds.
2126 g_date_time_difference (GDateTime *end,
2129 g_return_val_if_fail (begin != NULL, 0);
2130 g_return_val_if_fail (end != NULL, 0);
2132 return g_date_time_to_instant (end) -
2133 g_date_time_to_instant (begin);
2138 * @datetime: (type GDateTime) (not nullable): a #GDateTime
2140 * Hashes @datetime into a #guint, suitable for use within #GHashTable.
2142 * Returns: a #guint containing the hash
2147 g_date_time_hash (gconstpointer datetime)
2149 g_return_val_if_fail (datetime != NULL, 0);
2151 return g_date_time_to_instant ((GDateTime *) datetime);
2155 * g_date_time_equal:
2156 * @dt1: (type GDateTime) (not nullable): a #GDateTime
2157 * @dt2: (type GDateTime) (not nullable): a #GDateTime
2159 * Checks to see if @dt1 and @dt2 are equal.
2161 * Equal here means that they represent the same moment after converting
2162 * them to the same time zone.
2164 * Returns: %TRUE if @dt1 and @dt2 are equal
2169 g_date_time_equal (gconstpointer dt1,
2172 return g_date_time_difference ((GDateTime *) dt1, (GDateTime *) dt2) == 0;
2175 /* Year, Month, Day Getters {{{1 */
2177 * g_date_time_get_ymd:
2178 * @datetime: a #GDateTime.
2179 * @year: (out) (optional): the return location for the gregorian year, or %NULL.
2180 * @month: (out) (optional): the return location for the month of the year, or %NULL.
2181 * @day: (out) (optional): the return location for the day of the month, or %NULL.
2183 * Retrieves the Gregorian day, month, and year of a given #GDateTime.
2188 g_date_time_get_ymd (GDateTime *datetime,
2196 gint remaining_days;
2203 g_return_if_fail (datetime != NULL);
2205 remaining_days = datetime->days;
2208 * We need to convert an offset in days to its year/month/day representation.
2209 * Leap years makes this a little trickier than it should be, so we use
2210 * 400, 100 and 4 years cycles here to get to the correct year.
2213 /* Our days offset starts sets 0001-01-01 as day 1, if it was day 0 our
2214 * math would be simpler, so let's do it */
2217 the_year = (remaining_days / DAYS_IN_400YEARS) * 400 + 1;
2218 remaining_days = remaining_days % DAYS_IN_400YEARS;
2220 y100_cycles = remaining_days / DAYS_IN_100YEARS;
2221 remaining_days = remaining_days % DAYS_IN_100YEARS;
2222 the_year += y100_cycles * 100;
2224 y4_cycles = remaining_days / DAYS_IN_4YEARS;
2225 remaining_days = remaining_days % DAYS_IN_4YEARS;
2226 the_year += y4_cycles * 4;
2228 y1_cycles = remaining_days / 365;
2229 the_year += y1_cycles;
2230 remaining_days = remaining_days % 365;
2232 if (y1_cycles == 4 || y100_cycles == 4) {
2233 g_assert (remaining_days == 0);
2235 /* special case that indicates that the date is actually one year before,
2236 * in the 31th of December */
2243 /* now get the month and the day */
2244 leap = y1_cycles == 3 && (y4_cycles != 24 || y100_cycles == 3);
2246 g_assert (leap == GREGORIAN_LEAP(the_year));
2248 the_month = (remaining_days + 50) >> 5;
2249 preceding = (days_in_year[0][the_month - 1] + (the_month > 2 && leap));
2250 if (preceding > remaining_days)
2252 /* estimate is too large */
2254 preceding -= leap ? days_in_months[1][the_month]
2255 : days_in_months[0][the_month];
2258 remaining_days -= preceding;
2259 g_assert(0 <= remaining_days);
2261 the_day = remaining_days + 1;
2273 * g_date_time_get_year:
2274 * @datetime: A #GDateTime
2276 * Retrieves the year represented by @datetime in the Gregorian calendar.
2278 * Returns: the year represented by @datetime
2283 g_date_time_get_year (GDateTime *datetime)
2287 g_return_val_if_fail (datetime != NULL, 0);
2289 g_date_time_get_ymd (datetime, &year, NULL, NULL);
2295 * g_date_time_get_month:
2296 * @datetime: a #GDateTime
2298 * Retrieves the month of the year represented by @datetime in the Gregorian
2301 * Returns: the month represented by @datetime
2306 g_date_time_get_month (GDateTime *datetime)
2310 g_return_val_if_fail (datetime != NULL, 0);
2312 g_date_time_get_ymd (datetime, NULL, &month, NULL);
2318 * g_date_time_get_day_of_month:
2319 * @datetime: a #GDateTime
2321 * Retrieves the day of the month represented by @datetime in the gregorian
2324 * Returns: the day of the month
2329 g_date_time_get_day_of_month (GDateTime *datetime)
2336 g_return_val_if_fail (datetime != NULL, 0);
2338 is_leap = GREGORIAN_LEAP (g_date_time_get_year (datetime)) ? 1 : 0;
2339 g_date_time_get_week_number (datetime, NULL, NULL, &day_of_year);
2341 for (i = 1; i <= 12; i++)
2343 if (days_in_year[is_leap][i] >= day_of_year)
2344 return day_of_year - last;
2345 last = days_in_year[is_leap][i];
2348 g_warn_if_reached ();
2352 /* Week of year / day of week getters {{{1 */
2354 * g_date_time_get_week_numbering_year:
2355 * @datetime: a #GDateTime
2357 * Returns the ISO 8601 week-numbering year in which the week containing
2360 * This function, taken together with g_date_time_get_week_of_year() and
2361 * g_date_time_get_day_of_week() can be used to determine the full ISO
2362 * week date on which @datetime falls.
2364 * This is usually equal to the normal Gregorian year (as returned by
2365 * g_date_time_get_year()), except as detailed below:
2367 * For Thursday, the week-numbering year is always equal to the usual
2368 * calendar year. For other days, the number is such that every day
2369 * within a complete week (Monday to Sunday) is contained within the
2370 * same week-numbering year.
2372 * For Monday, Tuesday and Wednesday occurring near the end of the year,
2373 * this may mean that the week-numbering year is one greater than the
2374 * calendar year (so that these days have the same week-numbering year
2375 * as the Thursday occurring early in the next year).
2377 * For Friday, Saturday and Sunday occurring near the start of the year,
2378 * this may mean that the week-numbering year is one less than the
2379 * calendar year (so that these days have the same week-numbering year
2380 * as the Thursday occurring late in the previous year).
2382 * An equivalent description is that the week-numbering year is equal to
2383 * the calendar year containing the majority of the days in the current
2384 * week (Monday to Sunday).
2386 * Note that January 1 0001 in the proleptic Gregorian calendar is a
2387 * Monday, so this function never returns 0.
2389 * Returns: the ISO 8601 week-numbering year for @datetime
2394 g_date_time_get_week_numbering_year (GDateTime *datetime)
2396 gint year = -1, month = -1, day = -1, weekday;
2398 g_date_time_get_ymd (datetime, &year, &month, &day);
2399 weekday = g_date_time_get_day_of_week (datetime);
2401 /* January 1, 2, 3 might be in the previous year if they occur after
2404 * Jan 1: Friday, Saturday, Sunday => day 1: weekday 5, 6, 7
2405 * Jan 2: Saturday, Sunday => day 2: weekday 6, 7
2406 * Jan 3: Sunday => day 3: weekday 7
2408 * So we have a special case if (day - weekday) <= -4
2410 if (month == 1 && (day - weekday) <= -4)
2413 /* December 29, 30, 31 might be in the next year if they occur before
2416 * Dec 31: Monday, Tuesday, Wednesday => day 31: weekday 1, 2, 3
2417 * Dec 30: Monday, Tuesday => day 30: weekday 1, 2
2418 * Dec 29: Monday => day 29: weekday 1
2420 * So we have a special case if (day - weekday) >= 28
2422 else if (month == 12 && (day - weekday) >= 28)
2430 * g_date_time_get_week_of_year:
2431 * @datetime: a #GDateTime
2433 * Returns the ISO 8601 week number for the week containing @datetime.
2434 * The ISO 8601 week number is the same for every day of the week (from
2435 * Moday through Sunday). That can produce some unusual results
2436 * (described below).
2438 * The first week of the year is week 1. This is the week that contains
2439 * the first Thursday of the year. Equivalently, this is the first week
2440 * that has more than 4 of its days falling within the calendar year.
2442 * The value 0 is never returned by this function. Days contained
2443 * within a year but occurring before the first ISO 8601 week of that
2444 * year are considered as being contained in the last week of the
2445 * previous year. Similarly, the final days of a calendar year may be
2446 * considered as being part of the first ISO 8601 week of the next year
2447 * if 4 or more days of that week are contained within the new year.
2449 * Returns: the ISO 8601 week number for @datetime.
2454 g_date_time_get_week_of_year (GDateTime *datetime)
2458 g_return_val_if_fail (datetime != NULL, 0);
2460 g_date_time_get_week_number (datetime, &weeknum, NULL, NULL);
2466 * g_date_time_get_day_of_week:
2467 * @datetime: a #GDateTime
2469 * Retrieves the ISO 8601 day of the week on which @datetime falls (1 is
2470 * Monday, 2 is Tuesday... 7 is Sunday).
2472 * Returns: the day of the week
2477 g_date_time_get_day_of_week (GDateTime *datetime)
2479 g_return_val_if_fail (datetime != NULL, 0);
2481 return (datetime->days - 1) % 7 + 1;
2484 /* Day of year getter {{{1 */
2486 * g_date_time_get_day_of_year:
2487 * @datetime: a #GDateTime
2489 * Retrieves the day of the year represented by @datetime in the Gregorian
2492 * Returns: the day of the year
2497 g_date_time_get_day_of_year (GDateTime *datetime)
2501 g_return_val_if_fail (datetime != NULL, 0);
2503 g_date_time_get_week_number (datetime, NULL, NULL, &doy);
2507 /* Time component getters {{{1 */
2510 * g_date_time_get_hour:
2511 * @datetime: a #GDateTime
2513 * Retrieves the hour of the day represented by @datetime
2515 * Returns: the hour of the day
2520 g_date_time_get_hour (GDateTime *datetime)
2522 g_return_val_if_fail (datetime != NULL, 0);
2524 return (datetime->usec / USEC_PER_HOUR);
2528 * g_date_time_get_minute:
2529 * @datetime: a #GDateTime
2531 * Retrieves the minute of the hour represented by @datetime
2533 * Returns: the minute of the hour
2538 g_date_time_get_minute (GDateTime *datetime)
2540 g_return_val_if_fail (datetime != NULL, 0);
2542 return (datetime->usec % USEC_PER_HOUR) / USEC_PER_MINUTE;
2546 * g_date_time_get_second:
2547 * @datetime: a #GDateTime
2549 * Retrieves the second of the minute represented by @datetime
2551 * Returns: the second represented by @datetime
2556 g_date_time_get_second (GDateTime *datetime)
2558 g_return_val_if_fail (datetime != NULL, 0);
2560 return (datetime->usec % USEC_PER_MINUTE) / USEC_PER_SECOND;
2564 * g_date_time_get_microsecond:
2565 * @datetime: a #GDateTime
2567 * Retrieves the microsecond of the date represented by @datetime
2569 * Returns: the microsecond of the second
2574 g_date_time_get_microsecond (GDateTime *datetime)
2576 g_return_val_if_fail (datetime != NULL, 0);
2578 return (datetime->usec % USEC_PER_SECOND);
2582 * g_date_time_get_seconds:
2583 * @datetime: a #GDateTime
2585 * Retrieves the number of seconds since the start of the last minute,
2586 * including the fractional part.
2588 * Returns: the number of seconds
2593 g_date_time_get_seconds (GDateTime *datetime)
2595 g_return_val_if_fail (datetime != NULL, 0);
2597 return (datetime->usec % USEC_PER_MINUTE) / 1000000.0;
2600 /* Exporters {{{1 */
2602 * g_date_time_to_unix:
2603 * @datetime: a #GDateTime
2605 * Gives the Unix time corresponding to @datetime, rounding down to the
2608 * Unix time is the number of seconds that have elapsed since 1970-01-01
2609 * 00:00:00 UTC, regardless of the time zone associated with @datetime.
2611 * Returns: the Unix time corresponding to @datetime
2616 g_date_time_to_unix (GDateTime *datetime)
2618 g_return_val_if_fail (datetime != NULL, 0);
2620 return INSTANT_TO_UNIX (g_date_time_to_instant (datetime));
2624 * g_date_time_to_unix_usec:
2625 * @datetime: a #GDateTime
2627 * Gives the Unix time corresponding to @datetime, in microseconds.
2629 * Unix time is the number of microseconds that have elapsed since 1970-01-01
2630 * 00:00:00 UTC, regardless of the time zone associated with @datetime.
2632 * Returns: the Unix time corresponding to @datetime
2637 g_date_time_to_unix_usec (GDateTime *datetime)
2639 g_return_val_if_fail (datetime != NULL, 0);
2641 return INSTANT_TO_UNIX_USECS (g_date_time_to_instant (datetime));
2645 * g_date_time_to_timeval:
2646 * @datetime: a #GDateTime
2647 * @tv: a #GTimeVal to modify
2649 * Stores the instant in time that @datetime represents into @tv.
2651 * The time contained in a #GTimeVal is always stored in the form of
2652 * seconds elapsed since 1970-01-01 00:00:00 UTC, regardless of the time
2653 * zone associated with @datetime.
2655 * On systems where 'long' is 32bit (ie: all 32bit systems and all
2656 * Windows systems), a #GTimeVal is incapable of storing the entire
2657 * range of values that #GDateTime is capable of expressing. On those
2658 * systems, this function returns %FALSE to indicate that the time is
2661 * On systems where 'long' is 64bit, this function never fails.
2663 * Returns: %TRUE if successful, else %FALSE
2666 * Deprecated: 2.62: #GTimeVal is not year-2038-safe. Use
2667 * g_date_time_to_unix() instead.
2669 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
2671 g_date_time_to_timeval (GDateTime *datetime,
2674 g_return_val_if_fail (datetime != NULL, FALSE);
2676 tv->tv_sec = INSTANT_TO_UNIX (g_date_time_to_instant (datetime));
2677 tv->tv_usec = datetime->usec % USEC_PER_SECOND;
2681 G_GNUC_END_IGNORE_DEPRECATIONS
2683 /* Timezone queries {{{1 */
2685 * g_date_time_get_utc_offset:
2686 * @datetime: a #GDateTime
2688 * Determines the offset to UTC in effect at the time and in the time
2689 * zone of @datetime.
2691 * The offset is the number of microseconds that you add to UTC time to
2692 * arrive at local time for the time zone (ie: negative numbers for time
2693 * zones west of GMT, positive numbers for east).
2695 * If @datetime represents UTC time, then the offset is always zero.
2697 * Returns: the number of microseconds that should be added to UTC to
2698 * get the local time
2703 g_date_time_get_utc_offset (GDateTime *datetime)
2707 g_return_val_if_fail (datetime != NULL, 0);
2709 offset = g_time_zone_get_offset (datetime->tz, datetime->interval);
2711 return (gint64) offset * USEC_PER_SECOND;
2715 * g_date_time_get_timezone:
2716 * @datetime: a #GDateTime
2718 * Get the time zone for this @datetime.
2720 * Returns: (transfer none): the time zone
2724 g_date_time_get_timezone (GDateTime *datetime)
2726 g_return_val_if_fail (datetime != NULL, NULL);
2728 g_assert (datetime->tz != NULL);
2729 return datetime->tz;
2733 * g_date_time_get_timezone_abbreviation:
2734 * @datetime: a #GDateTime
2736 * Determines the time zone abbreviation to be used at the time and in
2737 * the time zone of @datetime.
2739 * For example, in Toronto this is currently "EST" during the winter
2740 * months and "EDT" during the summer months when daylight savings
2741 * time is in effect.
2743 * Returns: (transfer none): the time zone abbreviation. The returned
2744 * string is owned by the #GDateTime and it should not be
2750 g_date_time_get_timezone_abbreviation (GDateTime *datetime)
2752 g_return_val_if_fail (datetime != NULL, NULL);
2754 return g_time_zone_get_abbreviation (datetime->tz, datetime->interval);
2758 * g_date_time_is_daylight_savings:
2759 * @datetime: a #GDateTime
2761 * Determines if daylight savings time is in effect at the time and in
2762 * the time zone of @datetime.
2764 * Returns: %TRUE if daylight savings time is in effect
2769 g_date_time_is_daylight_savings (GDateTime *datetime)
2771 g_return_val_if_fail (datetime != NULL, FALSE);
2773 return g_time_zone_is_dst (datetime->tz, datetime->interval);
2776 /* Timezone convert {{{1 */
2778 * g_date_time_to_timezone:
2779 * @datetime: a #GDateTime
2780 * @tz: the new #GTimeZone
2782 * Create a new #GDateTime corresponding to the same instant in time as
2783 * @datetime, but in the time zone @tz.
2785 * This call can fail in the case that the time goes out of bounds. For
2786 * example, converting 0001-01-01 00:00:00 UTC to a time zone west of
2787 * Greenwich will fail (due to the year 0 being out of range).
2789 * Returns: (transfer full) (nullable): the newly created #GDateTime which
2790 * should be freed with g_date_time_unref(), or %NULL
2795 g_date_time_to_timezone (GDateTime *datetime,
2798 g_return_val_if_fail (datetime != NULL, NULL);
2799 g_return_val_if_fail (tz != NULL, NULL);
2801 return g_date_time_from_instant (tz, g_date_time_to_instant (datetime));
2805 * g_date_time_to_local:
2806 * @datetime: a #GDateTime
2808 * Creates a new #GDateTime corresponding to the same instant in time as
2809 * @datetime, but in the local time zone.
2811 * This call is equivalent to calling g_date_time_to_timezone() with the
2812 * time zone returned by g_time_zone_new_local().
2814 * Returns: (transfer full) (nullable): the newly created #GDateTime which
2815 * should be freed with g_date_time_unref(), or %NULL
2820 g_date_time_to_local (GDateTime *datetime)
2825 local = g_time_zone_new_local ();
2826 new = g_date_time_to_timezone (datetime, local);
2827 g_time_zone_unref (local);
2833 * g_date_time_to_utc:
2834 * @datetime: a #GDateTime
2836 * Creates a new #GDateTime corresponding to the same instant in time as
2837 * @datetime, but in UTC.
2839 * This call is equivalent to calling g_date_time_to_timezone() with the
2840 * time zone returned by g_time_zone_new_utc().
2842 * Returns: (transfer full) (nullable): the newly created #GDateTime which
2843 * should be freed with g_date_time_unref(), or %NULL
2848 g_date_time_to_utc (GDateTime *datetime)
2853 utc = g_time_zone_new_utc ();
2854 new = g_date_time_to_timezone (datetime, utc);
2855 g_time_zone_unref (utc);
2863 format_z (GString *outstr,
2870 gchar sign = offset >= 0 ? '+' : '-';
2872 offset = ABS (offset);
2873 hours = offset / 3600;
2874 minutes = offset / 60 % 60;
2875 seconds = offset % 60;
2880 g_string_append_printf (outstr, "%c%02d%02d",
2887 g_string_append_printf (outstr, "%c%02d:%02d",
2894 g_string_append_printf (outstr, "%c%02d:%02d:%02d",
2902 g_string_append_printf (outstr, "%c%02d", sign, hours);
2904 if (minutes != 0 || seconds != 0)
2906 g_string_append_printf (outstr, ":%02d", minutes);
2909 g_string_append_printf (outstr, ":%02d", seconds);
2920 #ifdef HAVE_LANGINFO_OUTDIGIT
2921 /* Initializes the array with UTF-8 encoded alternate digits suitable for use
2922 * in current locale. Returns NULL when current locale does not use alternate
2923 * digits or there was an error converting them to UTF-8.
2925 * This needs external locking, so must only be called from within
2928 static const gchar * const *
2929 initialize_alt_digits (void)
2934 const gchar *locale_digit;
2936 #define MAX_UTF8_ENCODING_LEN 4
2937 static gchar buffer[N_DIGITS * (MAX_UTF8_ENCODING_LEN + 1 /* null separator */)];
2939 #undef MAX_UTF8_ENCODING_LEN
2940 gchar *buffer_end = buffer;
2941 static const gchar *alt_digits[10];
2943 for (i = 0; i != 10; ++i)
2945 locale_digit = nl_langinfo (_NL_CTYPE_OUTDIGIT0_MB + i);
2947 if (g_strcmp0 (locale_digit, "") == 0)
2950 digit = _g_ctype_locale_to_utf8 (locale_digit, -1, NULL, &digit_len, NULL);
2954 g_assert (digit_len < (gsize) (buffer + sizeof (buffer) - buffer_end));
2956 alt_digits[i] = buffer_end;
2957 buffer_end = g_stpcpy (buffer_end, digit);
2958 /* skip trailing null byte */
2966 #endif /* HAVE_LANGINFO_OUTDIGIT */
2968 /* Look up the era which contains @datetime, in the ERA description from libc
2969 * which corresponds to the currently set LC_TIME locale. The ERA is parsed and
2970 * cached the first time this function is called (or when LC_TIME changes).
2971 * See nl_langinfo(3).
2973 * The return value is (transfer full). */
2974 static GEraDescriptionSegment *
2975 date_time_lookup_era (GDateTime *datetime,
2976 gboolean locale_is_utf8)
2978 static GMutex era_mutex;
2979 static GPtrArray *static_era_description = NULL; /* (mutex era_mutex) (element-type GEraDescriptionSegment) */
2980 static const char *static_era_description_locale = NULL; /* (mutex era_mutex) */
2981 const char *current_lc_time = setlocale (LC_TIME, NULL);
2982 GPtrArray *local_era_description; /* (element-type GEraDescriptionSegment) */
2983 GEraDate datetime_date;
2985 g_mutex_lock (&era_mutex);
2987 if (static_era_description_locale != current_lc_time)
2989 const char *era_description_str;
2990 size_t era_description_str_len;
2993 era_description_str = ERA_DESCRIPTION;
2994 if (era_description_str != NULL)
2996 /* FIXME: glibc 2.37 seems to return the era segments nul-separated rather
2997 * than semicolon-separated (which is what nl_langinfo(3) specifies).
2998 * Fix that up before sending it to the parsing code.
2999 * See https://sourceware.org/bugzilla/show_bug.cgi?id=31030*/
3001 /* Work out the length of the whole description string, regardless
3002 * of whether it uses nuls or semicolons as separators. */
3003 int n_entries = ERA_DESCRIPTION_N_SEGMENTS;
3004 const char *s = era_description_str;
3006 for (int i = 1; i < n_entries; i++)
3008 const char *next_semicolon = strchr (s, ';');
3009 const char *next_nul = strchr (s, '\0');
3011 if (next_semicolon != NULL && next_semicolon < next_nul)
3012 s = next_semicolon + 1;
3017 era_description_str_len = strlen (s) + (s - era_description_str);
3019 /* Replace all the nuls with semicolons. */
3020 era_description_str = tmp = g_memdup2 (era_description_str, era_description_str_len + 1);
3021 s = era_description_str;
3023 for (int i = 1; i < n_entries; i++)
3025 char *next_nul = strchr (s, '\0');
3027 if ((size_t) (next_nul - era_description_str) >= era_description_str_len)
3035 /* Convert from the LC_TIME encoding to UTF-8 if needed. */
3036 if (!locale_is_utf8 && ERA_DESCRIPTION_IS_LOCALE)
3039 era_description_str = tmp2 = g_locale_to_utf8 (era_description_str, -1, NULL, NULL, NULL);
3041 tmp = g_steal_pointer (&tmp2);
3044 g_clear_pointer (&static_era_description, g_ptr_array_unref);
3046 if (era_description_str != NULL)
3047 static_era_description = _g_era_description_parse (era_description_str);
3048 if (static_era_description == NULL)
3049 g_warning ("Could not parse ERA description: %s", era_description_str);
3053 g_clear_pointer (&static_era_description, g_ptr_array_unref);
3058 static_era_description_locale = current_lc_time;
3061 if (static_era_description == NULL)
3063 g_mutex_unlock (&era_mutex);
3067 local_era_description = g_ptr_array_ref (static_era_description);
3068 g_mutex_unlock (&era_mutex);
3070 /* Search through the eras and see if one matches. */
3071 datetime_date.type = G_ERA_DATE_SET;
3072 datetime_date.year = g_date_time_get_year (datetime);
3073 datetime_date.month = g_date_time_get_month (datetime);
3074 datetime_date.day = g_date_time_get_day_of_month (datetime);
3076 for (unsigned int i = 0; i < local_era_description->len; i++)
3078 GEraDescriptionSegment *segment = g_ptr_array_index (local_era_description, i);
3080 if ((_g_era_date_compare (&segment->start_date, &datetime_date) <= 0 &&
3081 _g_era_date_compare (&datetime_date, &segment->end_date) <= 0) ||
3082 (_g_era_date_compare (&segment->end_date, &datetime_date) <= 0 &&
3083 _g_era_date_compare (&datetime_date, &segment->start_date) <= 0))
3085 /* @datetime is within this era segment. */
3086 g_ptr_array_unref (local_era_description);
3087 return _g_era_description_segment_ref (segment);
3091 g_ptr_array_unref (local_era_description);
3097 format_number (GString *str,
3098 gboolean use_alt_digits,
3103 const gchar *ascii_digits[10] = {
3104 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
3106 const gchar * const *digits = ascii_digits;
3107 const gchar *tmp[10];
3109 #ifdef HAVE_LANGINFO_OUTDIGIT
3110 static GMutex alt_digits_mutex;
3113 g_return_if_fail (width <= 10);
3115 #ifdef HAVE_LANGINFO_OUTDIGIT
3118 static const gchar * const *alt_digits = NULL;
3119 static char *alt_digits_locale = NULL;
3120 const char *current_ctype_locale = setlocale (LC_CTYPE, NULL);
3122 /* Lock so we can initialise (or re-initialise, if the locale has changed)
3123 * and hold access to the digits buffer until done formatting. */
3124 g_mutex_lock (&alt_digits_mutex);
3126 if (g_strcmp0 (alt_digits_locale, current_ctype_locale) != 0)
3128 alt_digits = initialize_alt_digits ();
3130 if (alt_digits == NULL)
3131 alt_digits = ascii_digits;
3133 g_free (alt_digits_locale);
3134 alt_digits_locale = g_strdup (current_ctype_locale);
3137 digits = alt_digits;
3139 #endif /* HAVE_LANGINFO_OUTDIGIT */
3143 tmp[i++] = digits[number % 10];
3148 while (pad && i < width)
3149 tmp[i++] = *pad == '0' ? digits[0] : pad;
3151 #ifdef HAVE_LANGINFO_OUTDIGIT
3153 g_mutex_unlock (&alt_digits_mutex);
3156 /* should really be impossible */
3160 g_string_append (str, tmp[--i]);
3164 format_ampm (GDateTime *datetime,
3166 gboolean locale_is_utf8,
3170 gchar *tmp = NULL, *ampm_dup;
3172 ampm = GET_AMPM (datetime);
3174 if (!ampm || ampm[0] == '\0')
3175 ampm = get_fallback_ampm (g_date_time_get_hour (datetime));
3177 if (!locale_is_utf8 && GET_AMPM_IS_LOCALE)
3179 /* This assumes that locale encoding can't have embedded NULs */
3180 ampm = tmp = g_locale_to_utf8 (ampm, -1, NULL, NULL, NULL);
3185 ampm_dup = g_utf8_strup (ampm, -1);
3187 ampm_dup = g_utf8_strdown (ampm, -1);
3190 g_string_append (outstr, ampm_dup);
3196 static gboolean g_date_time_format_utf8 (GDateTime *datetime,
3197 const gchar *format,
3199 gboolean locale_is_utf8);
3201 /* g_date_time_format() subroutine that takes a locale-encoded format
3202 * string and produces a UTF-8 encoded date/time string.
3205 g_date_time_format_locale (GDateTime *datetime,
3206 const gchar *locale_format,
3208 gboolean locale_is_utf8)
3214 return g_date_time_format_utf8 (datetime, locale_format, outstr, locale_is_utf8);
3216 utf8_format = _g_time_locale_to_utf8 (locale_format, -1, NULL, NULL, NULL);
3217 if (utf8_format == NULL)
3220 success = g_date_time_format_utf8 (datetime, utf8_format, outstr,
3222 g_free (utf8_format);
3226 static inline gboolean
3227 string_append (GString *string,
3239 s = tmp = g_utf8_strup (s, -1);
3240 g_string_append (string, s);
3244 utf8 = _g_time_locale_to_utf8 (s, -1, NULL, &utf8_len, NULL);
3249 tmp = g_utf8_strup (utf8, utf8_len);
3251 utf8 = g_steal_pointer (&tmp);
3253 g_string_append_len (string, utf8, utf8_len);
3262 /* g_date_time_format() subroutine that takes a UTF-8 encoded format
3263 * string and produces a UTF-8 encoded date/time string.
3266 g_date_time_format_utf8 (GDateTime *datetime,
3267 const gchar *utf8_format,
3269 gboolean locale_is_utf8)
3274 gboolean alt_digits = FALSE;
3275 gboolean alt_era = FALSE;
3276 gboolean pad_set = FALSE;
3277 gboolean mod_case = FALSE;
3278 gboolean name_is_utf8;
3279 const gchar *pad = "";
3280 const gchar *mod = "";
3285 while (*utf8_format)
3287 len = strcspn (utf8_format, "%");
3289 g_string_append_len (outstr, utf8_format, len);
3295 g_assert (*utf8_format == '%');
3307 c = g_utf8_get_char (utf8_format);
3308 utf8_format = g_utf8_next_char (utf8_format);
3312 name = WEEKDAY_ABBR (datetime);
3313 if (g_strcmp0 (name, "") == 0)
3316 name_is_utf8 = locale_is_utf8 || !WEEKDAY_ABBR_IS_LOCALE;
3318 if (!string_append (outstr, name, mod_case, name_is_utf8))
3323 name = WEEKDAY_FULL (datetime);
3324 if (g_strcmp0 (name, "") == 0)
3327 name_is_utf8 = locale_is_utf8 || !WEEKDAY_FULL_IS_LOCALE;
3329 if (!string_append (outstr, name, mod_case, name_is_utf8))
3334 name = alt_digits ? MONTH_ABBR_STANDALONE (datetime)
3335 : MONTH_ABBR_WITH_DAY (datetime);
3336 if (g_strcmp0 (name, "") == 0)
3339 name_is_utf8 = locale_is_utf8 ||
3340 ((alt_digits && !MONTH_ABBR_STANDALONE_IS_LOCALE) ||
3341 (!alt_digits && !MONTH_ABBR_WITH_DAY_IS_LOCALE));
3343 if (!string_append (outstr, name, mod_case, name_is_utf8))
3348 name = alt_digits ? MONTH_FULL_STANDALONE (datetime)
3349 : MONTH_FULL_WITH_DAY (datetime);
3350 if (g_strcmp0 (name, "") == 0)
3353 name_is_utf8 = locale_is_utf8 ||
3354 ((alt_digits && !MONTH_FULL_STANDALONE_IS_LOCALE) ||
3355 (!alt_digits && !MONTH_FULL_WITH_DAY_IS_LOCALE));
3357 if (!string_append (outstr, name, mod_case, name_is_utf8))
3363 const char *subformat = alt_era ? PREFERRED_ERA_DATE_TIME_FMT : PREFERRED_DATE_TIME_FMT;
3366 if (alt_era && g_strcmp0 (subformat, "") == 0)
3367 subformat = PREFERRED_DATE_TIME_FMT;
3369 if (g_strcmp0 (subformat, "") == 0)
3371 if (!g_date_time_format_locale (datetime, subformat,
3372 outstr, locale_is_utf8))
3379 GEraDescriptionSegment *era = date_time_lookup_era (datetime, locale_is_utf8);
3382 g_string_append (outstr, era->era_name);
3383 _g_era_description_segment_unref (era);
3388 format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3389 g_date_time_get_year (datetime) / 100);
3392 format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3393 g_date_time_get_day_of_month (datetime));
3396 format_number (outstr, alt_digits, pad_set ? pad : "\u2007", 2,
3397 g_date_time_get_day_of_month (datetime));
3400 g_string_append_printf (outstr, "%06" G_GUINT64_FORMAT,
3401 datetime->usec % G_TIME_SPAN_SECOND);
3404 g_string_append_printf (outstr, "%d-%02d-%02d",
3405 g_date_time_get_year (datetime),
3406 g_date_time_get_month (datetime),
3407 g_date_time_get_day_of_month (datetime));
3410 format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3411 g_date_time_get_week_numbering_year (datetime) % 100);
3414 format_number (outstr, alt_digits, pad_set ? pad : 0, 0,
3415 g_date_time_get_week_numbering_year (datetime));
3418 name = alt_digits ? MONTH_ABBR_STANDALONE (datetime)
3419 : MONTH_ABBR_WITH_DAY (datetime);
3420 if (g_strcmp0 (name, "") == 0)
3423 name_is_utf8 = locale_is_utf8 ||
3424 ((alt_digits && !MONTH_ABBR_STANDALONE_IS_LOCALE) ||
3425 (!alt_digits && !MONTH_ABBR_WITH_DAY_IS_LOCALE));
3427 if (!string_append (outstr, name, mod_case, name_is_utf8))
3432 format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3433 g_date_time_get_hour (datetime));
3436 format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3437 (g_date_time_get_hour (datetime) + 11) % 12 + 1);
3440 format_number (outstr, alt_digits, pad_set ? pad : "0", 3,
3441 g_date_time_get_day_of_year (datetime));
3444 format_number (outstr, alt_digits, pad_set ? pad : "\u2007", 2,
3445 g_date_time_get_hour (datetime));
3448 format_number (outstr, alt_digits, pad_set ? pad : "\u2007", 2,
3449 (g_date_time_get_hour (datetime) + 11) % 12 + 1);
3452 format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3453 g_date_time_get_month (datetime));
3456 format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3457 g_date_time_get_minute (datetime));
3460 g_string_append_c (outstr, '\n');
3469 if (!format_ampm (datetime, outstr, locale_is_utf8,
3470 mod_case && g_strcmp0 (mod, "#") == 0 ? FALSE
3475 if (!format_ampm (datetime, outstr, locale_is_utf8,
3476 mod_case && g_strcmp0 (mod, "^") == 0 ? TRUE
3482 if (g_strcmp0 (PREFERRED_12HR_TIME_FMT, "") == 0)
3484 if (!g_date_time_format_locale (datetime, PREFERRED_12HR_TIME_FMT,
3485 outstr, locale_is_utf8))
3490 g_string_append_printf (outstr, "%02d:%02d",
3491 g_date_time_get_hour (datetime),
3492 g_date_time_get_minute (datetime));
3495 g_string_append_printf (outstr, "%" G_GINT64_FORMAT, g_date_time_to_unix (datetime));
3498 format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3499 g_date_time_get_second (datetime));
3502 g_string_append_c (outstr, '\t');
3505 g_string_append_printf (outstr, "%02d:%02d:%02d",
3506 g_date_time_get_hour (datetime),
3507 g_date_time_get_minute (datetime),
3508 g_date_time_get_second (datetime));
3511 format_number (outstr, alt_digits, 0, 0,
3512 g_date_time_get_day_of_week (datetime));
3515 format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3516 g_date_time_get_week_of_year (datetime));
3519 format_number (outstr, alt_digits, 0, 0,
3520 g_date_time_get_day_of_week (datetime) % 7);
3524 const char *subformat = alt_era ? PREFERRED_ERA_DATE_FMT : PREFERRED_DATE_FMT;
3527 if (alt_era && g_strcmp0 (subformat, "") == 0)
3528 subformat = PREFERRED_DATE_FMT;
3530 if (g_strcmp0 (subformat, "") == 0)
3532 if (!g_date_time_format_locale (datetime, subformat,
3533 outstr, locale_is_utf8))
3539 const char *subformat = alt_era ? PREFERRED_ERA_TIME_FMT : PREFERRED_TIME_FMT;
3542 if (alt_era && g_strcmp0 (subformat, "") == 0)
3543 subformat = PREFERRED_TIME_FMT;
3545 if (g_strcmp0 (subformat, "") == 0)
3547 if (!g_date_time_format_locale (datetime, subformat,
3548 outstr, locale_is_utf8))
3555 GEraDescriptionSegment *era = date_time_lookup_era (datetime, locale_is_utf8);
3558 int delta = g_date_time_get_year (datetime) - era->start_date.year;
3560 /* Both these years are in the Gregorian calendar (CE/BCE),
3561 * which has no year zero. So take one from the delta if they
3562 * cross across where year zero would be. */
3563 if ((g_date_time_get_year (datetime) < 0) != (era->start_date.year < 0))
3566 format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3567 era->offset + delta * era->direction_multiplier);
3568 _g_era_description_segment_unref (era);
3573 format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3574 g_date_time_get_year (datetime) % 100);
3579 GEraDescriptionSegment *era = date_time_lookup_era (datetime, locale_is_utf8);
3582 if (!g_date_time_format_utf8 (datetime, era->era_format,
3583 outstr, locale_is_utf8))
3585 _g_era_description_segment_unref (era);
3589 _g_era_description_segment_unref (era);
3594 format_number (outstr, alt_digits, 0, 0,
3595 g_date_time_get_year (datetime));
3600 offset = g_date_time_get_utc_offset (datetime) / USEC_PER_SECOND;
3601 if (!format_z (outstr, (int) offset, colons))
3606 tz = g_date_time_get_timezone_abbreviation (datetime);
3607 if (mod_case && g_strcmp0 (mod, "#") == 0)
3608 tz = tmp = g_utf8_strdown (tz, -1);
3609 g_string_append (outstr, tz);
3613 g_string_append_c (outstr, '%');
3628 /* Colons are only allowed before 'z' */
3629 if (*utf8_format && *utf8_format != 'z' && *utf8_format != ':')
3650 * g_date_time_format:
3651 * @datetime: A #GDateTime
3652 * @format: a valid UTF-8 string, containing the format for the
3655 * Creates a newly allocated string representing the requested @format.
3657 * The format strings understood by this function are a subset of the
3658 * `strftime()` format language as specified by C99. The `%D`, `%U` and `%W`
3659 * conversions are not supported, nor is the `E` modifier. The GNU
3660 * extensions `%k`, `%l`, `%s` and `%P` are supported, however, as are the
3661 * `0`, `_` and `-` modifiers. The Python extension `%f` is also supported.
3663 * In contrast to `strftime()`, this function always produces a UTF-8
3664 * string, regardless of the current locale. Note that the rendering of
3665 * many formats is locale-dependent and may not match the `strftime()`
3668 * The following format specifiers are supported:
3670 * - `%a`: the abbreviated weekday name according to the current locale
3671 * - `%A`: the full weekday name according to the current locale
3672 * - `%b`: the abbreviated month name according to the current locale
3673 * - `%B`: the full month name according to the current locale
3674 * - `%c`: the preferred date and time representation for the current locale
3675 * - `%C`: the century number (year/100) as a 2-digit integer (00-99)
3676 * - `%d`: the day of the month as a decimal number (range 01 to 31)
3677 * - `%e`: the day of the month as a decimal number (range 1 to 31);
3678 * single digits are preceded by a figure space (U+2007)
3679 * - `%F`: equivalent to `%Y-%m-%d` (the ISO 8601 date format)
3680 * - `%g`: the last two digits of the ISO 8601 week-based year as a
3681 * decimal number (00-99). This works well with `%V` and `%u`.
3682 * - `%G`: the ISO 8601 week-based year as a decimal number. This works
3683 * well with `%V` and `%u`.
3684 * - `%h`: equivalent to `%b`
3685 * - `%H`: the hour as a decimal number using a 24-hour clock (range 00 to 23)
3686 * - `%I`: the hour as a decimal number using a 12-hour clock (range 01 to 12)
3687 * - `%j`: the day of the year as a decimal number (range 001 to 366)
3688 * - `%k`: the hour (24-hour clock) as a decimal number (range 0 to 23);
3689 * single digits are preceded by a figure space (U+2007)
3690 * - `%l`: the hour (12-hour clock) as a decimal number (range 1 to 12);
3691 * single digits are preceded by a figure space (U+2007)
3692 * - `%m`: the month as a decimal number (range 01 to 12)
3693 * - `%M`: the minute as a decimal number (range 00 to 59)
3694 * - `%f`: the microsecond as a decimal number (range 000000 to 999999)
3695 * - `%p`: either ‘AM’ or ‘PM’ according to the given time value, or the
3696 * corresponding strings for the current locale. Noon is treated as
3697 * ‘PM’ and midnight as ‘AM’. Use of this format specifier is discouraged, as
3698 * many locales have no concept of AM/PM formatting. Use `%c` or `%X` instead.
3699 * - `%P`: like `%p` but lowercase: ‘am’ or ‘pm’ or a corresponding string for
3700 * the current locale. Use of this format specifier is discouraged, as
3701 * many locales have no concept of AM/PM formatting. Use `%c` or `%X` instead.
3702 * - `%r`: the time in a.m. or p.m. notation. Use of this format specifier is
3703 * discouraged, as many locales have no concept of AM/PM formatting. Use `%c`
3705 * - `%R`: the time in 24-hour notation (`%H:%M`)
3706 * - `%s`: the number of seconds since the Epoch, that is, since 1970-01-01
3708 * - `%S`: the second as a decimal number (range 00 to 60)
3709 * - `%t`: a tab character
3710 * - `%T`: the time in 24-hour notation with seconds (`%H:%M:%S`)
3711 * - `%u`: the ISO 8601 standard day of the week as a decimal, range 1 to 7,
3712 * Monday being 1. This works well with `%G` and `%V`.
3713 * - `%V`: the ISO 8601 standard week number of the current year as a decimal
3714 * number, range 01 to 53, where week 1 is the first week that has at
3715 * least 4 days in the new year. See g_date_time_get_week_of_year().
3716 * This works well with `%G` and `%u`.
3717 * - `%w`: the day of the week as a decimal, range 0 to 6, Sunday being 0.
3718 * This is not the ISO 8601 standard format — use `%u` instead.
3719 * - `%x`: the preferred date representation for the current locale without
3721 * - `%X`: the preferred time representation for the current locale without
3723 * - `%y`: the year as a decimal number without the century
3724 * - `%Y`: the year as a decimal number including the century
3725 * - `%z`: the time zone as an offset from UTC (`+hhmm`)
3726 * - `%:z`: the time zone as an offset from UTC (`+hh:mm`).
3727 * This is a gnulib `strftime()` extension. Since: 2.38
3728 * - `%::z`: the time zone as an offset from UTC (`+hh:mm:ss`). This is a
3729 * gnulib `strftime()` extension. Since: 2.38
3730 * - `%:::z`: the time zone as an offset from UTC, with `:` to necessary
3731 * precision (e.g., `-04`, `+05:30`). This is a gnulib `strftime()` extension. Since: 2.38
3732 * - `%Z`: the time zone or name or abbreviation
3733 * - `%%`: a literal `%` character
3735 * Some conversion specifications can be modified by preceding the
3736 * conversion specifier by one or more modifier characters.
3738 * The following modifiers are supported for many of the numeric
3741 * - `O`: Use alternative numeric symbols, if the current locale supports those.
3742 * - `_`: Pad a numeric result with spaces. This overrides the default padding
3743 * for the specifier.
3744 * - `-`: Do not pad a numeric result. This overrides the default padding
3745 * for the specifier.
3746 * - `0`: Pad a numeric result with zeros. This overrides the default padding
3747 * for the specifier.
3749 * The following modifiers are supported for many of the alphabetic conversions:
3751 * - `^`: Use upper case if possible. This is a gnulib `strftime()` extension.
3753 * - `#`: Use opposite case if possible. This is a gnulib `strftime()`
3754 * extension. Since: 2.80
3756 * Additionally, when `O` is used with `B`, `b`, or `h`, it produces the alternative
3757 * form of a month name. The alternative form should be used when the month
3758 * name is used without a day number (e.g., standalone). It is required in
3759 * some languages (Baltic, Slavic, Greek, and more) due to their grammatical
3760 * rules. For other languages there is no difference. `%OB` is a GNU and BSD
3761 * `strftime()` extension expected to be added to the future POSIX specification,
3762 * `%Ob` and `%Oh` are GNU `strftime()` extensions. Since: 2.56
3764 * Since GLib 2.80, when `E` is used with `%c`, `%C`, `%x`, `%X`, `%y` or `%Y`,
3765 * the date is formatted using an alternate era representation specific to the
3766 * locale. This is typically used for the Thai solar calendar or Japanese era
3767 * names, for example.
3769 * - `%Ec`: the preferred date and time representation for the current locale,
3770 * using the alternate era representation
3771 * - `%EC`: the name of the era
3772 * - `%Ex`: the preferred date representation for the current locale without
3773 * the time, using the alternate era representation
3774 * - `%EX`: the preferred time representation for the current locale without
3775 * the date, using the alternate era representation
3776 * - `%Ey`: the year since the beginning of the era denoted by the `%EC`
3778 * - `%EY`: the full alternative year representation
3780 * Returns: (transfer full) (nullable): a newly allocated string formatted to
3781 * the requested format or %NULL in the case that there was an error (such
3782 * as a format specifier not being supported in the current locale). The
3783 * string should be freed with g_free().
3788 g_date_time_format (GDateTime *datetime,
3789 const gchar *format)
3792 const gchar *charset;
3793 /* Avoid conversions from locale (for LC_TIME and not for LC_MESSAGES unless
3794 * specified otherwise) charset to UTF-8 if charset is compatible
3795 * with UTF-8 already. Check for UTF-8 and synonymous canonical names of
3797 gboolean time_is_utf8_compatible = _g_get_time_charset (&charset) ||
3798 g_strcmp0 ("ASCII", charset) == 0 ||
3799 g_strcmp0 ("ANSI_X3.4-1968", charset) == 0;
3801 g_return_val_if_fail (datetime != NULL, NULL);
3802 g_return_val_if_fail (format != NULL, NULL);
3803 g_return_val_if_fail (g_utf8_validate (format, -1, NULL), NULL);
3805 outstr = g_string_sized_new (strlen (format) * 2);
3807 if (!g_date_time_format_utf8 (datetime, format, outstr,
3808 time_is_utf8_compatible))
3810 g_string_free (outstr, TRUE);
3814 return g_string_free (outstr, FALSE);
3818 * g_date_time_format_iso8601:
3819 * @datetime: A #GDateTime
3821 * Format @datetime in [ISO 8601 format](https://en.wikipedia.org/wiki/ISO_8601),
3822 * including the date, time and time zone, and return that as a UTF-8 encoded
3825 * Since GLib 2.66, this will output to sub-second precision if needed.
3827 * Returns: (transfer full) (nullable): a newly allocated string formatted in
3828 * ISO 8601 format or %NULL in the case that there was an error. The string
3829 * should be freed with g_free().
3834 g_date_time_format_iso8601 (GDateTime *datetime)
3836 GString *outstr = NULL;
3837 gchar *main_date = NULL;
3839 gchar *format = "%C%y-%m-%dT%H:%M:%S";
3841 g_return_val_if_fail (datetime != NULL, NULL);
3843 /* if datetime has sub-second non-zero values below the second precision we
3844 * should print them as well */
3845 if (datetime->usec % G_TIME_SPAN_SECOND != 0)
3846 format = "%C%y-%m-%dT%H:%M:%S.%f";
3848 /* Main date and time. */
3849 main_date = g_date_time_format (datetime, format);
3850 outstr = g_string_new (main_date);
3853 /* Timezone. Format it as `%:::z` unless the offset is zero, in which case
3854 * we can simply use `Z`. */
3855 offset = g_date_time_get_utc_offset (datetime);
3859 g_string_append_c (outstr, 'Z');
3863 gchar *time_zone = g_date_time_format (datetime, "%:::z");
3864 g_string_append (outstr, time_zone);
3868 return g_string_free (outstr, FALSE);
3873 /* vim:set foldmethod=marker: */