• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* gdatetime.c
2  *
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  *
9  * This library is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU Lesser General Public License as
11  * published by the Free Software Foundation; either version 2.1 of the
12  * licence, or (at your option) any later version.
13  *
14  * This is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this library; if not, see <http://www.gnu.org/licenses/>.
21  *
22  * Authors: Christian Hergert <chris@dronelabs.com>
23  *          Thiago Santos <thiago.sousa.santos@collabora.co.uk>
24  *          Emmanuele Bassi <ebassi@linux.intel.com>
25  *          Ryan Lortie <desrt@desrt.ca>
26  *          Robert Ancell <robert.ancell@canonical.com>
27  */
28 
29 /* Algorithms within this file are based on the Calendar FAQ by
30  * Claus Tondering.  It can be found at
31  * http://www.tondering.dk/claus/cal/calendar29.txt
32  *
33  * Copyright and disclaimer
34  * ------------------------
35  *   This document is Copyright (C) 2008 by Claus Tondering.
36  *   E-mail: claus@tondering.dk. (Please include the word
37  *   "calendar" in the subject line.)
38  *   The document may be freely distributed, provided this
39  *   copyright notice is included and no money is charged for
40  *   the document.
41  *
42  *   This document is provided "as is". No warranties are made as
43  *   to its correctness.
44  */
45 
46 /* Prologue {{{1 */
47 
48 #include "config.h"
49 
50 /* langinfo.h in glibc 2.27 defines ALTMON_* only if _GNU_SOURCE is defined.  */
51 #ifndef _GNU_SOURCE
52 #define _GNU_SOURCE 1
53 #endif
54 
55 #include <math.h>
56 #include <stdlib.h>
57 #include <string.h>
58 
59 #ifdef HAVE_LANGINFO_TIME
60 #include <langinfo.h>
61 #endif
62 
63 #include "gdatetime.h"
64 
65 #include "gslice.h"
66 #include "gatomic.h"
67 #include "gcharset.h"
68 #include "gconvert.h"
69 #include "gfileutils.h"
70 #include "ghash.h"
71 #include "gmain.h"
72 #include "gmappedfile.h"
73 #include "gstrfuncs.h"
74 #include "gtestutils.h"
75 #include "gthread.h"
76 #include "gtimezone.h"
77 
78 #include "glibintl.h"
79 
80 #ifndef G_OS_WIN32
81 #include <sys/time.h>
82 #include <time.h>
83 #else
84 #if defined (_MSC_VER) && (_MSC_VER < 1800)
85 /* fallback implementation for isnan() on VS2012 and earlier */
86 #define isnan _isnan
87 #endif
88 #endif /* !G_OS_WIN32 */
89 
90 /**
91  * SECTION:date-time
92  * @title: GDateTime
93  * @short_description: a structure representing Date and Time
94  * @see_also: #GTimeZone
95  *
96  * #GDateTime is a structure that combines a Gregorian date and time
97  * into a single structure.  It provides many conversion and methods to
98  * manipulate dates and times.  Time precision is provided down to
99  * microseconds and the time can range (proleptically) from 0001-01-01
100  * 00:00:00 to 9999-12-31 23:59:59.999999.  #GDateTime follows POSIX
101  * time in the sense that it is oblivious to leap seconds.
102  *
103  * #GDateTime is an immutable object; once it has been created it cannot
104  * be modified further.  All modifiers will create a new #GDateTime.
105  * Nearly all such functions can fail due to the date or time going out
106  * of range, in which case %NULL will be returned.
107  *
108  * #GDateTime is reference counted: the reference count is increased by calling
109  * g_date_time_ref() and decreased by calling g_date_time_unref(). When the
110  * reference count drops to 0, the resources allocated by the #GDateTime
111  * structure are released.
112  *
113  * Many parts of the API may produce non-obvious results.  As an
114  * example, adding two months to January 31st will yield March 31st
115  * whereas adding one month and then one month again will yield either
116  * March 28th or March 29th.  Also note that adding 24 hours is not
117  * always the same as adding one day (since days containing daylight
118  * savings time transitions are either 23 or 25 hours in length).
119  *
120  * #GDateTime is available since GLib 2.26.
121  */
122 
123 struct _GDateTime
124 {
125   /* Microsecond timekeeping within Day */
126   guint64 usec;
127 
128   /* TimeZone information */
129   GTimeZone *tz;
130   gint interval;
131 
132   /* 1 is 0001-01-01 in Proleptic Gregorian */
133   gint32 days;
134 
135   gint ref_count;  /* (atomic) */
136 };
137 
138 /* Time conversion {{{1 */
139 
140 #define UNIX_EPOCH_START     719163
141 #define INSTANT_TO_UNIX(instant) \
142   ((instant)/USEC_PER_SECOND - UNIX_EPOCH_START * SEC_PER_DAY)
143 #define INSTANT_TO_UNIX_USECS(instant) \
144   ((instant) - UNIX_EPOCH_START * SEC_PER_DAY * USEC_PER_SECOND)
145 #define UNIX_TO_INSTANT(unix) \
146   (((gint64) (unix) + UNIX_EPOCH_START * SEC_PER_DAY) * USEC_PER_SECOND)
147 #define UNIX_USECS_TO_INSTANT(unix_usecs) \
148   ((gint64) (unix_usecs) + UNIX_EPOCH_START * SEC_PER_DAY * USEC_PER_SECOND)
149 #define UNIX_TO_INSTANT_IS_VALID(unix) \
150   ((gint64) (unix) <= INSTANT_TO_UNIX (G_MAXINT64))
151 #define UNIX_USECS_TO_INSTANT_IS_VALID(unix_usecs) \
152   ((gint64) (unix_usecs) <= INSTANT_TO_UNIX_USECS (G_MAXINT64))
153 
154 #define DAYS_IN_4YEARS    1461    /* days in 4 years */
155 #define DAYS_IN_100YEARS  36524   /* days in 100 years */
156 #define DAYS_IN_400YEARS  146097  /* days in 400 years  */
157 
158 #define USEC_PER_SECOND      (G_GINT64_CONSTANT (1000000))
159 #define USEC_PER_MINUTE      (G_GINT64_CONSTANT (60000000))
160 #define USEC_PER_HOUR        (G_GINT64_CONSTANT (3600000000))
161 #define USEC_PER_MILLISECOND (G_GINT64_CONSTANT (1000))
162 #define USEC_PER_DAY         (G_GINT64_CONSTANT (86400000000))
163 #define SEC_PER_DAY          (G_GINT64_CONSTANT (86400))
164 
165 #define SECS_PER_MINUTE (60)
166 #define SECS_PER_HOUR   (60 * SECS_PER_MINUTE)
167 #define SECS_PER_DAY    (24 * SECS_PER_HOUR)
168 #define SECS_PER_YEAR   (365 * SECS_PER_DAY)
169 #define SECS_PER_JULIAN (DAYS_PER_PERIOD * SECS_PER_DAY)
170 
171 #define GREGORIAN_LEAP(y)    ((((y) % 4) == 0) && (!((((y) % 100) == 0) && (((y) % 400) != 0))))
172 #define JULIAN_YEAR(d)       ((d)->julian / 365.25)
173 #define DAYS_PER_PERIOD      (G_GINT64_CONSTANT (2914695))
174 
175 static const guint16 days_in_months[2][13] =
176 {
177   { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
178   { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
179 };
180 
181 static const guint16 days_in_year[2][13] =
182 {
183   {  0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
184   {  0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
185 };
186 
187 #ifdef HAVE_LANGINFO_TIME
188 
189 #define GET_AMPM(d) ((g_date_time_get_hour (d) < 12) ? \
190                      nl_langinfo (AM_STR) : \
191                      nl_langinfo (PM_STR))
192 #define GET_AMPM_IS_LOCALE TRUE
193 
194 #define PREFERRED_DATE_TIME_FMT nl_langinfo (D_T_FMT)
195 #define PREFERRED_DATE_FMT nl_langinfo (D_FMT)
196 #define PREFERRED_TIME_FMT nl_langinfo (T_FMT)
197 #define PREFERRED_12HR_TIME_FMT nl_langinfo (T_FMT_AMPM)
198 
199 static const gint weekday_item[2][7] =
200 {
201   { ABDAY_2, ABDAY_3, ABDAY_4, ABDAY_5, ABDAY_6, ABDAY_7, ABDAY_1 },
202   { DAY_2, DAY_3, DAY_4, DAY_5, DAY_6, DAY_7, DAY_1 }
203 };
204 
205 static const gint month_item[2][12] =
206 {
207   { ABMON_1, ABMON_2, ABMON_3, ABMON_4, ABMON_5, ABMON_6, ABMON_7, ABMON_8, ABMON_9, ABMON_10, ABMON_11, ABMON_12 },
208   { MON_1, MON_2, MON_3, MON_4, MON_5, MON_6, MON_7, MON_8, MON_9, MON_10, MON_11, MON_12 },
209 };
210 
211 #define WEEKDAY_ABBR(d) nl_langinfo (weekday_item[0][g_date_time_get_day_of_week (d) - 1])
212 #define WEEKDAY_ABBR_IS_LOCALE TRUE
213 #define WEEKDAY_FULL(d) nl_langinfo (weekday_item[1][g_date_time_get_day_of_week (d) - 1])
214 #define WEEKDAY_FULL_IS_LOCALE TRUE
215 #define MONTH_ABBR(d) nl_langinfo (month_item[0][g_date_time_get_month (d) - 1])
216 #define MONTH_ABBR_IS_LOCALE TRUE
217 #define MONTH_FULL(d) nl_langinfo (month_item[1][g_date_time_get_month (d) - 1])
218 #define MONTH_FULL_IS_LOCALE TRUE
219 
220 #else
221 
222 #define GET_AMPM(d)          (get_fallback_ampm (g_date_time_get_hour (d)))
223 #define GET_AMPM_IS_LOCALE   FALSE
224 
225 /* Translators: this is the preferred format for expressing the date and the time */
226 #define PREFERRED_DATE_TIME_FMT C_("GDateTime", "%a %b %e %H:%M:%S %Y")
227 
228 /* Translators: this is the preferred format for expressing the date */
229 #define PREFERRED_DATE_FMT C_("GDateTime", "%m/%d/%y")
230 
231 /* Translators: this is the preferred format for expressing the time */
232 #define PREFERRED_TIME_FMT C_("GDateTime", "%H:%M:%S")
233 
234 /* Translators: this is the preferred format for expressing 12 hour time */
235 #define PREFERRED_12HR_TIME_FMT C_("GDateTime", "%I:%M:%S %p")
236 
237 #define WEEKDAY_ABBR(d)       (get_weekday_name_abbr (g_date_time_get_day_of_week (d)))
238 #define WEEKDAY_ABBR_IS_LOCALE FALSE
239 #define WEEKDAY_FULL(d)       (get_weekday_name (g_date_time_get_day_of_week (d)))
240 #define WEEKDAY_FULL_IS_LOCALE FALSE
241 /* We don't yet know if nl_langinfo (MON_n) returns standalone or complete-date
242  * format forms but if nl_langinfo (ALTMON_n) is not supported then we will
243  * have to use MONTH_FULL as standalone.  The same if nl_langinfo () does not
244  * exist at all.  MONTH_ABBR is similar: if nl_langinfo (_NL_ABALTMON_n) is not
245  * supported then we will use MONTH_ABBR as standalone.
246  */
247 #define MONTH_ABBR(d)         (get_month_name_abbr_standalone (g_date_time_get_month (d)))
248 #define MONTH_ABBR_IS_LOCALE  FALSE
249 #define MONTH_FULL(d)         (get_month_name_standalone (g_date_time_get_month (d)))
250 #define MONTH_FULL_IS_LOCALE  FALSE
251 
252 static const gchar *
get_month_name_standalone(gint month)253 get_month_name_standalone (gint month)
254 {
255   switch (month)
256     {
257     case 1:
258       /* Translators: Some languages (Baltic, Slavic, Greek, and some more)
259        * need different grammatical forms of month names depending on whether
260        * they are standalone or in a complete date context, with the day
261        * number.  Some other languages may prefer starting with uppercase when
262        * they are standalone and with lowercase when they are in a complete
263        * date context.  Here are full month names in a form appropriate when
264        * they are used standalone.  If your system is Linux with the glibc
265        * version 2.27 (released Feb 1, 2018) or newer or if it is from the BSD
266        * family (which includes OS X) then you can refer to the date command
267        * line utility and see what the command `date +%OB' produces.  Also in
268        * the latest Linux the command `locale alt_mon' in your native locale
269        * produces a complete list of month names almost ready to copy and
270        * paste here.  Note that in most of the languages (western European,
271        * non-European) there is no difference between the standalone and
272        * complete date form.
273        */
274       return C_("full month name", "January");
275     case 2:
276       return C_("full month name", "February");
277     case 3:
278       return C_("full month name", "March");
279     case 4:
280       return C_("full month name", "April");
281     case 5:
282       return C_("full month name", "May");
283     case 6:
284       return C_("full month name", "June");
285     case 7:
286       return C_("full month name", "July");
287     case 8:
288       return C_("full month name", "August");
289     case 9:
290       return C_("full month name", "September");
291     case 10:
292       return C_("full month name", "October");
293     case 11:
294       return C_("full month name", "November");
295     case 12:
296       return C_("full month name", "December");
297 
298     default:
299       g_warning ("Invalid month number %d", month);
300     }
301 
302   return NULL;
303 }
304 
305 static const gchar *
get_month_name_abbr_standalone(gint month)306 get_month_name_abbr_standalone (gint month)
307 {
308   switch (month)
309     {
310     case 1:
311       /* Translators: Some languages need different grammatical forms of
312        * month names depending on whether they are standalone or in a complete
313        * date context, with the day number.  Some may prefer starting with
314        * uppercase when they are standalone and with lowercase when they are
315        * in a full date context.  However, as these names are abbreviated
316        * the grammatical difference is visible probably only in Belarusian
317        * and Russian.  In other languages there is no difference between
318        * the standalone and complete date form when they are abbreviated.
319        * If your system is Linux with the glibc version 2.27 (released
320        * Feb 1, 2018) or newer then you can refer to the date command line
321        * utility and see what the command `date +%Ob' produces.  Also in
322        * the latest Linux the command `locale ab_alt_mon' in your native
323        * locale produces a complete list of month names almost ready to copy
324        * and paste here.  Note that this feature is not yet supported by any
325        * other platform.  Here are abbreviated month names in a form
326        * appropriate when they are used standalone.
327        */
328       return C_("abbreviated month name", "Jan");
329     case 2:
330       return C_("abbreviated month name", "Feb");
331     case 3:
332       return C_("abbreviated month name", "Mar");
333     case 4:
334       return C_("abbreviated month name", "Apr");
335     case 5:
336       return C_("abbreviated month name", "May");
337     case 6:
338       return C_("abbreviated month name", "Jun");
339     case 7:
340       return C_("abbreviated month name", "Jul");
341     case 8:
342       return C_("abbreviated month name", "Aug");
343     case 9:
344       return C_("abbreviated month name", "Sep");
345     case 10:
346       return C_("abbreviated month name", "Oct");
347     case 11:
348       return C_("abbreviated month name", "Nov");
349     case 12:
350       return C_("abbreviated month name", "Dec");
351 
352     default:
353       g_warning ("Invalid month number %d", month);
354     }
355 
356   return NULL;
357 }
358 
359 static const gchar *
get_weekday_name(gint day)360 get_weekday_name (gint day)
361 {
362   switch (day)
363     {
364     case 1:
365       return C_("full weekday name", "Monday");
366     case 2:
367       return C_("full weekday name", "Tuesday");
368     case 3:
369       return C_("full weekday name", "Wednesday");
370     case 4:
371       return C_("full weekday name", "Thursday");
372     case 5:
373       return C_("full weekday name", "Friday");
374     case 6:
375       return C_("full weekday name", "Saturday");
376     case 7:
377       return C_("full weekday name", "Sunday");
378 
379     default:
380       g_warning ("Invalid week day number %d", day);
381     }
382 
383   return NULL;
384 }
385 
386 static const gchar *
get_weekday_name_abbr(gint day)387 get_weekday_name_abbr (gint day)
388 {
389   switch (day)
390     {
391     case 1:
392       return C_("abbreviated weekday name", "Mon");
393     case 2:
394       return C_("abbreviated weekday name", "Tue");
395     case 3:
396       return C_("abbreviated weekday name", "Wed");
397     case 4:
398       return C_("abbreviated weekday name", "Thu");
399     case 5:
400       return C_("abbreviated weekday name", "Fri");
401     case 6:
402       return C_("abbreviated weekday name", "Sat");
403     case 7:
404       return C_("abbreviated weekday name", "Sun");
405 
406     default:
407       g_warning ("Invalid week day number %d", day);
408     }
409 
410   return NULL;
411 }
412 
413 #endif  /* HAVE_LANGINFO_TIME */
414 
415 #ifdef HAVE_LANGINFO_ALTMON
416 
417 /* If nl_langinfo () supports ALTMON_n then MON_n returns full date format
418  * forms and ALTMON_n returns standalone forms.
419  */
420 
421 #define MONTH_FULL_WITH_DAY(d) MONTH_FULL(d)
422 #define MONTH_FULL_WITH_DAY_IS_LOCALE MONTH_FULL_IS_LOCALE
423 
424 static const gint alt_month_item[12] =
425 {
426   ALTMON_1, ALTMON_2, ALTMON_3, ALTMON_4, ALTMON_5, ALTMON_6,
427   ALTMON_7, ALTMON_8, ALTMON_9, ALTMON_10, ALTMON_11, ALTMON_12
428 };
429 
430 #define MONTH_FULL_STANDALONE(d) nl_langinfo (alt_month_item[g_date_time_get_month (d) - 1])
431 #define MONTH_FULL_STANDALONE_IS_LOCALE TRUE
432 
433 #else
434 
435 /* If nl_langinfo () does not support ALTMON_n then either MON_n returns
436  * standalone forms or nl_langinfo (MON_n) does not work so we have defined
437  * it as standalone form.
438  */
439 
440 #define MONTH_FULL_STANDALONE(d) MONTH_FULL(d)
441 #define MONTH_FULL_STANDALONE_IS_LOCALE MONTH_FULL_IS_LOCALE
442 #define MONTH_FULL_WITH_DAY(d) (get_month_name_with_day (g_date_time_get_month (d)))
443 #define MONTH_FULL_WITH_DAY_IS_LOCALE FALSE
444 
445 static const gchar *
get_month_name_with_day(gint month)446 get_month_name_with_day (gint month)
447 {
448   switch (month)
449     {
450     case 1:
451       /* Translators: Some languages need different grammatical forms of
452        * month names depending on whether they are standalone or in a full
453        * date context, with the day number.  Some may prefer starting with
454        * uppercase when they are standalone and with lowercase when they are
455        * in a full date context.  Here are full month names in a form
456        * appropriate when they are used in a full date context, with the
457        * day number.  If your system is Linux with the glibc version 2.27
458        * (released Feb 1, 2018) or newer or if it is from the BSD family
459        * (which includes OS X) then you can refer to the date command line
460        * utility and see what the command `date +%B' produces.  Also in
461        * the latest Linux the command `locale mon' in your native locale
462        * produces a complete list of month names almost ready to copy and
463        * paste here.  In older Linux systems due to a bug the result is
464        * incorrect in some languages.  Note that in most of the languages
465        * (western European, non-European) there is no difference between the
466        * standalone and complete date form.
467        */
468       return C_("full month name with day", "January");
469     case 2:
470       return C_("full month name with day", "February");
471     case 3:
472       return C_("full month name with day", "March");
473     case 4:
474       return C_("full month name with day", "April");
475     case 5:
476       return C_("full month name with day", "May");
477     case 6:
478       return C_("full month name with day", "June");
479     case 7:
480       return C_("full month name with day", "July");
481     case 8:
482       return C_("full month name with day", "August");
483     case 9:
484       return C_("full month name with day", "September");
485     case 10:
486       return C_("full month name with day", "October");
487     case 11:
488       return C_("full month name with day", "November");
489     case 12:
490       return C_("full month name with day", "December");
491 
492     default:
493       g_warning ("Invalid month number %d", month);
494     }
495 
496   return NULL;
497 }
498 
499 #endif  /* HAVE_LANGINFO_ALTMON */
500 
501 #ifdef HAVE_LANGINFO_ABALTMON
502 
503 /* If nl_langinfo () supports _NL_ABALTMON_n then ABMON_n returns full
504  * date format forms and _NL_ABALTMON_n returns standalone forms.
505  */
506 
507 #define MONTH_ABBR_WITH_DAY(d) MONTH_ABBR(d)
508 #define MONTH_ABBR_WITH_DAY_IS_LOCALE MONTH_ABBR_IS_LOCALE
509 
510 static const gint ab_alt_month_item[12] =
511 {
512   _NL_ABALTMON_1, _NL_ABALTMON_2, _NL_ABALTMON_3, _NL_ABALTMON_4,
513   _NL_ABALTMON_5, _NL_ABALTMON_6, _NL_ABALTMON_7, _NL_ABALTMON_8,
514   _NL_ABALTMON_9, _NL_ABALTMON_10, _NL_ABALTMON_11, _NL_ABALTMON_12
515 };
516 
517 #define MONTH_ABBR_STANDALONE(d) nl_langinfo (ab_alt_month_item[g_date_time_get_month (d) - 1])
518 #define MONTH_ABBR_STANDALONE_IS_LOCALE TRUE
519 
520 #else
521 
522 /* If nl_langinfo () does not support _NL_ABALTMON_n then either ABMON_n
523  * returns standalone forms or nl_langinfo (ABMON_n) does not work so we
524  * have defined it as standalone form. Now it's time to swap.
525  */
526 
527 #define MONTH_ABBR_STANDALONE(d) MONTH_ABBR(d)
528 #define MONTH_ABBR_STANDALONE_IS_LOCALE MONTH_ABBR_IS_LOCALE
529 #define MONTH_ABBR_WITH_DAY(d) (get_month_name_abbr_with_day (g_date_time_get_month (d)))
530 #define MONTH_ABBR_WITH_DAY_IS_LOCALE FALSE
531 
532 static const gchar *
get_month_name_abbr_with_day(gint month)533 get_month_name_abbr_with_day (gint month)
534 {
535   switch (month)
536     {
537     case 1:
538       /* Translators: Some languages need different grammatical forms of
539        * month names depending on whether they are standalone or in a full
540        * date context, with the day number.  Some may prefer starting with
541        * uppercase when they are standalone and with lowercase when they are
542        * in a full date context.  Here are abbreviated month names in a form
543        * appropriate when they are used in a full date context, with the
544        * day number.  However, as these names are abbreviated the grammatical
545        * difference is visible probably only in Belarusian and Russian.
546        * In other languages there is no difference between the standalone
547        * and complete date form when they are abbreviated.  If your system
548        * is Linux with the glibc version 2.27 (released Feb 1, 2018) or newer
549        * then you can refer to the date command line utility and see what the
550        * command `date +%b' produces.  Also in the latest Linux the command
551        * `locale abmon' in your native locale produces a complete list of
552        * month names almost ready to copy and paste here.  In other systems
553        * due to a bug the result is incorrect in some languages.
554        */
555       return C_("abbreviated month name with day", "Jan");
556     case 2:
557       return C_("abbreviated month name with day", "Feb");
558     case 3:
559       return C_("abbreviated month name with day", "Mar");
560     case 4:
561       return C_("abbreviated month name with day", "Apr");
562     case 5:
563       return C_("abbreviated month name with day", "May");
564     case 6:
565       return C_("abbreviated month name with day", "Jun");
566     case 7:
567       return C_("abbreviated month name with day", "Jul");
568     case 8:
569       return C_("abbreviated month name with day", "Aug");
570     case 9:
571       return C_("abbreviated month name with day", "Sep");
572     case 10:
573       return C_("abbreviated month name with day", "Oct");
574     case 11:
575       return C_("abbreviated month name with day", "Nov");
576     case 12:
577       return C_("abbreviated month name with day", "Dec");
578 
579     default:
580       g_warning ("Invalid month number %d", month);
581     }
582 
583   return NULL;
584 }
585 
586 #endif  /* HAVE_LANGINFO_ABALTMON */
587 
588 /* Format AM/PM indicator if the locale does not have a localized version. */
589 static const gchar *
get_fallback_ampm(gint hour)590 get_fallback_ampm (gint hour)
591 {
592   if (hour < 12)
593     /* Translators: 'before midday' indicator */
594     return C_("GDateTime", "AM");
595   else
596     /* Translators: 'after midday' indicator */
597     return C_("GDateTime", "PM");
598 }
599 
600 static inline gint
ymd_to_days(gint year,gint month,gint day)601 ymd_to_days (gint year,
602              gint month,
603              gint day)
604 {
605   gint64 days;
606 
607   days = ((gint64) year - 1) * 365 + ((year - 1) / 4) - ((year - 1) / 100)
608       + ((year - 1) / 400);
609 
610   days += days_in_year[0][month - 1];
611   if (GREGORIAN_LEAP (year) && month > 2)
612     day++;
613 
614   days += day;
615 
616   return days;
617 }
618 
619 static void
g_date_time_get_week_number(GDateTime * datetime,gint * week_number,gint * day_of_week,gint * day_of_year)620 g_date_time_get_week_number (GDateTime *datetime,
621                              gint      *week_number,
622                              gint      *day_of_week,
623                              gint      *day_of_year)
624 {
625   gint a, b, c, d, e, f, g, n, s, month, day, year;
626 
627   g_date_time_get_ymd (datetime, &year, &month, &day);
628 
629   if (month <= 2)
630     {
631       a = g_date_time_get_year (datetime) - 1;
632       b = (a / 4) - (a / 100) + (a / 400);
633       c = ((a - 1) / 4) - ((a - 1) / 100) + ((a - 1) / 400);
634       s = b - c;
635       e = 0;
636       f = day - 1 + (31 * (month - 1));
637     }
638   else
639     {
640       a = year;
641       b = (a / 4) - (a / 100) + (a / 400);
642       c = ((a - 1) / 4) - ((a - 1) / 100) + ((a - 1) / 400);
643       s = b - c;
644       e = s + 1;
645       f = day + (((153 * (month - 3)) + 2) / 5) + 58 + s;
646     }
647 
648   g = (a + b) % 7;
649   d = (f + g - e) % 7;
650   n = f + 3 - d;
651 
652   if (week_number)
653     {
654       if (n < 0)
655         *week_number = 53 - ((g - s) / 5);
656       else if (n > 364 + s)
657         *week_number = 1;
658       else
659         *week_number = (n / 7) + 1;
660     }
661 
662   if (day_of_week)
663     *day_of_week = d + 1;
664 
665   if (day_of_year)
666     *day_of_year = f + 1;
667 }
668 
669 /* Lifecycle {{{1 */
670 
671 static GDateTime *
g_date_time_alloc(GTimeZone * tz)672 g_date_time_alloc (GTimeZone *tz)
673 {
674   GDateTime *datetime;
675 
676   datetime = g_slice_new0 (GDateTime);
677   datetime->tz = g_time_zone_ref (tz);
678   datetime->ref_count = 1;
679 
680   return datetime;
681 }
682 
683 /**
684  * g_date_time_ref:
685  * @datetime: a #GDateTime
686  *
687  * Atomically increments the reference count of @datetime by one.
688  *
689  * Returns: the #GDateTime with the reference count increased
690  *
691  * Since: 2.26
692  */
693 GDateTime *
g_date_time_ref(GDateTime * datetime)694 g_date_time_ref (GDateTime *datetime)
695 {
696   g_return_val_if_fail (datetime != NULL, NULL);
697   g_return_val_if_fail (datetime->ref_count > 0, NULL);
698 
699   g_atomic_int_inc (&datetime->ref_count);
700 
701   return datetime;
702 }
703 
704 /**
705  * g_date_time_unref:
706  * @datetime: a #GDateTime
707  *
708  * Atomically decrements the reference count of @datetime by one.
709  *
710  * When the reference count reaches zero, the resources allocated by
711  * @datetime are freed
712  *
713  * Since: 2.26
714  */
715 void
g_date_time_unref(GDateTime * datetime)716 g_date_time_unref (GDateTime *datetime)
717 {
718   g_return_if_fail (datetime != NULL);
719   g_return_if_fail (datetime->ref_count > 0);
720 
721   if (g_atomic_int_dec_and_test (&datetime->ref_count))
722     {
723       g_time_zone_unref (datetime->tz);
724       g_slice_free (GDateTime, datetime);
725     }
726 }
727 
728 /* Internal state transformers {{{1 */
729 /*< internal >
730  * g_date_time_to_instant:
731  * @datetime: a #GDateTime
732  *
733  * Convert a @datetime into an instant.
734  *
735  * An instant is a number that uniquely describes a particular
736  * microsecond in time, taking time zone considerations into account.
737  * (ie: "03:00 -0400" is the same instant as "02:00 -0500").
738  *
739  * An instant is always positive but we use a signed return value to
740  * avoid troubles with C.
741  */
742 static gint64
g_date_time_to_instant(GDateTime * datetime)743 g_date_time_to_instant (GDateTime *datetime)
744 {
745   gint64 offset;
746 
747   offset = g_time_zone_get_offset (datetime->tz, datetime->interval);
748   offset *= USEC_PER_SECOND;
749 
750   return datetime->days * USEC_PER_DAY + datetime->usec - offset;
751 }
752 
753 /*< internal >
754  * g_date_time_from_instant:
755  * @tz: a #GTimeZone
756  * @instant: an instant in time
757  *
758  * Creates a #GDateTime from a time zone and an instant.
759  *
760  * This might fail if the time ends up being out of range.
761  */
762 static GDateTime *
g_date_time_from_instant(GTimeZone * tz,gint64 instant)763 g_date_time_from_instant (GTimeZone *tz,
764                           gint64     instant)
765 {
766   GDateTime *datetime;
767   gint64 offset;
768 
769   if (instant < 0 || instant > G_GINT64_CONSTANT (1000000000000000000))
770     return NULL;
771 
772   datetime = g_date_time_alloc (tz);
773   datetime->interval = g_time_zone_find_interval (tz,
774                                                   G_TIME_TYPE_UNIVERSAL,
775                                                   INSTANT_TO_UNIX (instant));
776   offset = g_time_zone_get_offset (datetime->tz, datetime->interval);
777   offset *= USEC_PER_SECOND;
778 
779   instant += offset;
780 
781   datetime->days = instant / USEC_PER_DAY;
782   datetime->usec = instant % USEC_PER_DAY;
783 
784   if (datetime->days < 1 || 3652059 < datetime->days)
785     {
786       g_date_time_unref (datetime);
787       datetime = NULL;
788     }
789 
790   return datetime;
791 }
792 
793 
794 /*< internal >
795  * g_date_time_deal_with_date_change:
796  * @datetime: a #GDateTime
797  *
798  * This function should be called whenever the date changes by adding
799  * days, months or years.  It does three things.
800  *
801  * First, we ensure that the date falls between 0001-01-01 and
802  * 9999-12-31 and return %FALSE if it does not.
803  *
804  * Next we update the ->interval field.
805  *
806  * Finally, we ensure that the resulting date and time pair exists (by
807  * ensuring that our time zone has an interval containing it) and
808  * adjusting as required.  For example, if we have the time 02:30:00 on
809  * March 13 2010 in Toronto and we add 1 day to it, we would end up with
810  * 2:30am on March 14th, which doesn't exist.  In that case, we bump the
811  * time up to 3:00am.
812  */
813 static gboolean
g_date_time_deal_with_date_change(GDateTime * datetime)814 g_date_time_deal_with_date_change (GDateTime *datetime)
815 {
816   GTimeType was_dst;
817   gint64 full_time;
818   gint64 usec;
819 
820   if (datetime->days < 1 || datetime->days > 3652059)
821     return FALSE;
822 
823   was_dst = g_time_zone_is_dst (datetime->tz, datetime->interval);
824 
825   full_time = datetime->days * USEC_PER_DAY + datetime->usec;
826 
827 
828   usec = full_time % USEC_PER_SECOND;
829   full_time /= USEC_PER_SECOND;
830   full_time -= UNIX_EPOCH_START * SEC_PER_DAY;
831 
832   datetime->interval = g_time_zone_adjust_time (datetime->tz,
833                                                 was_dst,
834                                                 &full_time);
835   full_time += UNIX_EPOCH_START * SEC_PER_DAY;
836   full_time *= USEC_PER_SECOND;
837   full_time += usec;
838 
839   datetime->days = full_time / USEC_PER_DAY;
840   datetime->usec = full_time % USEC_PER_DAY;
841 
842   /* maybe daylight time caused us to shift to a different day,
843    * but it definitely didn't push us into a different year */
844   return TRUE;
845 }
846 
847 static GDateTime *
g_date_time_replace_days(GDateTime * datetime,gint days)848 g_date_time_replace_days (GDateTime *datetime,
849                           gint       days)
850 {
851   GDateTime *new;
852 
853   new = g_date_time_alloc (datetime->tz);
854   new->interval = datetime->interval;
855   new->usec = datetime->usec;
856   new->days = days;
857 
858   if (!g_date_time_deal_with_date_change (new))
859     {
860       g_date_time_unref (new);
861       new = NULL;
862     }
863 
864   return new;
865 }
866 
867 /* now/unix/timeval Constructors {{{1 */
868 
869 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
870 /*< internal >
871  * g_date_time_new_from_timeval:
872  * @tz: a #GTimeZone
873  * @tv: a #GTimeVal
874  *
875  * Creates a #GDateTime corresponding to the given #GTimeVal @tv in the
876  * given time zone @tz.
877  *
878  * The time contained in a #GTimeVal is always stored in the form of
879  * seconds elapsed since 1970-01-01 00:00:00 UTC, regardless of the
880  * given time zone.
881  *
882  * This call can fail (returning %NULL) if @tv represents a time outside
883  * of the supported range of #GDateTime.
884  *
885  * You should release the return value by calling g_date_time_unref()
886  * when you are done with it.
887  *
888  * Returns: a new #GDateTime, or %NULL
889  *
890  * Since: 2.26
891  **/
892 static GDateTime *
g_date_time_new_from_timeval(GTimeZone * tz,const GTimeVal * tv)893 g_date_time_new_from_timeval (GTimeZone      *tz,
894                               const GTimeVal *tv)
895 {
896   if ((gint64) tv->tv_sec > G_MAXINT64 - 1 ||
897       !UNIX_TO_INSTANT_IS_VALID ((gint64) tv->tv_sec + 1))
898     return NULL;
899 
900   return g_date_time_from_instant (tz, tv->tv_usec +
901                                    UNIX_TO_INSTANT (tv->tv_sec));
902 }
903 G_GNUC_END_IGNORE_DEPRECATIONS
904 
905 /*< internal >
906  * g_date_time_new_from_unix:
907  * @tz: a #GTimeZone
908  * @usecs: the Unix time, in microseconds since the epoch
909  *
910  * Creates a #GDateTime corresponding to the given Unix time @t_us in the
911  * given time zone @tz.
912  *
913  * Unix time is the number of seconds that have elapsed since 1970-01-01
914  * 00:00:00 UTC, regardless of the time zone given.
915  *
916  * This call can fail (returning %NULL) if @t represents a time outside
917  * of the supported range of #GDateTime.
918  *
919  * You should release the return value by calling g_date_time_unref()
920  * when you are done with it.
921  *
922  * Returns: a new #GDateTime, or %NULL
923  *
924  * Since: 2.26
925  **/
926 static GDateTime *
g_date_time_new_from_unix(GTimeZone * tz,gint64 usecs)927 g_date_time_new_from_unix (GTimeZone *tz,
928                            gint64     usecs)
929 {
930   if (!UNIX_USECS_TO_INSTANT_IS_VALID (usecs))
931     return NULL;
932 
933   return g_date_time_from_instant (tz, UNIX_USECS_TO_INSTANT (usecs));
934 }
935 
936 /**
937  * g_date_time_new_now: (constructor)
938  * @tz: a #GTimeZone
939  *
940  * Creates a #GDateTime corresponding to this exact instant in the given
941  * time zone @tz.  The time is as accurate as the system allows, to a
942  * maximum accuracy of 1 microsecond.
943  *
944  * This function will always succeed unless GLib is still being used after the
945  * year 9999.
946  *
947  * You should release the return value by calling g_date_time_unref()
948  * when you are done with it.
949  *
950  * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
951  *
952  * Since: 2.26
953  **/
954 GDateTime *
g_date_time_new_now(GTimeZone * tz)955 g_date_time_new_now (GTimeZone *tz)
956 {
957   gint64 now_us;
958 
959   now_us = g_get_real_time ();
960 
961   return g_date_time_new_from_unix (tz, now_us);
962 }
963 
964 /**
965  * g_date_time_new_now_local: (constructor)
966  *
967  * Creates a #GDateTime corresponding to this exact instant in the local
968  * time zone.
969  *
970  * This is equivalent to calling g_date_time_new_now() with the time
971  * zone returned by g_time_zone_new_local().
972  *
973  * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
974  *
975  * Since: 2.26
976  **/
977 GDateTime *
g_date_time_new_now_local(void)978 g_date_time_new_now_local (void)
979 {
980   GDateTime *datetime;
981   GTimeZone *local;
982 
983   local = g_time_zone_new_local ();
984   datetime = g_date_time_new_now (local);
985   g_time_zone_unref (local);
986 
987   return datetime;
988 }
989 
990 /**
991  * g_date_time_new_now_utc: (constructor)
992  *
993  * Creates a #GDateTime corresponding to this exact instant in UTC.
994  *
995  * This is equivalent to calling g_date_time_new_now() with the time
996  * zone returned by g_time_zone_new_utc().
997  *
998  * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
999  *
1000  * Since: 2.26
1001  **/
1002 GDateTime *
g_date_time_new_now_utc(void)1003 g_date_time_new_now_utc (void)
1004 {
1005   GDateTime *datetime;
1006   GTimeZone *utc;
1007 
1008   utc = g_time_zone_new_utc ();
1009   datetime = g_date_time_new_now (utc);
1010   g_time_zone_unref (utc);
1011 
1012   return datetime;
1013 }
1014 
1015 /**
1016  * g_date_time_new_from_unix_local: (constructor)
1017  * @t: the Unix time
1018  *
1019  * Creates a #GDateTime corresponding to the given Unix time @t in the
1020  * local time zone.
1021  *
1022  * Unix time is the number of seconds that have elapsed since 1970-01-01
1023  * 00:00:00 UTC, regardless of the local time offset.
1024  *
1025  * This call can fail (returning %NULL) if @t represents a time outside
1026  * of the supported range of #GDateTime.
1027  *
1028  * You should release the return value by calling g_date_time_unref()
1029  * when you are done with it.
1030  *
1031  * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
1032  *
1033  * Since: 2.26
1034  **/
1035 GDateTime *
g_date_time_new_from_unix_local(gint64 t)1036 g_date_time_new_from_unix_local (gint64 t)
1037 {
1038   GDateTime *datetime;
1039   GTimeZone *local;
1040 
1041   if (t > G_MAXINT64 / USEC_PER_SECOND ||
1042       t < G_MININT64 / USEC_PER_SECOND)
1043     return NULL;
1044 
1045   local = g_time_zone_new_local ();
1046   datetime = g_date_time_new_from_unix (local, t * USEC_PER_SECOND);
1047   g_time_zone_unref (local);
1048 
1049   return datetime;
1050 }
1051 
1052 /**
1053  * g_date_time_new_from_unix_utc: (constructor)
1054  * @t: the Unix time
1055  *
1056  * Creates a #GDateTime corresponding to the given Unix time @t in UTC.
1057  *
1058  * Unix time is the number of seconds that have elapsed since 1970-01-01
1059  * 00:00:00 UTC.
1060  *
1061  * This call can fail (returning %NULL) if @t represents a time outside
1062  * of the supported range of #GDateTime.
1063  *
1064  * You should release the return value by calling g_date_time_unref()
1065  * when you are done with it.
1066  *
1067  * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
1068  *
1069  * Since: 2.26
1070  **/
1071 GDateTime *
g_date_time_new_from_unix_utc(gint64 t)1072 g_date_time_new_from_unix_utc (gint64 t)
1073 {
1074   GDateTime *datetime;
1075   GTimeZone *utc;
1076 
1077   if (t > G_MAXINT64 / USEC_PER_SECOND ||
1078       t < G_MININT64 / USEC_PER_SECOND)
1079     return NULL;
1080 
1081   utc = g_time_zone_new_utc ();
1082   datetime = g_date_time_new_from_unix (utc, t * USEC_PER_SECOND);
1083   g_time_zone_unref (utc);
1084 
1085   return datetime;
1086 }
1087 
1088 /**
1089  * g_date_time_new_from_timeval_local: (constructor)
1090  * @tv: a #GTimeVal
1091  *
1092  * Creates a #GDateTime corresponding to the given #GTimeVal @tv in the
1093  * local time zone.
1094  *
1095  * The time contained in a #GTimeVal is always stored in the form of
1096  * seconds elapsed since 1970-01-01 00:00:00 UTC, regardless of the
1097  * local time offset.
1098  *
1099  * This call can fail (returning %NULL) if @tv represents a time outside
1100  * of the supported range of #GDateTime.
1101  *
1102  * You should release the return value by calling g_date_time_unref()
1103  * when you are done with it.
1104  *
1105  * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
1106  *
1107  * Since: 2.26
1108  * Deprecated: 2.62: #GTimeVal is not year-2038-safe. Use
1109  *    g_date_time_new_from_unix_local() instead.
1110  **/
1111 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1112 GDateTime *
g_date_time_new_from_timeval_local(const GTimeVal * tv)1113 g_date_time_new_from_timeval_local (const GTimeVal *tv)
1114 {
1115   GDateTime *datetime;
1116   GTimeZone *local;
1117 
1118   local = g_time_zone_new_local ();
1119   datetime = g_date_time_new_from_timeval (local, tv);
1120   g_time_zone_unref (local);
1121 
1122   return datetime;
1123 }
1124 G_GNUC_END_IGNORE_DEPRECATIONS
1125 
1126 /**
1127  * g_date_time_new_from_timeval_utc: (constructor)
1128  * @tv: a #GTimeVal
1129  *
1130  * Creates a #GDateTime corresponding to the given #GTimeVal @tv in UTC.
1131  *
1132  * The time contained in a #GTimeVal is always stored in the form of
1133  * seconds elapsed since 1970-01-01 00:00:00 UTC.
1134  *
1135  * This call can fail (returning %NULL) if @tv represents a time outside
1136  * of the supported range of #GDateTime.
1137  *
1138  * You should release the return value by calling g_date_time_unref()
1139  * when you are done with it.
1140  *
1141  * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
1142  *
1143  * Since: 2.26
1144  * Deprecated: 2.62: #GTimeVal is not year-2038-safe. Use
1145  *    g_date_time_new_from_unix_utc() instead.
1146  **/
1147 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1148 GDateTime *
g_date_time_new_from_timeval_utc(const GTimeVal * tv)1149 g_date_time_new_from_timeval_utc (const GTimeVal *tv)
1150 {
1151   GDateTime *datetime;
1152   GTimeZone *utc;
1153 
1154   utc = g_time_zone_new_utc ();
1155   datetime = g_date_time_new_from_timeval (utc, tv);
1156   g_time_zone_unref (utc);
1157 
1158   return datetime;
1159 }
1160 G_GNUC_END_IGNORE_DEPRECATIONS
1161 
1162 /* Parse integers in the form d (week days), dd (hours etc), ddd (ordinal days) or dddd (years) */
1163 static gboolean
get_iso8601_int(const gchar * text,gsize length,gint * value)1164 get_iso8601_int (const gchar *text, gsize length, gint *value)
1165 {
1166   gsize i;
1167   guint v = 0;
1168 
1169   if (length < 1 || length > 4)
1170     return FALSE;
1171 
1172   for (i = 0; i < length; i++)
1173     {
1174       const gchar c = text[i];
1175       if (c < '0' || c > '9')
1176         return FALSE;
1177       v = v * 10 + (c - '0');
1178     }
1179 
1180   *value = v;
1181   return TRUE;
1182 }
1183 
1184 /* Parse seconds in the form ss or ss.sss (variable length decimal) */
1185 static gboolean
get_iso8601_seconds(const gchar * text,gsize length,gdouble * value)1186 get_iso8601_seconds (const gchar *text, gsize length, gdouble *value)
1187 {
1188   gsize i;
1189   guint64 divisor = 1, v = 0;
1190 
1191   if (length < 2)
1192     return FALSE;
1193 
1194   for (i = 0; i < 2; i++)
1195     {
1196       const gchar c = text[i];
1197       if (c < '0' || c > '9')
1198         return FALSE;
1199       v = v * 10 + (c - '0');
1200     }
1201 
1202   if (length > 2 && !(text[i] == '.' || text[i] == ','))
1203     return FALSE;
1204 
1205   /* Ignore leap seconds, see g_date_time_new_from_iso8601() */
1206   if (v >= 60.0 && v <= 61.0)
1207     v = 59.0;
1208 
1209   i++;
1210   if (i == length)
1211     return FALSE;
1212 
1213   for (; i < length; i++)
1214     {
1215       const gchar c = text[i];
1216       if (c < '0' || c > '9' ||
1217           v > (G_MAXUINT64 - (c - '0')) / 10 ||
1218           divisor > G_MAXUINT64 / 10)
1219         return FALSE;
1220       v = v * 10 + (c - '0');
1221       divisor *= 10;
1222     }
1223 
1224   *value = (gdouble) v / divisor;
1225   return TRUE;
1226 }
1227 
1228 static GDateTime *
g_date_time_new_ordinal(GTimeZone * tz,gint year,gint ordinal_day,gint hour,gint minute,gdouble seconds)1229 g_date_time_new_ordinal (GTimeZone *tz, gint year, gint ordinal_day, gint hour, gint minute, gdouble seconds)
1230 {
1231   GDateTime *dt;
1232 
1233   if (ordinal_day < 1 || ordinal_day > (GREGORIAN_LEAP (year) ? 366 : 365))
1234     return NULL;
1235 
1236   dt = g_date_time_new (tz, year, 1, 1, hour, minute, seconds);
1237   if (dt == NULL)
1238     return NULL;
1239   dt->days += ordinal_day - 1;
1240 
1241   return dt;
1242 }
1243 
1244 static GDateTime *
g_date_time_new_week(GTimeZone * tz,gint year,gint week,gint week_day,gint hour,gint minute,gdouble seconds)1245 g_date_time_new_week (GTimeZone *tz, gint year, gint week, gint week_day, gint hour, gint minute, gdouble seconds)
1246 {
1247   gint64 p;
1248   gint max_week, jan4_week_day, ordinal_day;
1249   GDateTime *dt;
1250 
1251   p = (year * 365 + (year / 4) - (year / 100) + (year / 400)) % 7;
1252   max_week = p == 4 ? 53 : 52;
1253 
1254   if (week < 1 || week > max_week || week_day < 1 || week_day > 7)
1255     return NULL;
1256 
1257   dt = g_date_time_new (tz, year, 1, 4, 0, 0, 0);
1258   if (dt == NULL)
1259     return NULL;
1260   g_date_time_get_week_number (dt, NULL, &jan4_week_day, NULL);
1261   g_date_time_unref (dt);
1262 
1263   ordinal_day = (week * 7) + week_day - (jan4_week_day + 3);
1264   if (ordinal_day < 0)
1265     {
1266       year--;
1267       ordinal_day += GREGORIAN_LEAP (year) ? 366 : 365;
1268     }
1269   else if (ordinal_day > (GREGORIAN_LEAP (year) ? 366 : 365))
1270     {
1271       ordinal_day -= (GREGORIAN_LEAP (year) ? 366 : 365);
1272       year++;
1273     }
1274 
1275   return g_date_time_new_ordinal (tz, year, ordinal_day, hour, minute, seconds);
1276 }
1277 
1278 static GDateTime *
parse_iso8601_date(const gchar * text,gsize length,gint hour,gint minute,gdouble seconds,GTimeZone * tz)1279 parse_iso8601_date (const gchar *text, gsize length,
1280                     gint hour, gint minute, gdouble seconds, GTimeZone *tz)
1281 {
1282   /* YYYY-MM-DD */
1283   if (length == 10 && text[4] == '-' && text[7] == '-')
1284     {
1285       int year, month, day;
1286       if (!get_iso8601_int (text, 4, &year) ||
1287           !get_iso8601_int (text + 5, 2, &month) ||
1288           !get_iso8601_int (text + 8, 2, &day))
1289         return NULL;
1290       return g_date_time_new (tz, year, month, day, hour, minute, seconds);
1291     }
1292   /* YYYY-DDD */
1293   else if (length == 8 && text[4] == '-')
1294     {
1295       gint year, ordinal_day;
1296       if (!get_iso8601_int (text, 4, &year) ||
1297           !get_iso8601_int (text + 5, 3, &ordinal_day))
1298         return NULL;
1299       return g_date_time_new_ordinal (tz, year, ordinal_day, hour, minute, seconds);
1300     }
1301   /* YYYY-Www-D */
1302   else if (length == 10 && text[4] == '-' && text[5] == 'W' && text[8] == '-')
1303     {
1304       gint year, week, week_day;
1305       if (!get_iso8601_int (text, 4, &year) ||
1306           !get_iso8601_int (text + 6, 2, &week) ||
1307           !get_iso8601_int (text + 9, 1, &week_day))
1308         return NULL;
1309       return g_date_time_new_week (tz, year, week, week_day, hour, minute, seconds);
1310     }
1311   /* YYYYWwwD */
1312   else if (length == 8 && text[4] == 'W')
1313     {
1314       gint year, week, week_day;
1315       if (!get_iso8601_int (text, 4, &year) ||
1316           !get_iso8601_int (text + 5, 2, &week) ||
1317           !get_iso8601_int (text + 7, 1, &week_day))
1318         return NULL;
1319       return g_date_time_new_week (tz, year, week, week_day, hour, minute, seconds);
1320     }
1321   /* YYYYMMDD */
1322   else if (length == 8)
1323     {
1324       int year, month, day;
1325       if (!get_iso8601_int (text, 4, &year) ||
1326           !get_iso8601_int (text + 4, 2, &month) ||
1327           !get_iso8601_int (text + 6, 2, &day))
1328         return NULL;
1329       return g_date_time_new (tz, year, month, day, hour, minute, seconds);
1330     }
1331   /* YYYYDDD */
1332   else if (length == 7)
1333     {
1334       gint year, ordinal_day;
1335       if (!get_iso8601_int (text, 4, &year) ||
1336           !get_iso8601_int (text + 4, 3, &ordinal_day))
1337         return NULL;
1338       return g_date_time_new_ordinal (tz, year, ordinal_day, hour, minute, seconds);
1339     }
1340   else
1341     return FALSE;
1342 }
1343 
1344 static GTimeZone *
parse_iso8601_timezone(const gchar * text,gsize length,gssize * tz_offset)1345 parse_iso8601_timezone (const gchar *text, gsize length, gssize *tz_offset)
1346 {
1347   gint i, tz_length, offset_hours, offset_minutes;
1348   gint offset_sign = 1;
1349   GTimeZone *tz;
1350 
1351   /* UTC uses Z suffix  */
1352   if (length > 0 && text[length - 1] == 'Z')
1353     {
1354       *tz_offset = length - 1;
1355       return g_time_zone_new_utc ();
1356     }
1357 
1358   /* Look for '+' or '-' of offset */
1359   for (i = length - 1; i >= 0; i--)
1360     if (text[i] == '+' || text[i] == '-')
1361       {
1362         offset_sign = text[i] == '-' ? -1 : 1;
1363         break;
1364       }
1365   if (i < 0)
1366     return NULL;
1367   tz_length = length - i;
1368 
1369   /* +hh:mm or -hh:mm */
1370   if (tz_length == 6 && text[i+3] == ':')
1371     {
1372       if (!get_iso8601_int (text + i + 1, 2, &offset_hours) ||
1373           !get_iso8601_int (text + i + 4, 2, &offset_minutes))
1374         return NULL;
1375     }
1376   /* +hhmm or -hhmm */
1377   else if (tz_length == 5)
1378     {
1379       if (!get_iso8601_int (text + i + 1, 2, &offset_hours) ||
1380           !get_iso8601_int (text + i + 3, 2, &offset_minutes))
1381         return NULL;
1382     }
1383   /* +hh or -hh */
1384   else if (tz_length == 3)
1385     {
1386       if (!get_iso8601_int (text + i + 1, 2, &offset_hours))
1387         return NULL;
1388       offset_minutes = 0;
1389     }
1390   else
1391     return NULL;
1392 
1393   *tz_offset = i;
1394   tz = g_time_zone_new_identifier (text + i);
1395 
1396   /* Double-check that the GTimeZone matches our interpretation of the timezone.
1397    * This can fail because our interpretation is less strict than (for example)
1398    * parse_time() in gtimezone.c, which restricts the range of the parsed
1399    * integers. */
1400   if (tz == NULL || g_time_zone_get_offset (tz, 0) != offset_sign * (offset_hours * 3600 + offset_minutes * 60))
1401     {
1402       g_clear_pointer (&tz, g_time_zone_unref);
1403       return NULL;
1404     }
1405 
1406   return tz;
1407 }
1408 
1409 static gboolean
parse_iso8601_time(const gchar * text,gsize length,gint * hour,gint * minute,gdouble * seconds,GTimeZone ** tz)1410 parse_iso8601_time (const gchar *text, gsize length,
1411                     gint *hour, gint *minute, gdouble *seconds, GTimeZone **tz)
1412 {
1413   gssize tz_offset = -1;
1414 
1415   /* Check for timezone suffix */
1416   *tz = parse_iso8601_timezone (text, length, &tz_offset);
1417   if (tz_offset >= 0)
1418     length = tz_offset;
1419 
1420   /* hh:mm:ss(.sss) */
1421   if (length >= 8 && text[2] == ':' && text[5] == ':')
1422     {
1423       return get_iso8601_int (text, 2, hour) &&
1424              get_iso8601_int (text + 3, 2, minute) &&
1425              get_iso8601_seconds (text + 6, length - 6, seconds);
1426     }
1427   /* hhmmss(.sss) */
1428   else if (length >= 6)
1429     {
1430       return get_iso8601_int (text, 2, hour) &&
1431              get_iso8601_int (text + 2, 2, minute) &&
1432              get_iso8601_seconds (text + 4, length - 4, seconds);
1433     }
1434   else
1435     return FALSE;
1436 }
1437 
1438 /**
1439  * g_date_time_new_from_iso8601: (constructor)
1440  * @text: an ISO 8601 formatted time string.
1441  * @default_tz: (nullable): a #GTimeZone to use if the text doesn't contain a
1442  *                          timezone, or %NULL.
1443  *
1444  * Creates a #GDateTime corresponding to the given
1445  * [ISO 8601 formatted string](https://en.wikipedia.org/wiki/ISO_8601)
1446  * @text. ISO 8601 strings of the form <date><sep><time><tz> are supported, with
1447  * some extensions from [RFC 3339](https://tools.ietf.org/html/rfc3339) as
1448  * mentioned below.
1449  *
1450  * Note that as #GDateTime "is oblivious to leap seconds", leap seconds information
1451  * in an ISO-8601 string will be ignored, so a `23:59:60` time would be parsed as
1452  * `23:59:59`.
1453  *
1454  * <sep> is the separator and can be either 'T', 't' or ' '. The latter two
1455  * separators are an extension from
1456  * [RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6).
1457  *
1458  * <date> is in the form:
1459  *
1460  * - `YYYY-MM-DD` - Year/month/day, e.g. 2016-08-24.
1461  * - `YYYYMMDD` - Same as above without dividers.
1462  * - `YYYY-DDD` - Ordinal day where DDD is from 001 to 366, e.g. 2016-237.
1463  * - `YYYYDDD` - Same as above without dividers.
1464  * - `YYYY-Www-D` - Week day where ww is from 01 to 52 and D from 1-7,
1465  *   e.g. 2016-W34-3.
1466  * - `YYYYWwwD` - Same as above without dividers.
1467  *
1468  * <time> is in the form:
1469  *
1470  * - `hh:mm:ss(.sss)` - Hours, minutes, seconds (subseconds), e.g. 22:10:42.123.
1471  * - `hhmmss(.sss)` - Same as above without dividers.
1472  *
1473  * <tz> is an optional timezone suffix of the form:
1474  *
1475  * - `Z` - UTC.
1476  * - `+hh:mm` or `-hh:mm` - Offset from UTC in hours and minutes, e.g. +12:00.
1477  * - `+hh` or `-hh` - Offset from UTC in hours, e.g. +12.
1478  *
1479  * If the timezone is not provided in @text it must be provided in @default_tz
1480  * (this field is otherwise ignored).
1481  *
1482  * This call can fail (returning %NULL) if @text is not a valid ISO 8601
1483  * formatted string.
1484  *
1485  * You should release the return value by calling g_date_time_unref()
1486  * when you are done with it.
1487  *
1488  * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
1489  *
1490  * Since: 2.56
1491  */
1492 GDateTime *
g_date_time_new_from_iso8601(const gchar * text,GTimeZone * default_tz)1493 g_date_time_new_from_iso8601 (const gchar *text, GTimeZone *default_tz)
1494 {
1495   gint length, date_length = -1;
1496   gint hour = 0, minute = 0;
1497   gdouble seconds = 0.0;
1498   GTimeZone *tz = NULL;
1499   GDateTime *datetime = NULL;
1500 
1501   g_return_val_if_fail (text != NULL, NULL);
1502 
1503   /* Count length of string and find date / time separator ('T', 't', or ' ') */
1504   for (length = 0; text[length] != '\0'; length++)
1505     {
1506       if (date_length < 0 && (text[length] == 'T' || text[length] == 't' || text[length] == ' '))
1507         date_length = length;
1508     }
1509 
1510   if (date_length < 0)
1511     return NULL;
1512 
1513   if (!parse_iso8601_time (text + date_length + 1, length - (date_length + 1),
1514                            &hour, &minute, &seconds, &tz))
1515     goto out;
1516   if (tz == NULL && default_tz == NULL)
1517     return NULL;
1518 
1519   datetime = parse_iso8601_date (text, date_length, hour, minute, seconds, tz ? tz : default_tz);
1520 
1521 out:
1522     if (tz != NULL)
1523       g_time_zone_unref (tz);
1524     return datetime;
1525 }
1526 
1527 /* full new functions {{{1 */
1528 
1529 /**
1530  * g_date_time_new: (constructor)
1531  * @tz: a #GTimeZone
1532  * @year: the year component of the date
1533  * @month: the month component of the date
1534  * @day: the day component of the date
1535  * @hour: the hour component of the date
1536  * @minute: the minute component of the date
1537  * @seconds: the number of seconds past the minute
1538  *
1539  * Creates a new #GDateTime corresponding to the given date and time in
1540  * the time zone @tz.
1541  *
1542  * The @year must be between 1 and 9999, @month between 1 and 12 and @day
1543  * between 1 and 28, 29, 30 or 31 depending on the month and the year.
1544  *
1545  * @hour must be between 0 and 23 and @minute must be between 0 and 59.
1546  *
1547  * @seconds must be at least 0.0 and must be strictly less than 60.0.
1548  * It will be rounded down to the nearest microsecond.
1549  *
1550  * If the given time is not representable in the given time zone (for
1551  * example, 02:30 on March 14th 2010 in Toronto, due to daylight savings
1552  * time) then the time will be rounded up to the nearest existing time
1553  * (in this case, 03:00).  If this matters to you then you should verify
1554  * the return value for containing the same as the numbers you gave.
1555  *
1556  * In the case that the given time is ambiguous in the given time zone
1557  * (for example, 01:30 on November 7th 2010 in Toronto, due to daylight
1558  * savings time) then the time falling within standard (ie:
1559  * non-daylight) time is taken.
1560  *
1561  * It not considered a programmer error for the values to this function
1562  * to be out of range, but in the case that they are, the function will
1563  * return %NULL.
1564  *
1565  * You should release the return value by calling g_date_time_unref()
1566  * when you are done with it.
1567  *
1568  * Returns: (transfer full) (nullable): a new #GDateTime, or %NULL
1569  *
1570  * Since: 2.26
1571  **/
1572 GDateTime *
g_date_time_new(GTimeZone * tz,gint year,gint month,gint day,gint hour,gint minute,gdouble seconds)1573 g_date_time_new (GTimeZone *tz,
1574                  gint       year,
1575                  gint       month,
1576                  gint       day,
1577                  gint       hour,
1578                  gint       minute,
1579                  gdouble    seconds)
1580 {
1581   GDateTime *datetime;
1582   gint64 full_time;
1583   /* keep these variables as volatile. We do not want them ending up in
1584    * registers - them doing so may cause us to hit precision problems on i386.
1585    * See: https://bugzilla.gnome.org/show_bug.cgi?id=792410 */
1586   volatile gint64 usec;
1587   volatile gdouble usecd;
1588 
1589   g_return_val_if_fail (tz != NULL, NULL);
1590 
1591   if (year < 1 || year > 9999 ||
1592       month < 1 || month > 12 ||
1593       day < 1 || day > days_in_months[GREGORIAN_LEAP (year)][month] ||
1594       hour < 0 || hour > 23 ||
1595       minute < 0 || minute > 59 ||
1596       isnan (seconds) ||
1597       seconds < 0.0 || seconds >= 60.0)
1598     return NULL;
1599 
1600   datetime = g_date_time_alloc (tz);
1601   datetime->days = ymd_to_days (year, month, day);
1602   datetime->usec = (hour   * USEC_PER_HOUR)
1603                  + (minute * USEC_PER_MINUTE)
1604                  + (gint64) (seconds * USEC_PER_SECOND);
1605 
1606   full_time = SEC_PER_DAY *
1607                 (ymd_to_days (year, month, day) - UNIX_EPOCH_START) +
1608               SECS_PER_HOUR * hour +
1609               SECS_PER_MINUTE * minute +
1610               (int) seconds;
1611 
1612   datetime->interval = g_time_zone_adjust_time (datetime->tz,
1613                                                 G_TIME_TYPE_STANDARD,
1614                                                 &full_time);
1615 
1616   /* This is the correct way to convert a scaled FP value to integer.
1617    * If this surprises you, please observe that (int)(1.000001 * 1e6)
1618    * is 1000000.  This is not a problem with precision, it's just how
1619    * FP numbers work.
1620    * See https://bugzilla.gnome.org/show_bug.cgi?id=697715. */
1621   usec = seconds * USEC_PER_SECOND;
1622   usecd = (usec + 1) * 1e-6;
1623   if (usecd <= seconds) {
1624     usec++;
1625   }
1626 
1627   full_time += UNIX_EPOCH_START * SEC_PER_DAY;
1628   datetime->days = full_time / SEC_PER_DAY;
1629   datetime->usec = (full_time % SEC_PER_DAY) * USEC_PER_SECOND;
1630   datetime->usec += usec % USEC_PER_SECOND;
1631 
1632   return datetime;
1633 }
1634 
1635 /**
1636  * g_date_time_new_local: (constructor)
1637  * @year: the year component of the date
1638  * @month: the month component of the date
1639  * @day: the day component of the date
1640  * @hour: the hour component of the date
1641  * @minute: the minute component of the date
1642  * @seconds: the number of seconds past the minute
1643  *
1644  * Creates a new #GDateTime corresponding to the given date and time in
1645  * the local time zone.
1646  *
1647  * This call is equivalent to calling g_date_time_new() with the time
1648  * zone returned by g_time_zone_new_local().
1649  *
1650  * Returns: (transfer full) (nullable): a #GDateTime, or %NULL
1651  *
1652  * Since: 2.26
1653  **/
1654 GDateTime *
g_date_time_new_local(gint year,gint month,gint day,gint hour,gint minute,gdouble seconds)1655 g_date_time_new_local (gint    year,
1656                        gint    month,
1657                        gint    day,
1658                        gint    hour,
1659                        gint    minute,
1660                        gdouble seconds)
1661 {
1662   GDateTime *datetime;
1663   GTimeZone *local;
1664 
1665   local = g_time_zone_new_local ();
1666   datetime = g_date_time_new (local, year, month, day, hour, minute, seconds);
1667   g_time_zone_unref (local);
1668 
1669   return datetime;
1670 }
1671 
1672 /**
1673  * g_date_time_new_utc: (constructor)
1674  * @year: the year component of the date
1675  * @month: the month component of the date
1676  * @day: the day component of the date
1677  * @hour: the hour component of the date
1678  * @minute: the minute component of the date
1679  * @seconds: the number of seconds past the minute
1680  *
1681  * Creates a new #GDateTime corresponding to the given date and time in
1682  * UTC.
1683  *
1684  * This call is equivalent to calling g_date_time_new() with the time
1685  * zone returned by g_time_zone_new_utc().
1686  *
1687  * Returns: (transfer full) (nullable): a #GDateTime, or %NULL
1688  *
1689  * Since: 2.26
1690  **/
1691 GDateTime *
g_date_time_new_utc(gint year,gint month,gint day,gint hour,gint minute,gdouble seconds)1692 g_date_time_new_utc (gint    year,
1693                      gint    month,
1694                      gint    day,
1695                      gint    hour,
1696                      gint    minute,
1697                      gdouble seconds)
1698 {
1699   GDateTime *datetime;
1700   GTimeZone *utc;
1701 
1702   utc = g_time_zone_new_utc ();
1703   datetime = g_date_time_new (utc, year, month, day, hour, minute, seconds);
1704   g_time_zone_unref (utc);
1705 
1706   return datetime;
1707 }
1708 
1709 /* Adders {{{1 */
1710 
1711 /**
1712  * g_date_time_add:
1713  * @datetime: a #GDateTime
1714  * @timespan: a #GTimeSpan
1715  *
1716  * Creates a copy of @datetime and adds the specified timespan to the copy.
1717  *
1718  * Returns: (transfer full) (nullable): the newly created #GDateTime which
1719  *   should be freed with g_date_time_unref(), or %NULL
1720  *
1721  * Since: 2.26
1722  */
1723 GDateTime*
g_date_time_add(GDateTime * datetime,GTimeSpan timespan)1724 g_date_time_add (GDateTime *datetime,
1725                  GTimeSpan  timespan)
1726 {
1727   g_return_val_if_fail (datetime != NULL, NULL);
1728 
1729   return g_date_time_from_instant (datetime->tz, timespan +
1730                                    g_date_time_to_instant (datetime));
1731 }
1732 
1733 /**
1734  * g_date_time_add_years:
1735  * @datetime: a #GDateTime
1736  * @years: the number of years
1737  *
1738  * Creates a copy of @datetime and adds the specified number of years to the
1739  * copy. Add negative values to subtract years.
1740  *
1741  * As with g_date_time_add_months(), if the resulting date would be 29th
1742  * February on a non-leap year, the day will be clamped to 28th February.
1743  *
1744  * Returns: (transfer full) (nullable): the newly created #GDateTime which
1745  *   should be freed with g_date_time_unref(), or %NULL
1746  *
1747  * Since: 2.26
1748  */
1749 GDateTime *
g_date_time_add_years(GDateTime * datetime,gint years)1750 g_date_time_add_years (GDateTime *datetime,
1751                        gint       years)
1752 {
1753   gint year, month, day;
1754 
1755   g_return_val_if_fail (datetime != NULL, NULL);
1756 
1757   if (years < -10000 || years > 10000)
1758     return NULL;
1759 
1760   g_date_time_get_ymd (datetime, &year, &month, &day);
1761   year += years;
1762 
1763   /* only possible issue is if we've entered a year with no February 29
1764    */
1765   if (month == 2 && day == 29 && !GREGORIAN_LEAP (year))
1766     day = 28;
1767 
1768   return g_date_time_replace_days (datetime, ymd_to_days (year, month, day));
1769 }
1770 
1771 /**
1772  * g_date_time_add_months:
1773  * @datetime: a #GDateTime
1774  * @months: the number of months
1775  *
1776  * Creates a copy of @datetime and adds the specified number of months to the
1777  * copy. Add negative values to subtract months.
1778  *
1779  * The day of the month of the resulting #GDateTime is clamped to the number
1780  * of days in the updated calendar month. For example, if adding 1 month to
1781  * 31st January 2018, the result would be 28th February 2018. In 2020 (a leap
1782  * year), the result would be 29th February.
1783  *
1784  * Returns: (transfer full) (nullable): the newly created #GDateTime which
1785  *   should be freed with g_date_time_unref(), or %NULL
1786  *
1787  * Since: 2.26
1788  */
1789 GDateTime*
g_date_time_add_months(GDateTime * datetime,gint months)1790 g_date_time_add_months (GDateTime *datetime,
1791                         gint       months)
1792 {
1793   gint year, month, day;
1794 
1795   g_return_val_if_fail (datetime != NULL, NULL);
1796   g_date_time_get_ymd (datetime, &year, &month, &day);
1797 
1798   if (months < -120000 || months > 120000)
1799     return NULL;
1800 
1801   year += months / 12;
1802   month += months % 12;
1803   if (month < 1)
1804     {
1805       month += 12;
1806       year--;
1807     }
1808   else if (month > 12)
1809     {
1810       month -= 12;
1811       year++;
1812     }
1813 
1814   day = MIN (day, days_in_months[GREGORIAN_LEAP (year)][month]);
1815 
1816   return g_date_time_replace_days (datetime, ymd_to_days (year, month, day));
1817 }
1818 
1819 /**
1820  * g_date_time_add_weeks:
1821  * @datetime: a #GDateTime
1822  * @weeks: the number of weeks
1823  *
1824  * Creates a copy of @datetime and adds the specified number of weeks to the
1825  * copy. Add negative values to subtract weeks.
1826  *
1827  * Returns: (transfer full) (nullable): the newly created #GDateTime which
1828  *   should be freed with g_date_time_unref(), or %NULL
1829  *
1830  * Since: 2.26
1831  */
1832 GDateTime*
g_date_time_add_weeks(GDateTime * datetime,gint weeks)1833 g_date_time_add_weeks (GDateTime *datetime,
1834                        gint             weeks)
1835 {
1836   g_return_val_if_fail (datetime != NULL, NULL);
1837 
1838   return g_date_time_add_days (datetime, weeks * 7);
1839 }
1840 
1841 /**
1842  * g_date_time_add_days:
1843  * @datetime: a #GDateTime
1844  * @days: the number of days
1845  *
1846  * Creates a copy of @datetime and adds the specified number of days to the
1847  * copy. Add negative values to subtract days.
1848  *
1849  * Returns: (transfer full) (nullable): the newly created #GDateTime which
1850  *   should be freed with g_date_time_unref(), or %NULL
1851  *
1852  * Since: 2.26
1853  */
1854 GDateTime*
g_date_time_add_days(GDateTime * datetime,gint days)1855 g_date_time_add_days (GDateTime *datetime,
1856                       gint       days)
1857 {
1858   g_return_val_if_fail (datetime != NULL, NULL);
1859 
1860   if (days < -3660000 || days > 3660000)
1861     return NULL;
1862 
1863   return g_date_time_replace_days (datetime, datetime->days + days);
1864 }
1865 
1866 /**
1867  * g_date_time_add_hours:
1868  * @datetime: a #GDateTime
1869  * @hours: the number of hours to add
1870  *
1871  * Creates a copy of @datetime and adds the specified number of hours.
1872  * Add negative values to subtract hours.
1873  *
1874  * Returns: (transfer full) (nullable): the newly created #GDateTime which
1875  *   should be freed with g_date_time_unref(), or %NULL
1876  *
1877  * Since: 2.26
1878  */
1879 GDateTime*
g_date_time_add_hours(GDateTime * datetime,gint hours)1880 g_date_time_add_hours (GDateTime *datetime,
1881                        gint       hours)
1882 {
1883   return g_date_time_add (datetime, hours * USEC_PER_HOUR);
1884 }
1885 
1886 /**
1887  * g_date_time_add_minutes:
1888  * @datetime: a #GDateTime
1889  * @minutes: the number of minutes to add
1890  *
1891  * Creates a copy of @datetime adding the specified number of minutes.
1892  * Add negative values to subtract minutes.
1893  *
1894  * Returns: (transfer full) (nullable): the newly created #GDateTime which
1895  *   should be freed with g_date_time_unref(), or %NULL
1896  *
1897  * Since: 2.26
1898  */
1899 GDateTime*
g_date_time_add_minutes(GDateTime * datetime,gint minutes)1900 g_date_time_add_minutes (GDateTime *datetime,
1901                          gint             minutes)
1902 {
1903   return g_date_time_add (datetime, minutes * USEC_PER_MINUTE);
1904 }
1905 
1906 
1907 /**
1908  * g_date_time_add_seconds:
1909  * @datetime: a #GDateTime
1910  * @seconds: the number of seconds to add
1911  *
1912  * Creates a copy of @datetime and adds the specified number of seconds.
1913  * Add negative values to subtract seconds.
1914  *
1915  * Returns: (transfer full) (nullable): the newly created #GDateTime which
1916  *   should be freed with g_date_time_unref(), or %NULL
1917  *
1918  * Since: 2.26
1919  */
1920 GDateTime*
g_date_time_add_seconds(GDateTime * datetime,gdouble seconds)1921 g_date_time_add_seconds (GDateTime *datetime,
1922                          gdouble    seconds)
1923 {
1924   return g_date_time_add (datetime, seconds * USEC_PER_SECOND);
1925 }
1926 
1927 /**
1928  * g_date_time_add_full:
1929  * @datetime: a #GDateTime
1930  * @years: the number of years to add
1931  * @months: the number of months to add
1932  * @days: the number of days to add
1933  * @hours: the number of hours to add
1934  * @minutes: the number of minutes to add
1935  * @seconds: the number of seconds to add
1936  *
1937  * Creates a new #GDateTime adding the specified values to the current date and
1938  * time in @datetime. Add negative values to subtract.
1939  *
1940  * Returns: (transfer full) (nullable): the newly created #GDateTime which
1941  *   should be freed with g_date_time_unref(), or %NULL
1942  *
1943  * Since: 2.26
1944  */
1945 GDateTime *
g_date_time_add_full(GDateTime * datetime,gint years,gint months,gint days,gint hours,gint minutes,gdouble seconds)1946 g_date_time_add_full (GDateTime *datetime,
1947                       gint       years,
1948                       gint       months,
1949                       gint       days,
1950                       gint       hours,
1951                       gint       minutes,
1952                       gdouble    seconds)
1953 {
1954   gint year, month, day;
1955   gint64 full_time;
1956   GDateTime *new;
1957   gint interval;
1958 
1959   g_return_val_if_fail (datetime != NULL, NULL);
1960   g_date_time_get_ymd (datetime, &year, &month, &day);
1961 
1962   months += years * 12;
1963 
1964   if (months < -120000 || months > 120000)
1965     return NULL;
1966 
1967   if (days < -3660000 || days > 3660000)
1968     return NULL;
1969 
1970   year += months / 12;
1971   month += months % 12;
1972   if (month < 1)
1973     {
1974       month += 12;
1975       year--;
1976     }
1977   else if (month > 12)
1978     {
1979       month -= 12;
1980       year++;
1981     }
1982 
1983   day = MIN (day, days_in_months[GREGORIAN_LEAP (year)][month]);
1984 
1985   /* full_time is now in unix (local) time */
1986   full_time = datetime->usec / USEC_PER_SECOND + SEC_PER_DAY *
1987     (ymd_to_days (year, month, day) + days - UNIX_EPOCH_START);
1988 
1989   interval = g_time_zone_adjust_time (datetime->tz,
1990                                       g_time_zone_is_dst (datetime->tz,
1991                                                           datetime->interval),
1992                                       &full_time);
1993 
1994   /* move to UTC unix time */
1995   full_time -= g_time_zone_get_offset (datetime->tz, interval);
1996 
1997   /* convert back to an instant, add back fractional seconds */
1998   full_time += UNIX_EPOCH_START * SEC_PER_DAY;
1999   full_time = full_time * USEC_PER_SECOND +
2000               datetime->usec % USEC_PER_SECOND;
2001 
2002   /* do the actual addition now */
2003   full_time += (hours * USEC_PER_HOUR) +
2004                (minutes * USEC_PER_MINUTE) +
2005                (gint64) (seconds * USEC_PER_SECOND);
2006 
2007   /* find the new interval */
2008   interval = g_time_zone_find_interval (datetime->tz,
2009                                         G_TIME_TYPE_UNIVERSAL,
2010                                         INSTANT_TO_UNIX (full_time));
2011 
2012   /* convert back into local time */
2013   full_time += USEC_PER_SECOND *
2014                g_time_zone_get_offset (datetime->tz, interval);
2015 
2016   /* split into days and usec of a new datetime */
2017   new = g_date_time_alloc (datetime->tz);
2018   new->interval = interval;
2019   new->days = full_time / USEC_PER_DAY;
2020   new->usec = full_time % USEC_PER_DAY;
2021 
2022   /* XXX validate */
2023 
2024   return new;
2025 }
2026 
2027 /* Compare, difference, hash, equal {{{1 */
2028 /**
2029  * g_date_time_compare:
2030  * @dt1: (type GDateTime) (not nullable): first #GDateTime to compare
2031  * @dt2: (type GDateTime) (not nullable): second #GDateTime to compare
2032  *
2033  * A comparison function for #GDateTimes that is suitable
2034  * as a #GCompareFunc. Both #GDateTimes must be non-%NULL.
2035  *
2036  * Returns: -1, 0 or 1 if @dt1 is less than, equal to or greater
2037  *   than @dt2.
2038  *
2039  * Since: 2.26
2040  */
2041 gint
g_date_time_compare(gconstpointer dt1,gconstpointer dt2)2042 g_date_time_compare (gconstpointer dt1,
2043                      gconstpointer dt2)
2044 {
2045   gint64 difference;
2046 
2047   difference = g_date_time_difference ((GDateTime *) dt1, (GDateTime *) dt2);
2048 
2049   if (difference < 0)
2050     return -1;
2051 
2052   else if (difference > 0)
2053     return 1;
2054 
2055   else
2056     return 0;
2057 }
2058 
2059 /**
2060  * g_date_time_difference:
2061  * @end: a #GDateTime
2062  * @begin: a #GDateTime
2063  *
2064  * Calculates the difference in time between @end and @begin.  The
2065  * #GTimeSpan that is returned is effectively @end - @begin (ie:
2066  * positive if the first parameter is larger).
2067  *
2068  * Returns: the difference between the two #GDateTime, as a time
2069  *   span expressed in microseconds.
2070  *
2071  * Since: 2.26
2072  */
2073 GTimeSpan
g_date_time_difference(GDateTime * end,GDateTime * begin)2074 g_date_time_difference (GDateTime *end,
2075                         GDateTime *begin)
2076 {
2077   g_return_val_if_fail (begin != NULL, 0);
2078   g_return_val_if_fail (end != NULL, 0);
2079 
2080   return g_date_time_to_instant (end) -
2081          g_date_time_to_instant (begin);
2082 }
2083 
2084 /**
2085  * g_date_time_hash:
2086  * @datetime: (type GDateTime) (not nullable): a #GDateTime
2087  *
2088  * Hashes @datetime into a #guint, suitable for use within #GHashTable.
2089  *
2090  * Returns: a #guint containing the hash
2091  *
2092  * Since: 2.26
2093  */
2094 guint
g_date_time_hash(gconstpointer datetime)2095 g_date_time_hash (gconstpointer datetime)
2096 {
2097   g_return_val_if_fail (datetime != NULL, 0);
2098 
2099   return g_date_time_to_instant ((GDateTime *) datetime);
2100 }
2101 
2102 /**
2103  * g_date_time_equal:
2104  * @dt1: (type GDateTime) (not nullable): a #GDateTime
2105  * @dt2: (type GDateTime) (not nullable): a #GDateTime
2106  *
2107  * Checks to see if @dt1 and @dt2 are equal.
2108  *
2109  * Equal here means that they represent the same moment after converting
2110  * them to the same time zone.
2111  *
2112  * Returns: %TRUE if @dt1 and @dt2 are equal
2113  *
2114  * Since: 2.26
2115  */
2116 gboolean
g_date_time_equal(gconstpointer dt1,gconstpointer dt2)2117 g_date_time_equal (gconstpointer dt1,
2118                    gconstpointer dt2)
2119 {
2120   return g_date_time_difference ((GDateTime *) dt1, (GDateTime *) dt2) == 0;
2121 }
2122 
2123 /* Year, Month, Day Getters {{{1 */
2124 /**
2125  * g_date_time_get_ymd:
2126  * @datetime: a #GDateTime.
2127  * @year: (out) (optional): the return location for the gregorian year, or %NULL.
2128  * @month: (out) (optional): the return location for the month of the year, or %NULL.
2129  * @day: (out) (optional): the return location for the day of the month, or %NULL.
2130  *
2131  * Retrieves the Gregorian day, month, and year of a given #GDateTime.
2132  *
2133  * Since: 2.26
2134  **/
2135 void
g_date_time_get_ymd(GDateTime * datetime,gint * year,gint * month,gint * day)2136 g_date_time_get_ymd (GDateTime *datetime,
2137                      gint      *year,
2138                      gint      *month,
2139                      gint      *day)
2140 {
2141   gint the_year;
2142   gint the_month;
2143   gint the_day;
2144   gint remaining_days;
2145   gint y100_cycles;
2146   gint y4_cycles;
2147   gint y1_cycles;
2148   gint preceding;
2149   gboolean leap;
2150 
2151   g_return_if_fail (datetime != NULL);
2152 
2153   remaining_days = datetime->days;
2154 
2155   /*
2156    * We need to convert an offset in days to its year/month/day representation.
2157    * Leap years makes this a little trickier than it should be, so we use
2158    * 400, 100 and 4 years cycles here to get to the correct year.
2159    */
2160 
2161   /* Our days offset starts sets 0001-01-01 as day 1, if it was day 0 our
2162    * math would be simpler, so let's do it */
2163   remaining_days--;
2164 
2165   the_year = (remaining_days / DAYS_IN_400YEARS) * 400 + 1;
2166   remaining_days = remaining_days % DAYS_IN_400YEARS;
2167 
2168   y100_cycles = remaining_days / DAYS_IN_100YEARS;
2169   remaining_days = remaining_days % DAYS_IN_100YEARS;
2170   the_year += y100_cycles * 100;
2171 
2172   y4_cycles = remaining_days / DAYS_IN_4YEARS;
2173   remaining_days = remaining_days % DAYS_IN_4YEARS;
2174   the_year += y4_cycles * 4;
2175 
2176   y1_cycles = remaining_days / 365;
2177   the_year += y1_cycles;
2178   remaining_days = remaining_days % 365;
2179 
2180   if (y1_cycles == 4 || y100_cycles == 4) {
2181     g_assert (remaining_days == 0);
2182 
2183     /* special case that indicates that the date is actually one year before,
2184      * in the 31th of December */
2185     the_year--;
2186     the_month = 12;
2187     the_day = 31;
2188     goto end;
2189   }
2190 
2191   /* now get the month and the day */
2192   leap = y1_cycles == 3 && (y4_cycles != 24 || y100_cycles == 3);
2193 
2194   g_assert (leap == GREGORIAN_LEAP(the_year));
2195 
2196   the_month = (remaining_days + 50) >> 5;
2197   preceding = (days_in_year[0][the_month - 1] + (the_month > 2 && leap));
2198   if (preceding > remaining_days)
2199     {
2200       /* estimate is too large */
2201       the_month -= 1;
2202       preceding -= leap ? days_in_months[1][the_month]
2203                         : days_in_months[0][the_month];
2204     }
2205 
2206   remaining_days -= preceding;
2207   g_assert(0 <= remaining_days);
2208 
2209   the_day = remaining_days + 1;
2210 
2211 end:
2212   if (year)
2213     *year = the_year;
2214   if (month)
2215     *month = the_month;
2216   if (day)
2217     *day = the_day;
2218 }
2219 
2220 /**
2221  * g_date_time_get_year:
2222  * @datetime: A #GDateTime
2223  *
2224  * Retrieves the year represented by @datetime in the Gregorian calendar.
2225  *
2226  * Returns: the year represented by @datetime
2227  *
2228  * Since: 2.26
2229  */
2230 gint
g_date_time_get_year(GDateTime * datetime)2231 g_date_time_get_year (GDateTime *datetime)
2232 {
2233   gint year;
2234 
2235   g_return_val_if_fail (datetime != NULL, 0);
2236 
2237   g_date_time_get_ymd (datetime, &year, NULL, NULL);
2238 
2239   return year;
2240 }
2241 
2242 /**
2243  * g_date_time_get_month:
2244  * @datetime: a #GDateTime
2245  *
2246  * Retrieves the month of the year represented by @datetime in the Gregorian
2247  * calendar.
2248  *
2249  * Returns: the month represented by @datetime
2250  *
2251  * Since: 2.26
2252  */
2253 gint
g_date_time_get_month(GDateTime * datetime)2254 g_date_time_get_month (GDateTime *datetime)
2255 {
2256   gint month;
2257 
2258   g_return_val_if_fail (datetime != NULL, 0);
2259 
2260   g_date_time_get_ymd (datetime, NULL, &month, NULL);
2261 
2262   return month;
2263 }
2264 
2265 /**
2266  * g_date_time_get_day_of_month:
2267  * @datetime: a #GDateTime
2268  *
2269  * Retrieves the day of the month represented by @datetime in the gregorian
2270  * calendar.
2271  *
2272  * Returns: the day of the month
2273  *
2274  * Since: 2.26
2275  */
2276 gint
g_date_time_get_day_of_month(GDateTime * datetime)2277 g_date_time_get_day_of_month (GDateTime *datetime)
2278 {
2279   gint           day_of_year,
2280                  i;
2281   const guint16 *days;
2282   guint16        last = 0;
2283 
2284   g_return_val_if_fail (datetime != NULL, 0);
2285 
2286   days = days_in_year[GREGORIAN_LEAP (g_date_time_get_year (datetime)) ? 1 : 0];
2287   g_date_time_get_week_number (datetime, NULL, NULL, &day_of_year);
2288 
2289   for (i = 1; i <= 12; i++)
2290     {
2291       if (days [i] >= day_of_year)
2292         return day_of_year - last;
2293       last = days [i];
2294     }
2295 
2296   g_warn_if_reached ();
2297   return 0;
2298 }
2299 
2300 /* Week of year / day of week getters {{{1 */
2301 /**
2302  * g_date_time_get_week_numbering_year:
2303  * @datetime: a #GDateTime
2304  *
2305  * Returns the ISO 8601 week-numbering year in which the week containing
2306  * @datetime falls.
2307  *
2308  * This function, taken together with g_date_time_get_week_of_year() and
2309  * g_date_time_get_day_of_week() can be used to determine the full ISO
2310  * week date on which @datetime falls.
2311  *
2312  * This is usually equal to the normal Gregorian year (as returned by
2313  * g_date_time_get_year()), except as detailed below:
2314  *
2315  * For Thursday, the week-numbering year is always equal to the usual
2316  * calendar year.  For other days, the number is such that every day
2317  * within a complete week (Monday to Sunday) is contained within the
2318  * same week-numbering year.
2319  *
2320  * For Monday, Tuesday and Wednesday occurring near the end of the year,
2321  * this may mean that the week-numbering year is one greater than the
2322  * calendar year (so that these days have the same week-numbering year
2323  * as the Thursday occurring early in the next year).
2324  *
2325  * For Friday, Saturday and Sunday occurring near the start of the year,
2326  * this may mean that the week-numbering year is one less than the
2327  * calendar year (so that these days have the same week-numbering year
2328  * as the Thursday occurring late in the previous year).
2329  *
2330  * An equivalent description is that the week-numbering year is equal to
2331  * the calendar year containing the majority of the days in the current
2332  * week (Monday to Sunday).
2333  *
2334  * Note that January 1 0001 in the proleptic Gregorian calendar is a
2335  * Monday, so this function never returns 0.
2336  *
2337  * Returns: the ISO 8601 week-numbering year for @datetime
2338  *
2339  * Since: 2.26
2340  **/
2341 gint
g_date_time_get_week_numbering_year(GDateTime * datetime)2342 g_date_time_get_week_numbering_year (GDateTime *datetime)
2343 {
2344   gint year, month, day, weekday;
2345 
2346   g_date_time_get_ymd (datetime, &year, &month, &day);
2347   weekday = g_date_time_get_day_of_week (datetime);
2348 
2349   /* January 1, 2, 3 might be in the previous year if they occur after
2350    * Thursday.
2351    *
2352    *   Jan 1:  Friday, Saturday, Sunday    =>  day 1:  weekday 5, 6, 7
2353    *   Jan 2:  Saturday, Sunday            =>  day 2:  weekday 6, 7
2354    *   Jan 3:  Sunday                      =>  day 3:  weekday 7
2355    *
2356    * So we have a special case if (day - weekday) <= -4
2357    */
2358   if (month == 1 && (day - weekday) <= -4)
2359     return year - 1;
2360 
2361   /* December 29, 30, 31 might be in the next year if they occur before
2362    * Thursday.
2363    *
2364    *   Dec 31: Monday, Tuesday, Wednesday  =>  day 31: weekday 1, 2, 3
2365    *   Dec 30: Monday, Tuesday             =>  day 30: weekday 1, 2
2366    *   Dec 29: Monday                      =>  day 29: weekday 1
2367    *
2368    * So we have a special case if (day - weekday) >= 28
2369    */
2370   else if (month == 12 && (day - weekday) >= 28)
2371     return year + 1;
2372 
2373   else
2374     return year;
2375 }
2376 
2377 /**
2378  * g_date_time_get_week_of_year:
2379  * @datetime: a #GDateTime
2380  *
2381  * Returns the ISO 8601 week number for the week containing @datetime.
2382  * The ISO 8601 week number is the same for every day of the week (from
2383  * Moday through Sunday).  That can produce some unusual results
2384  * (described below).
2385  *
2386  * The first week of the year is week 1.  This is the week that contains
2387  * the first Thursday of the year.  Equivalently, this is the first week
2388  * that has more than 4 of its days falling within the calendar year.
2389  *
2390  * The value 0 is never returned by this function.  Days contained
2391  * within a year but occurring before the first ISO 8601 week of that
2392  * year are considered as being contained in the last week of the
2393  * previous year.  Similarly, the final days of a calendar year may be
2394  * considered as being part of the first ISO 8601 week of the next year
2395  * if 4 or more days of that week are contained within the new year.
2396  *
2397  * Returns: the ISO 8601 week number for @datetime.
2398  *
2399  * Since: 2.26
2400  */
2401 gint
g_date_time_get_week_of_year(GDateTime * datetime)2402 g_date_time_get_week_of_year (GDateTime *datetime)
2403 {
2404   gint weeknum;
2405 
2406   g_return_val_if_fail (datetime != NULL, 0);
2407 
2408   g_date_time_get_week_number (datetime, &weeknum, NULL, NULL);
2409 
2410   return weeknum;
2411 }
2412 
2413 /**
2414  * g_date_time_get_day_of_week:
2415  * @datetime: a #GDateTime
2416  *
2417  * Retrieves the ISO 8601 day of the week on which @datetime falls (1 is
2418  * Monday, 2 is Tuesday... 7 is Sunday).
2419  *
2420  * Returns: the day of the week
2421  *
2422  * Since: 2.26
2423  */
2424 gint
g_date_time_get_day_of_week(GDateTime * datetime)2425 g_date_time_get_day_of_week (GDateTime *datetime)
2426 {
2427   g_return_val_if_fail (datetime != NULL, 0);
2428 
2429   return (datetime->days - 1) % 7 + 1;
2430 }
2431 
2432 /* Day of year getter {{{1 */
2433 /**
2434  * g_date_time_get_day_of_year:
2435  * @datetime: a #GDateTime
2436  *
2437  * Retrieves the day of the year represented by @datetime in the Gregorian
2438  * calendar.
2439  *
2440  * Returns: the day of the year
2441  *
2442  * Since: 2.26
2443  */
2444 gint
g_date_time_get_day_of_year(GDateTime * datetime)2445 g_date_time_get_day_of_year (GDateTime *datetime)
2446 {
2447   gint doy = 0;
2448 
2449   g_return_val_if_fail (datetime != NULL, 0);
2450 
2451   g_date_time_get_week_number (datetime, NULL, NULL, &doy);
2452   return doy;
2453 }
2454 
2455 /* Time component getters {{{1 */
2456 
2457 /**
2458  * g_date_time_get_hour:
2459  * @datetime: a #GDateTime
2460  *
2461  * Retrieves the hour of the day represented by @datetime
2462  *
2463  * Returns: the hour of the day
2464  *
2465  * Since: 2.26
2466  */
2467 gint
g_date_time_get_hour(GDateTime * datetime)2468 g_date_time_get_hour (GDateTime *datetime)
2469 {
2470   g_return_val_if_fail (datetime != NULL, 0);
2471 
2472   return (datetime->usec / USEC_PER_HOUR);
2473 }
2474 
2475 /**
2476  * g_date_time_get_minute:
2477  * @datetime: a #GDateTime
2478  *
2479  * Retrieves the minute of the hour represented by @datetime
2480  *
2481  * Returns: the minute of the hour
2482  *
2483  * Since: 2.26
2484  */
2485 gint
g_date_time_get_minute(GDateTime * datetime)2486 g_date_time_get_minute (GDateTime *datetime)
2487 {
2488   g_return_val_if_fail (datetime != NULL, 0);
2489 
2490   return (datetime->usec % USEC_PER_HOUR) / USEC_PER_MINUTE;
2491 }
2492 
2493 /**
2494  * g_date_time_get_second:
2495  * @datetime: a #GDateTime
2496  *
2497  * Retrieves the second of the minute represented by @datetime
2498  *
2499  * Returns: the second represented by @datetime
2500  *
2501  * Since: 2.26
2502  */
2503 gint
g_date_time_get_second(GDateTime * datetime)2504 g_date_time_get_second (GDateTime *datetime)
2505 {
2506   g_return_val_if_fail (datetime != NULL, 0);
2507 
2508   return (datetime->usec % USEC_PER_MINUTE) / USEC_PER_SECOND;
2509 }
2510 
2511 /**
2512  * g_date_time_get_microsecond:
2513  * @datetime: a #GDateTime
2514  *
2515  * Retrieves the microsecond of the date represented by @datetime
2516  *
2517  * Returns: the microsecond of the second
2518  *
2519  * Since: 2.26
2520  */
2521 gint
g_date_time_get_microsecond(GDateTime * datetime)2522 g_date_time_get_microsecond (GDateTime *datetime)
2523 {
2524   g_return_val_if_fail (datetime != NULL, 0);
2525 
2526   return (datetime->usec % USEC_PER_SECOND);
2527 }
2528 
2529 /**
2530  * g_date_time_get_seconds:
2531  * @datetime: a #GDateTime
2532  *
2533  * Retrieves the number of seconds since the start of the last minute,
2534  * including the fractional part.
2535  *
2536  * Returns: the number of seconds
2537  *
2538  * Since: 2.26
2539  **/
2540 gdouble
g_date_time_get_seconds(GDateTime * datetime)2541 g_date_time_get_seconds (GDateTime *datetime)
2542 {
2543   g_return_val_if_fail (datetime != NULL, 0);
2544 
2545   return (datetime->usec % USEC_PER_MINUTE) / 1000000.0;
2546 }
2547 
2548 /* Exporters {{{1 */
2549 /**
2550  * g_date_time_to_unix:
2551  * @datetime: a #GDateTime
2552  *
2553  * Gives the Unix time corresponding to @datetime, rounding down to the
2554  * nearest second.
2555  *
2556  * Unix time is the number of seconds that have elapsed since 1970-01-01
2557  * 00:00:00 UTC, regardless of the time zone associated with @datetime.
2558  *
2559  * Returns: the Unix time corresponding to @datetime
2560  *
2561  * Since: 2.26
2562  **/
2563 gint64
g_date_time_to_unix(GDateTime * datetime)2564 g_date_time_to_unix (GDateTime *datetime)
2565 {
2566   g_return_val_if_fail (datetime != NULL, 0);
2567 
2568   return INSTANT_TO_UNIX (g_date_time_to_instant (datetime));
2569 }
2570 
2571 /**
2572  * g_date_time_to_timeval:
2573  * @datetime: a #GDateTime
2574  * @tv: a #GTimeVal to modify
2575  *
2576  * Stores the instant in time that @datetime represents into @tv.
2577  *
2578  * The time contained in a #GTimeVal is always stored in the form of
2579  * seconds elapsed since 1970-01-01 00:00:00 UTC, regardless of the time
2580  * zone associated with @datetime.
2581  *
2582  * On systems where 'long' is 32bit (ie: all 32bit systems and all
2583  * Windows systems), a #GTimeVal is incapable of storing the entire
2584  * range of values that #GDateTime is capable of expressing.  On those
2585  * systems, this function returns %FALSE to indicate that the time is
2586  * out of range.
2587  *
2588  * On systems where 'long' is 64bit, this function never fails.
2589  *
2590  * Returns: %TRUE if successful, else %FALSE
2591  *
2592  * Since: 2.26
2593  * Deprecated: 2.62: #GTimeVal is not year-2038-safe. Use
2594  *    g_date_time_to_unix() instead.
2595  **/
2596 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
2597 gboolean
g_date_time_to_timeval(GDateTime * datetime,GTimeVal * tv)2598 g_date_time_to_timeval (GDateTime *datetime,
2599                         GTimeVal  *tv)
2600 {
2601   g_return_val_if_fail (datetime != NULL, FALSE);
2602 
2603   tv->tv_sec = INSTANT_TO_UNIX (g_date_time_to_instant (datetime));
2604   tv->tv_usec = datetime->usec % USEC_PER_SECOND;
2605 
2606   return TRUE;
2607 }
2608 G_GNUC_END_IGNORE_DEPRECATIONS
2609 
2610 /* Timezone queries {{{1 */
2611 /**
2612  * g_date_time_get_utc_offset:
2613  * @datetime: a #GDateTime
2614  *
2615  * Determines the offset to UTC in effect at the time and in the time
2616  * zone of @datetime.
2617  *
2618  * The offset is the number of microseconds that you add to UTC time to
2619  * arrive at local time for the time zone (ie: negative numbers for time
2620  * zones west of GMT, positive numbers for east).
2621  *
2622  * If @datetime represents UTC time, then the offset is always zero.
2623  *
2624  * Returns: the number of microseconds that should be added to UTC to
2625  *          get the local time
2626  *
2627  * Since: 2.26
2628  **/
2629 GTimeSpan
g_date_time_get_utc_offset(GDateTime * datetime)2630 g_date_time_get_utc_offset (GDateTime *datetime)
2631 {
2632   gint offset;
2633 
2634   g_return_val_if_fail (datetime != NULL, 0);
2635 
2636   offset = g_time_zone_get_offset (datetime->tz, datetime->interval);
2637 
2638   return (gint64) offset * USEC_PER_SECOND;
2639 }
2640 
2641 /**
2642  * g_date_time_get_timezone:
2643  * @datetime: a #GDateTime
2644  *
2645  * Get the time zone for this @datetime.
2646  *
2647  * Returns: (transfer none): the time zone
2648  * Since: 2.58
2649  */
2650 GTimeZone *
g_date_time_get_timezone(GDateTime * datetime)2651 g_date_time_get_timezone (GDateTime *datetime)
2652 {
2653   g_return_val_if_fail (datetime != NULL, NULL);
2654 
2655   g_assert (datetime->tz != NULL);
2656   return datetime->tz;
2657 }
2658 
2659 /**
2660  * g_date_time_get_timezone_abbreviation:
2661  * @datetime: a #GDateTime
2662  *
2663  * Determines the time zone abbreviation to be used at the time and in
2664  * the time zone of @datetime.
2665  *
2666  * For example, in Toronto this is currently "EST" during the winter
2667  * months and "EDT" during the summer months when daylight savings
2668  * time is in effect.
2669  *
2670  * Returns: (transfer none): the time zone abbreviation. The returned
2671  *          string is owned by the #GDateTime and it should not be
2672  *          modified or freed
2673  *
2674  * Since: 2.26
2675  **/
2676 const gchar *
g_date_time_get_timezone_abbreviation(GDateTime * datetime)2677 g_date_time_get_timezone_abbreviation (GDateTime *datetime)
2678 {
2679   g_return_val_if_fail (datetime != NULL, NULL);
2680 
2681   return g_time_zone_get_abbreviation (datetime->tz, datetime->interval);
2682 }
2683 
2684 /**
2685  * g_date_time_is_daylight_savings:
2686  * @datetime: a #GDateTime
2687  *
2688  * Determines if daylight savings time is in effect at the time and in
2689  * the time zone of @datetime.
2690  *
2691  * Returns: %TRUE if daylight savings time is in effect
2692  *
2693  * Since: 2.26
2694  **/
2695 gboolean
g_date_time_is_daylight_savings(GDateTime * datetime)2696 g_date_time_is_daylight_savings (GDateTime *datetime)
2697 {
2698   g_return_val_if_fail (datetime != NULL, FALSE);
2699 
2700   return g_time_zone_is_dst (datetime->tz, datetime->interval);
2701 }
2702 
2703 /* Timezone convert {{{1 */
2704 /**
2705  * g_date_time_to_timezone:
2706  * @datetime: a #GDateTime
2707  * @tz: the new #GTimeZone
2708  *
2709  * Create a new #GDateTime corresponding to the same instant in time as
2710  * @datetime, but in the time zone @tz.
2711  *
2712  * This call can fail in the case that the time goes out of bounds.  For
2713  * example, converting 0001-01-01 00:00:00 UTC to a time zone west of
2714  * Greenwich will fail (due to the year 0 being out of range).
2715  *
2716  * Returns: (transfer full) (nullable): the newly created #GDateTime which
2717  *   should be freed with g_date_time_unref(), or %NULL
2718  *
2719  * Since: 2.26
2720  **/
2721 GDateTime *
g_date_time_to_timezone(GDateTime * datetime,GTimeZone * tz)2722 g_date_time_to_timezone (GDateTime *datetime,
2723                          GTimeZone *tz)
2724 {
2725   g_return_val_if_fail (datetime != NULL, NULL);
2726   g_return_val_if_fail (tz != NULL, NULL);
2727 
2728   return g_date_time_from_instant (tz, g_date_time_to_instant (datetime));
2729 }
2730 
2731 /**
2732  * g_date_time_to_local:
2733  * @datetime: a #GDateTime
2734  *
2735  * Creates a new #GDateTime corresponding to the same instant in time as
2736  * @datetime, but in the local time zone.
2737  *
2738  * This call is equivalent to calling g_date_time_to_timezone() with the
2739  * time zone returned by g_time_zone_new_local().
2740  *
2741  * Returns: (transfer full) (nullable): the newly created #GDateTime which
2742  *   should be freed with g_date_time_unref(), or %NULL
2743  *
2744  * Since: 2.26
2745  **/
2746 GDateTime *
g_date_time_to_local(GDateTime * datetime)2747 g_date_time_to_local (GDateTime *datetime)
2748 {
2749   GDateTime *new;
2750   GTimeZone *local;
2751 
2752   local = g_time_zone_new_local ();
2753   new = g_date_time_to_timezone (datetime, local);
2754   g_time_zone_unref (local);
2755 
2756   return new;
2757 }
2758 
2759 /**
2760  * g_date_time_to_utc:
2761  * @datetime: a #GDateTime
2762  *
2763  * Creates a new #GDateTime corresponding to the same instant in time as
2764  * @datetime, but in UTC.
2765  *
2766  * This call is equivalent to calling g_date_time_to_timezone() with the
2767  * time zone returned by g_time_zone_new_utc().
2768  *
2769  * Returns: (transfer full) (nullable): the newly created #GDateTime which
2770  *   should be freed with g_date_time_unref(), or %NULL
2771  *
2772  * Since: 2.26
2773  **/
2774 GDateTime *
g_date_time_to_utc(GDateTime * datetime)2775 g_date_time_to_utc (GDateTime *datetime)
2776 {
2777   GDateTime *new;
2778   GTimeZone *utc;
2779 
2780   utc = g_time_zone_new_utc ();
2781   new = g_date_time_to_timezone (datetime, utc);
2782   g_time_zone_unref (utc);
2783 
2784   return new;
2785 }
2786 
2787 /* Format {{{1 */
2788 
2789 static gboolean
format_z(GString * outstr,gint offset,guint colons)2790 format_z (GString *outstr,
2791           gint     offset,
2792           guint    colons)
2793 {
2794   gint hours;
2795   gint minutes;
2796   gint seconds;
2797   gchar sign = offset >= 0 ? '+' : '-';
2798 
2799   offset = ABS (offset);
2800   hours = offset / 3600;
2801   minutes = offset / 60 % 60;
2802   seconds = offset % 60;
2803 
2804   switch (colons)
2805     {
2806     case 0:
2807       g_string_append_printf (outstr, "%c%02d%02d",
2808                               sign,
2809                               hours,
2810                               minutes);
2811       break;
2812 
2813     case 1:
2814       g_string_append_printf (outstr, "%c%02d:%02d",
2815                               sign,
2816                               hours,
2817                               minutes);
2818       break;
2819 
2820     case 2:
2821       g_string_append_printf (outstr, "%c%02d:%02d:%02d",
2822                               sign,
2823                               hours,
2824                               minutes,
2825                               seconds);
2826       break;
2827 
2828     case 3:
2829       g_string_append_printf (outstr, "%c%02d", sign, hours);
2830 
2831       if (minutes != 0 || seconds != 0)
2832         {
2833           g_string_append_printf (outstr, ":%02d", minutes);
2834 
2835           if (seconds != 0)
2836             g_string_append_printf (outstr, ":%02d", seconds);
2837         }
2838       break;
2839 
2840     default:
2841       return FALSE;
2842     }
2843 
2844   return TRUE;
2845 }
2846 
2847 #ifdef HAVE_LANGINFO_OUTDIGIT
2848 /* Initializes the array with UTF-8 encoded alternate digits suitable for use
2849  * in current locale. Returns NULL when current locale does not use alternate
2850  * digits or there was an error converting them to UTF-8.
2851  */
2852 static const gchar * const *
initialize_alt_digits(void)2853 initialize_alt_digits (void)
2854 {
2855   guint i;
2856   gsize digit_len;
2857   gchar *digit;
2858   const gchar *locale_digit;
2859 #define N_DIGITS 10
2860 #define MAX_UTF8_ENCODING_LEN 4
2861   static gchar buffer[N_DIGITS * (MAX_UTF8_ENCODING_LEN + 1 /* null separator */)];
2862 #undef N_DIGITS
2863 #undef MAX_UTF8_ENCODING_LEN
2864   gchar *buffer_end = buffer;
2865   static const gchar *alt_digits[10];
2866 
2867   for (i = 0; i != 10; ++i)
2868     {
2869       locale_digit = nl_langinfo (_NL_CTYPE_OUTDIGIT0_MB + i);
2870 
2871       if (g_strcmp0 (locale_digit, "") == 0)
2872         return NULL;
2873 
2874       digit = g_locale_to_utf8 (locale_digit, -1, NULL, &digit_len, NULL);
2875       if (digit == NULL)
2876         return NULL;
2877 
2878       g_assert (digit_len < (gsize) (buffer + sizeof (buffer) - buffer_end));
2879 
2880       alt_digits[i] = buffer_end;
2881       buffer_end = g_stpcpy (buffer_end, digit);
2882       /* skip trailing null byte */
2883       buffer_end += 1;
2884 
2885       g_free (digit);
2886     }
2887 
2888   return alt_digits;
2889 }
2890 #endif /* HAVE_LANGINFO_OUTDIGIT */
2891 
2892 static void
format_number(GString * str,gboolean use_alt_digits,const gchar * pad,gint width,guint32 number)2893 format_number (GString     *str,
2894                gboolean     use_alt_digits,
2895                const gchar *pad,
2896                gint         width,
2897                guint32      number)
2898 {
2899   const gchar *ascii_digits[10] = {
2900     "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
2901   };
2902   const gchar * const *digits = ascii_digits;
2903   const gchar *tmp[10];
2904   gint i = 0;
2905 
2906   g_return_if_fail (width <= 10);
2907 
2908 #ifdef HAVE_LANGINFO_OUTDIGIT
2909   if (use_alt_digits)
2910     {
2911       static const gchar * const *alt_digits = NULL;
2912       static gsize initialised;
2913 
2914       if G_UNLIKELY (g_once_init_enter (&initialised))
2915         {
2916           alt_digits = initialize_alt_digits ();
2917 
2918           if (alt_digits == NULL)
2919             alt_digits = ascii_digits;
2920 
2921           g_once_init_leave (&initialised, TRUE);
2922         }
2923 
2924       digits = alt_digits;
2925     }
2926 #endif /* HAVE_LANGINFO_OUTDIGIT */
2927 
2928   do
2929     {
2930       tmp[i++] = digits[number % 10];
2931       number /= 10;
2932     }
2933   while (number);
2934 
2935   while (pad && i < width)
2936     tmp[i++] = *pad == '0' ? digits[0] : pad;
2937 
2938   /* should really be impossible */
2939   g_assert (i <= 10);
2940 
2941   while (i)
2942     g_string_append (str, tmp[--i]);
2943 }
2944 
2945 static gboolean
format_ampm(GDateTime * datetime,GString * outstr,gboolean locale_is_utf8,gboolean uppercase)2946 format_ampm (GDateTime *datetime,
2947              GString   *outstr,
2948              gboolean   locale_is_utf8,
2949              gboolean   uppercase)
2950 {
2951   const gchar *ampm;
2952   gchar       *tmp = NULL, *ampm_dup;
2953 
2954   ampm = GET_AMPM (datetime);
2955 
2956   if (!ampm || ampm[0] == '\0')
2957     ampm = get_fallback_ampm (g_date_time_get_hour (datetime));
2958 
2959   if (!locale_is_utf8 && GET_AMPM_IS_LOCALE)
2960     {
2961       /* This assumes that locale encoding can't have embedded NULs */
2962       ampm = tmp = g_locale_to_utf8 (ampm, -1, NULL, NULL, NULL);
2963       if (tmp == NULL)
2964         return FALSE;
2965     }
2966   if (uppercase)
2967     ampm_dup = g_utf8_strup (ampm, -1);
2968   else
2969     ampm_dup = g_utf8_strdown (ampm, -1);
2970   g_free (tmp);
2971 
2972   g_string_append (outstr, ampm_dup);
2973   g_free (ampm_dup);
2974 
2975   return TRUE;
2976 }
2977 
2978 static gboolean g_date_time_format_utf8 (GDateTime   *datetime,
2979 					 const gchar *format,
2980 					 GString     *outstr,
2981 					 gboolean     locale_is_utf8);
2982 
2983 /* g_date_time_format() subroutine that takes a locale-encoded format
2984  * string and produces a UTF-8 encoded date/time string.
2985  */
2986 static gboolean
g_date_time_format_locale(GDateTime * datetime,const gchar * locale_format,GString * outstr,gboolean locale_is_utf8)2987 g_date_time_format_locale (GDateTime   *datetime,
2988 			   const gchar *locale_format,
2989 			   GString     *outstr,
2990 			   gboolean     locale_is_utf8)
2991 {
2992   gchar *utf8_format;
2993   gboolean success;
2994 
2995   if (locale_is_utf8)
2996     return g_date_time_format_utf8 (datetime, locale_format, outstr, locale_is_utf8);
2997 
2998   utf8_format = g_locale_to_utf8 (locale_format, -1, NULL, NULL, NULL);
2999   if (utf8_format == NULL)
3000     return FALSE;
3001 
3002   success = g_date_time_format_utf8 (datetime, utf8_format, outstr,
3003                                      locale_is_utf8);
3004   g_free (utf8_format);
3005   return success;
3006 }
3007 
3008 static inline gboolean
string_append(GString * string,const gchar * s,gboolean s_is_utf8)3009 string_append (GString     *string,
3010                const gchar *s,
3011                gboolean     s_is_utf8)
3012 {
3013   gchar *utf8;
3014   gsize  utf8_len;
3015 
3016   if (s_is_utf8)
3017     {
3018       g_string_append (string, s);
3019     }
3020   else
3021     {
3022       utf8 = g_locale_to_utf8 (s, -1, NULL, &utf8_len, NULL);
3023       if (utf8 == NULL)
3024         return FALSE;
3025       g_string_append_len (string, utf8, utf8_len);
3026       g_free (utf8);
3027     }
3028 
3029   return TRUE;
3030 }
3031 
3032 /* g_date_time_format() subroutine that takes a UTF-8 encoded format
3033  * string and produces a UTF-8 encoded date/time string.
3034  */
3035 static gboolean
g_date_time_format_utf8(GDateTime * datetime,const gchar * utf8_format,GString * outstr,gboolean locale_is_utf8)3036 g_date_time_format_utf8 (GDateTime   *datetime,
3037 			 const gchar *utf8_format,
3038 			 GString     *outstr,
3039 			 gboolean     locale_is_utf8)
3040 {
3041   guint     len;
3042   guint     colons;
3043   gunichar  c;
3044   gboolean  alt_digits = FALSE;
3045   gboolean  pad_set = FALSE;
3046   gboolean  name_is_utf8;
3047   const gchar *pad = "";
3048   const gchar *name;
3049   const gchar *tz;
3050 
3051   while (*utf8_format)
3052     {
3053       len = strcspn (utf8_format, "%");
3054       if (len)
3055         g_string_append_len (outstr, utf8_format, len);
3056 
3057       utf8_format += len;
3058       if (!*utf8_format)
3059 	break;
3060 
3061       g_assert (*utf8_format == '%');
3062       utf8_format++;
3063       if (!*utf8_format)
3064 	break;
3065 
3066       colons = 0;
3067       alt_digits = FALSE;
3068       pad_set = FALSE;
3069 
3070     next_mod:
3071       c = g_utf8_get_char (utf8_format);
3072       utf8_format = g_utf8_next_char (utf8_format);
3073       switch (c)
3074 	{
3075 	case 'a':
3076 	  name = WEEKDAY_ABBR (datetime);
3077           if (g_strcmp0 (name, "") == 0)
3078             return FALSE;
3079 
3080           name_is_utf8 = locale_is_utf8 || !WEEKDAY_ABBR_IS_LOCALE;
3081 
3082           if (!string_append (outstr, name, name_is_utf8))
3083             return FALSE;
3084 
3085 	  break;
3086 	case 'A':
3087 	  name = WEEKDAY_FULL (datetime);
3088           if (g_strcmp0 (name, "") == 0)
3089             return FALSE;
3090 
3091           name_is_utf8 = locale_is_utf8 || !WEEKDAY_FULL_IS_LOCALE;
3092 
3093           if (!string_append (outstr, name, name_is_utf8))
3094             return FALSE;
3095 
3096 	  break;
3097 	case 'b':
3098 	  name = alt_digits ? MONTH_ABBR_STANDALONE (datetime)
3099 			    : MONTH_ABBR_WITH_DAY (datetime);
3100           if (g_strcmp0 (name, "") == 0)
3101             return FALSE;
3102 
3103           name_is_utf8 = locale_is_utf8 ||
3104             ((alt_digits && !MONTH_ABBR_STANDALONE_IS_LOCALE) ||
3105              (!alt_digits && !MONTH_ABBR_WITH_DAY_IS_LOCALE));
3106 
3107           if (!string_append (outstr, name, name_is_utf8))
3108             return FALSE;
3109 
3110 	  break;
3111 	case 'B':
3112 	  name = alt_digits ? MONTH_FULL_STANDALONE (datetime)
3113 			    : MONTH_FULL_WITH_DAY (datetime);
3114           if (g_strcmp0 (name, "") == 0)
3115             return FALSE;
3116 
3117           name_is_utf8 = locale_is_utf8 ||
3118             ((alt_digits && !MONTH_FULL_STANDALONE_IS_LOCALE) ||
3119              (!alt_digits && !MONTH_FULL_WITH_DAY_IS_LOCALE));
3120 
3121           if (!string_append (outstr, name, name_is_utf8))
3122               return FALSE;
3123 
3124 	  break;
3125 	case 'c':
3126 	  {
3127             if (g_strcmp0 (PREFERRED_DATE_TIME_FMT, "") == 0)
3128               return FALSE;
3129             if (!g_date_time_format_locale (datetime, PREFERRED_DATE_TIME_FMT,
3130                                             outstr, locale_is_utf8))
3131               return FALSE;
3132 	  }
3133 	  break;
3134 	case 'C':
3135 	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3136 			 g_date_time_get_year (datetime) / 100);
3137 	  break;
3138 	case 'd':
3139 	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3140 			 g_date_time_get_day_of_month (datetime));
3141 	  break;
3142 	case 'e':
3143 	  format_number (outstr, alt_digits, pad_set ? pad : " ", 2,
3144 			 g_date_time_get_day_of_month (datetime));
3145 	  break;
3146 	case 'f':
3147 	  g_string_append_printf (outstr, "%06" G_GUINT64_FORMAT,
3148 			datetime->usec % G_TIME_SPAN_SECOND);
3149 	  break;
3150 	case 'F':
3151 	  g_string_append_printf (outstr, "%d-%02d-%02d",
3152 				  g_date_time_get_year (datetime),
3153 				  g_date_time_get_month (datetime),
3154 				  g_date_time_get_day_of_month (datetime));
3155 	  break;
3156 	case 'g':
3157 	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3158 			 g_date_time_get_week_numbering_year (datetime) % 100);
3159 	  break;
3160 	case 'G':
3161 	  format_number (outstr, alt_digits, pad_set ? pad : 0, 0,
3162 			 g_date_time_get_week_numbering_year (datetime));
3163 	  break;
3164 	case 'h':
3165 	  name = alt_digits ? MONTH_ABBR_STANDALONE (datetime)
3166 			    : MONTH_ABBR_WITH_DAY (datetime);
3167           if (g_strcmp0 (name, "") == 0)
3168             return FALSE;
3169 
3170           name_is_utf8 = locale_is_utf8 ||
3171             ((alt_digits && !MONTH_ABBR_STANDALONE_IS_LOCALE) ||
3172              (!alt_digits && !MONTH_ABBR_WITH_DAY_IS_LOCALE));
3173 
3174           if (!string_append (outstr, name, name_is_utf8))
3175             return FALSE;
3176 
3177 	  break;
3178 	case 'H':
3179 	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3180 			 g_date_time_get_hour (datetime));
3181 	  break;
3182 	case 'I':
3183 	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3184 			 (g_date_time_get_hour (datetime) + 11) % 12 + 1);
3185 	  break;
3186 	case 'j':
3187 	  format_number (outstr, alt_digits, pad_set ? pad : "0", 3,
3188 			 g_date_time_get_day_of_year (datetime));
3189 	  break;
3190 	case 'k':
3191 	  format_number (outstr, alt_digits, pad_set ? pad : " ", 2,
3192 			 g_date_time_get_hour (datetime));
3193 	  break;
3194 	case 'l':
3195 	  format_number (outstr, alt_digits, pad_set ? pad : " ", 2,
3196 			 (g_date_time_get_hour (datetime) + 11) % 12 + 1);
3197 	  break;
3198 	case 'm':
3199 	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3200 			 g_date_time_get_month (datetime));
3201 	  break;
3202 	case 'M':
3203 	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3204 			 g_date_time_get_minute (datetime));
3205 	  break;
3206 	case 'n':
3207 	  g_string_append_c (outstr, '\n');
3208 	  break;
3209 	case 'O':
3210 	  alt_digits = TRUE;
3211 	  goto next_mod;
3212 	case 'p':
3213           if (!format_ampm (datetime, outstr, locale_is_utf8, TRUE))
3214             return FALSE;
3215           break;
3216 	case 'P':
3217           if (!format_ampm (datetime, outstr, locale_is_utf8, FALSE))
3218             return FALSE;
3219 	  break;
3220 	case 'r':
3221 	  {
3222             if (g_strcmp0 (PREFERRED_12HR_TIME_FMT, "") == 0)
3223               return FALSE;
3224 	    if (!g_date_time_format_locale (datetime, PREFERRED_12HR_TIME_FMT,
3225 					    outstr, locale_is_utf8))
3226 	      return FALSE;
3227 	  }
3228 	  break;
3229 	case 'R':
3230 	  g_string_append_printf (outstr, "%02d:%02d",
3231 				  g_date_time_get_hour (datetime),
3232 				  g_date_time_get_minute (datetime));
3233 	  break;
3234 	case 's':
3235 	  g_string_append_printf (outstr, "%" G_GINT64_FORMAT, g_date_time_to_unix (datetime));
3236 	  break;
3237 	case 'S':
3238 	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3239 			 g_date_time_get_second (datetime));
3240 	  break;
3241 	case 't':
3242 	  g_string_append_c (outstr, '\t');
3243 	  break;
3244 	case 'T':
3245 	  g_string_append_printf (outstr, "%02d:%02d:%02d",
3246 				  g_date_time_get_hour (datetime),
3247 				  g_date_time_get_minute (datetime),
3248 				  g_date_time_get_second (datetime));
3249 	  break;
3250 	case 'u':
3251 	  format_number (outstr, alt_digits, 0, 0,
3252 			 g_date_time_get_day_of_week (datetime));
3253 	  break;
3254 	case 'V':
3255 	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3256 			 g_date_time_get_week_of_year (datetime));
3257 	  break;
3258 	case 'w':
3259 	  format_number (outstr, alt_digits, 0, 0,
3260 			 g_date_time_get_day_of_week (datetime) % 7);
3261 	  break;
3262 	case 'x':
3263 	  {
3264             if (g_strcmp0 (PREFERRED_DATE_FMT, "") == 0)
3265               return FALSE;
3266 	    if (!g_date_time_format_locale (datetime, PREFERRED_DATE_FMT,
3267 					    outstr, locale_is_utf8))
3268 	      return FALSE;
3269 	  }
3270 	  break;
3271 	case 'X':
3272 	  {
3273             if (g_strcmp0 (PREFERRED_TIME_FMT, "") == 0)
3274               return FALSE;
3275 	    if (!g_date_time_format_locale (datetime, PREFERRED_TIME_FMT,
3276 					    outstr, locale_is_utf8))
3277 	      return FALSE;
3278 	  }
3279 	  break;
3280 	case 'y':
3281 	  format_number (outstr, alt_digits, pad_set ? pad : "0", 2,
3282 			 g_date_time_get_year (datetime) % 100);
3283 	  break;
3284 	case 'Y':
3285 	  format_number (outstr, alt_digits, 0, 0,
3286 			 g_date_time_get_year (datetime));
3287 	  break;
3288 	case 'z':
3289 	  {
3290 	    gint64 offset;
3291 	    offset = g_date_time_get_utc_offset (datetime) / USEC_PER_SECOND;
3292 	    if (!format_z (outstr, (int) offset, colons))
3293 	      return FALSE;
3294 	  }
3295 	  break;
3296 	case 'Z':
3297 	  tz = g_date_time_get_timezone_abbreviation (datetime);
3298           g_string_append (outstr, tz);
3299 	  break;
3300 	case '%':
3301 	  g_string_append_c (outstr, '%');
3302 	  break;
3303 	case '-':
3304 	  pad_set = TRUE;
3305 	  pad = "";
3306 	  goto next_mod;
3307 	case '_':
3308 	  pad_set = TRUE;
3309 	  pad = " ";
3310 	  goto next_mod;
3311 	case '0':
3312 	  pad_set = TRUE;
3313 	  pad = "0";
3314 	  goto next_mod;
3315 	case ':':
3316 	  /* Colons are only allowed before 'z' */
3317 	  if (*utf8_format && *utf8_format != 'z' && *utf8_format != ':')
3318 	    return FALSE;
3319 	  colons++;
3320 	  goto next_mod;
3321 	default:
3322 	  return FALSE;
3323 	}
3324     }
3325 
3326   return TRUE;
3327 }
3328 
3329 /**
3330  * g_date_time_format:
3331  * @datetime: A #GDateTime
3332  * @format: a valid UTF-8 string, containing the format for the
3333  *          #GDateTime
3334  *
3335  * Creates a newly allocated string representing the requested @format.
3336  *
3337  * The format strings understood by this function are a subset of the
3338  * strftime() format language as specified by C99.  The \%D, \%U and \%W
3339  * conversions are not supported, nor is the 'E' modifier.  The GNU
3340  * extensions \%k, \%l, \%s and \%P are supported, however, as are the
3341  * '0', '_' and '-' modifiers. The Python extension \%f is also supported.
3342  *
3343  * In contrast to strftime(), this function always produces a UTF-8
3344  * string, regardless of the current locale.  Note that the rendering of
3345  * many formats is locale-dependent and may not match the strftime()
3346  * output exactly.
3347  *
3348  * The following format specifiers are supported:
3349  *
3350  * - \%a: the abbreviated weekday name according to the current locale
3351  * - \%A: the full weekday name according to the current locale
3352  * - \%b: the abbreviated month name according to the current locale
3353  * - \%B: the full month name according to the current locale
3354  * - \%c: the preferred date and time representation for the current locale
3355  * - \%C: the century number (year/100) as a 2-digit integer (00-99)
3356  * - \%d: the day of the month as a decimal number (range 01 to 31)
3357  * - \%e: the day of the month as a decimal number (range  1 to 31)
3358  * - \%F: equivalent to `%Y-%m-%d` (the ISO 8601 date format)
3359  * - \%g: the last two digits of the ISO 8601 week-based year as a
3360  *   decimal number (00-99). This works well with \%V and \%u.
3361  * - \%G: the ISO 8601 week-based year as a decimal number. This works
3362  *   well with \%V and \%u.
3363  * - \%h: equivalent to \%b
3364  * - \%H: the hour as a decimal number using a 24-hour clock (range 00 to 23)
3365  * - \%I: the hour as a decimal number using a 12-hour clock (range 01 to 12)
3366  * - \%j: the day of the year as a decimal number (range 001 to 366)
3367  * - \%k: the hour (24-hour clock) as a decimal number (range 0 to 23);
3368  *   single digits are preceded by a blank
3369  * - \%l: the hour (12-hour clock) as a decimal number (range 1 to 12);
3370  *   single digits are preceded by a blank
3371  * - \%m: the month as a decimal number (range 01 to 12)
3372  * - \%M: the minute as a decimal number (range 00 to 59)
3373  * - \%f: the microsecond as a decimal number (range 000000 to 999999)
3374  * - \%p: either "AM" or "PM" according to the given time value, or the
3375  *   corresponding  strings for the current locale.  Noon is treated as
3376  *   "PM" and midnight as "AM". Use of this format specifier is discouraged, as
3377  *   many locales have no concept of AM/PM formatting. Use \%c or \%X instead.
3378  * - \%P: like \%p but lowercase: "am" or "pm" or a corresponding string for
3379  *   the current locale. Use of this format specifier is discouraged, as
3380  *   many locales have no concept of AM/PM formatting. Use \%c or \%X instead.
3381  * - \%r: the time in a.m. or p.m. notation. Use of this format specifier is
3382  *   discouraged, as many locales have no concept of AM/PM formatting. Use \%c
3383  *   or \%X instead.
3384  * - \%R: the time in 24-hour notation (\%H:\%M)
3385  * - \%s: the number of seconds since the Epoch, that is, since 1970-01-01
3386  *   00:00:00 UTC
3387  * - \%S: the second as a decimal number (range 00 to 60)
3388  * - \%t: a tab character
3389  * - \%T: the time in 24-hour notation with seconds (\%H:\%M:\%S)
3390  * - \%u: the ISO 8601 standard day of the week as a decimal, range 1 to 7,
3391  *    Monday being 1. This works well with \%G and \%V.
3392  * - \%V: the ISO 8601 standard week number of the current year as a decimal
3393  *   number, range 01 to 53, where week 1 is the first week that has at
3394  *   least 4 days in the new year. See g_date_time_get_week_of_year().
3395  *   This works well with \%G and \%u.
3396  * - \%w: the day of the week as a decimal, range 0 to 6, Sunday being 0.
3397  *   This is not the ISO 8601 standard format -- use \%u instead.
3398  * - \%x: the preferred date representation for the current locale without
3399  *   the time
3400  * - \%X: the preferred time representation for the current locale without
3401  *   the date
3402  * - \%y: the year as a decimal number without the century
3403  * - \%Y: the year as a decimal number including the century
3404  * - \%z: the time zone as an offset from UTC (+hhmm)
3405  * - \%:z: the time zone as an offset from UTC (+hh:mm).
3406  *   This is a gnulib strftime() extension. Since: 2.38
3407  * - \%::z: the time zone as an offset from UTC (+hh:mm:ss). This is a
3408  *   gnulib strftime() extension. Since: 2.38
3409  * - \%:::z: the time zone as an offset from UTC, with : to necessary
3410  *   precision (e.g., -04, +05:30). This is a gnulib strftime() extension. Since: 2.38
3411  * - \%Z: the time zone or name or abbreviation
3412  * - \%\%: a literal \% character
3413  *
3414  * Some conversion specifications can be modified by preceding the
3415  * conversion specifier by one or more modifier characters. The
3416  * following modifiers are supported for many of the numeric
3417  * conversions:
3418  *
3419  * - O: Use alternative numeric symbols, if the current locale supports those.
3420  * - _: Pad a numeric result with spaces. This overrides the default padding
3421  *   for the specifier.
3422  * - -: Do not pad a numeric result. This overrides the default padding
3423  *   for the specifier.
3424  * - 0: Pad a numeric result with zeros. This overrides the default padding
3425  *   for the specifier.
3426  *
3427  * Additionally, when O is used with B, b, or h, it produces the alternative
3428  * form of a month name. The alternative form should be used when the month
3429  * name is used without a day number (e.g., standalone). It is required in
3430  * some languages (Baltic, Slavic, Greek, and more) due to their grammatical
3431  * rules. For other languages there is no difference. \%OB is a GNU and BSD
3432  * strftime() extension expected to be added to the future POSIX specification,
3433  * \%Ob and \%Oh are GNU strftime() extensions. Since: 2.56
3434  *
3435  * Returns: (transfer full) (nullable): a newly allocated string formatted to
3436  *    the requested format or %NULL in the case that there was an error (such
3437  *    as a format specifier not being supported in the current locale). The
3438  *    string should be freed with g_free().
3439  *
3440  * Since: 2.26
3441  */
3442 gchar *
g_date_time_format(GDateTime * datetime,const gchar * format)3443 g_date_time_format (GDateTime   *datetime,
3444                     const gchar *format)
3445 {
3446   GString  *outstr;
3447   const gchar *charset;
3448   /* Avoid conversions from locale charset to UTF-8 if charset is compatible
3449    * with UTF-8 already. Check for UTF-8 and synonymous canonical names of
3450    * ASCII. */
3451   gboolean locale_is_utf8_compatible = g_get_charset (&charset) ||
3452     g_strcmp0 ("ASCII", charset) == 0 ||
3453     g_strcmp0 ("ANSI_X3.4-1968", charset) == 0;
3454 
3455   g_return_val_if_fail (datetime != NULL, NULL);
3456   g_return_val_if_fail (format != NULL, NULL);
3457   g_return_val_if_fail (g_utf8_validate (format, -1, NULL), NULL);
3458 
3459   outstr = g_string_sized_new (strlen (format) * 2);
3460 
3461   if (!g_date_time_format_utf8 (datetime, format, outstr,
3462                                 locale_is_utf8_compatible))
3463     {
3464       g_string_free (outstr, TRUE);
3465       return NULL;
3466     }
3467 
3468   return g_string_free (outstr, FALSE);
3469 }
3470 
3471 /**
3472  * g_date_time_format_iso8601:
3473  * @datetime: A #GDateTime
3474  *
3475  * Format @datetime in [ISO 8601 format](https://en.wikipedia.org/wiki/ISO_8601),
3476  * including the date, time and time zone, and return that as a UTF-8 encoded
3477  * string.
3478  *
3479  * Since GLib 2.66, this will output to sub-second precision if needed.
3480  *
3481  * Returns: (transfer full) (nullable): a newly allocated string formatted in
3482  *   ISO 8601 format or %NULL in the case that there was an error. The string
3483  *   should be freed with g_free().
3484  *
3485  * Since: 2.62
3486  */
3487 gchar *
g_date_time_format_iso8601(GDateTime * datetime)3488 g_date_time_format_iso8601 (GDateTime *datetime)
3489 {
3490   GString *outstr = NULL;
3491   gchar *main_date = NULL;
3492   gint64 offset;
3493   gchar *format = "%Y-%m-%dT%H:%M:%S";
3494 
3495   /* if datetime has sub-second non-zero values below the second precision we
3496    * should print them as well */
3497   if (datetime->usec % G_TIME_SPAN_SECOND != 0)
3498     format = "%Y-%m-%dT%H:%M:%S.%f";
3499 
3500   /* Main date and time. */
3501   main_date = g_date_time_format (datetime, format);
3502   outstr = g_string_new (main_date);
3503   g_free (main_date);
3504 
3505   /* Timezone. Format it as `%:::z` unless the offset is zero, in which case
3506    * we can simply use `Z`. */
3507   offset = g_date_time_get_utc_offset (datetime);
3508 
3509   if (offset == 0)
3510     {
3511       g_string_append_c (outstr, 'Z');
3512     }
3513   else
3514     {
3515       gchar *time_zone = g_date_time_format (datetime, "%:::z");
3516       g_string_append (outstr, time_zone);
3517       g_free (time_zone);
3518     }
3519 
3520   return g_string_free (outstr, FALSE);
3521 }
3522 
3523 
3524 /* Epilogue {{{1 */
3525 /* vim:set foldmethod=marker: */
3526