LCOV - code coverage report
Current view: top level - glib/glib - gdatetime.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 968 1052 92.0 %
Date: 2024-04-16 05:15:53 Functions: 77 78 98.7 %
Branches: 566 713 79.4 %

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

Generated by: LCOV version 1.14