Coverage Report

Created: 2025-07-23 06:49

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