datetime: Update modifiers for DST changes
[platform/upstream/glib.git] / glib / gdatetime.c
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  *
7  * This is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 /* Algorithms within this file are based on the Calendar FAQ by
23  * Claus Tondering.  It can be found at
24  * http://www.tondering.dk/claus/cal/calendar29.txt
25  *
26  * Copyright and disclaimer
27  * ------------------------
28  *   This document is Copyright (C) 2008 by Claus Tondering.
29  *   E-mail: claus@tondering.dk. (Please include the word
30  *   "calendar" in the subject line.)
31  *   The document may be freely distributed, provided this
32  *   copyright notice is included and no money is charged for
33  *   the document.
34  *
35  *   This document is provided "as is". No warranties are made as
36  *   to its correctness.
37  */
38
39 #include "config.h"
40
41 #include <stdlib.h>
42 #include <string.h>
43
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif
47
48 #ifndef G_OS_WIN32
49 #include <sys/time.h>
50 #include <time.h>
51 #endif /* !G_OS_WIN32 */
52
53 #include "gdatetime.h"
54
55 #include "gatomic.h"
56 #include "gfileutils.h"
57 #include "ghash.h"
58 #include "gmain.h"
59 #include "gmappedfile.h"
60 #include "gstrfuncs.h"
61 #include "gtestutils.h"
62 #include "gthread.h"
63
64 #include "glibintl.h"
65
66 /**
67  * SECTION:date-time
68  * @title: GDateTime
69  * @short_description: A structure representing Date and Time
70  *
71  * #GDateTime is a structure that combines a date and time into a single
72  * structure. It provides many conversion and methods to manipulate dates
73  * and times. Time precision is provided down to microseconds.
74  *
75  * #GDateTime is an immutable object: once it has been created it cannot be
76  * modified further. All modifiers will create a new #GDateTime.
77  *
78  * #GDateTime is reference counted: the reference count is increased by calling
79  * g_date_time_ref() and decreased by calling g_date_time_unref(). When the
80  * reference count drops to 0, the resources allocated by the #GDateTime
81  * structure are released.
82  *
83  * Internally, #GDateTime uses the Proleptic Gregorian Calendar, the first
84  * representable date is 0001-01-01. However, the public API uses the
85  * internationally accepted Gregorian Calendar.
86  *
87  * #GDateTime is available since GLib 2.26.
88  */
89
90 #define UNIX_EPOCH_START     719163
91
92 #define DAYS_IN_4YEARS    1461    /* days in 4 years */
93 #define DAYS_IN_100YEARS  36524   /* days in 100 years */
94 #define DAYS_IN_400YEARS  146097  /* days in 400 years  */
95
96 #define USEC_PER_SECOND      (G_GINT64_CONSTANT (1000000))
97 #define USEC_PER_MINUTE      (G_GINT64_CONSTANT (60000000))
98 #define USEC_PER_HOUR        (G_GINT64_CONSTANT (3600000000))
99 #define USEC_PER_MILLISECOND (G_GINT64_CONSTANT (1000))
100 #define USEC_PER_DAY         (G_GINT64_CONSTANT (86400000000))
101 #define SEC_PER_DAY          (G_GINT64_CONSTANT (86400))
102
103 #define GREGORIAN_LEAP(y)    ((((y) % 4) == 0) && (!((((y) % 100) == 0) && (((y) % 400) != 0))))
104 #define JULIAN_YEAR(d)       ((d)->julian / 365.25)
105 #define DAYS_PER_PERIOD      (G_GINT64_CONSTANT (2914695))
106
107 #define GET_AMPM(d,l)         ((g_date_time_get_hour (d) < 12)  \
108                                        /* Translators: 'before midday' indicator */ \
109                                 ? (l ? C_("GDateTime", "am") \
110                                        /* Translators: 'before midday' indicator */ \
111                                      : C_("GDateTime", "AM")) \
112                                   /* Translators: 'after midday' indicator */ \
113                                 : (l ? C_("GDateTime", "pm") \
114                                   /* Translators: 'after midday' indicator */ \
115                                      : C_("GDateTime", "PM")))
116
117 #define WEEKDAY_ABBR(d)       (get_weekday_name_abbr (g_date_time_get_day_of_week (datetime)))
118 #define WEEKDAY_FULL(d)       (get_weekday_name (g_date_time_get_day_of_week (datetime)))
119
120 #define MONTH_ABBR(d)         (get_month_name_abbr (g_date_time_get_month (datetime)))
121 #define MONTH_FULL(d)         (get_month_name (g_date_time_get_month (datetime)))
122
123 /* Translators: this is the preferred format for expressing the date */
124 #define GET_PREFERRED_DATE(d) (g_date_time_printf ((d), C_("GDateTime", "%m/%d/%y")))
125
126 /* Translators: this is the preferred format for expressing the time */
127 #define GET_PREFERRED_TIME(d) (g_date_time_printf ((d), C_("GDateTime", "%H:%M:%S")))
128
129 #define SECS_PER_MINUTE (60)
130 #define SECS_PER_HOUR   (60 * SECS_PER_MINUTE)
131 #define SECS_PER_DAY    (24 * SECS_PER_HOUR)
132 #define SECS_PER_YEAR   (365 * SECS_PER_DAY)
133 #define SECS_PER_JULIAN (DAYS_PER_PERIOD * SECS_PER_DAY)
134
135 typedef struct _GTimeZoneFile   GTimeZoneFile;
136
137 struct _GDateTime
138 {
139   /* 1 is 0001-01-01 in Proleptic Gregorian */
140   guint32 days;
141
142   /* Microsecond timekeeping within Day */
143   guint64 usec;
144
145   /* TimeZone information, NULL is UTC */
146   GTimeZone *tz;
147
148   volatile gint ref_count;
149 };
150
151 struct _GTimeZone
152 {
153   GTimeZoneFile *tz_file;
154
155   gchar *name;
156
157   gint64 offset;
158
159   guint is_dst      : 1;
160   guint is_utc      : 1;
161   guint is_floating : 1;
162 };
163
164 struct _GTimeZoneFile
165 {
166   GMappedFile *file;
167
168   gchar *filename;
169
170   volatile gint ref_count;
171 };
172
173 G_LOCK_DEFINE_STATIC (time_zone_files);
174 static GHashTable *time_zone_files = NULL;
175
176 static const guint16 days_in_months[2][13] =
177 {
178   { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
179   { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
180 };
181
182 static const guint16 days_in_year[2][13] =
183 {
184   {  0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
185   {  0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
186 };
187
188 static const gchar *
189 get_month_name (gint month)
190 {
191   switch (month)
192     {
193     case 1:
194       return C_("full month name", "January");
195     case 2:
196       return C_("full month name", "February");
197     case 3:
198       return C_("full month name", "March");
199     case 4:
200       return C_("full month name", "April");
201     case 5:
202       return C_("full month name", "May");
203     case 6:
204       return C_("full month name", "June");
205     case 7:
206       return C_("full month name", "July");
207     case 8:
208       return C_("full month name", "August");
209     case 9:
210       return C_("full month name", "September");
211     case 10:
212       return C_("full month name", "October");
213     case 11:
214       return C_("full month name", "November");
215     case 12:
216       return C_("full month name", "December");
217
218     default:
219       g_warning ("Invalid month number %d", month);
220     }
221
222   return NULL;
223 }
224
225 static const gchar *
226 get_month_name_abbr (gint month)
227 {
228   switch (month)
229     {
230     case 1:
231       return C_("abbreviated month name", "Jan");
232     case 2:
233       return C_("abbreviated month name", "Feb");
234     case 3:
235       return C_("abbreviated month name", "Mar");
236     case 4:
237       return C_("abbreviated month name", "Apr");
238     case 5:
239       return C_("abbreviated month name", "May");
240     case 6:
241       return C_("abbreviated month name", "Jun");
242     case 7:
243       return C_("abbreviated month name", "Jul");
244     case 8:
245       return C_("abbreviated month name", "Aug");
246     case 9:
247       return C_("abbreviated month name", "Sep");
248     case 10:
249       return C_("abbreviated month name", "Oct");
250     case 11:
251       return C_("abbreviated month name", "Nov");
252     case 12:
253       return C_("abbreviated month name", "Dec");
254
255     default:
256       g_warning ("Invalid month number %d", month);
257     }
258
259   return NULL;
260 }
261
262 static const gchar *
263 get_weekday_name (gint day)
264 {
265   switch (day)
266     {
267     case 1:
268       return C_("full weekday name", "Monday");
269     case 2:
270       return C_("full weekday name", "Tuesday");
271     case 3:
272       return C_("full weekday name", "Wednesday");
273     case 4:
274       return C_("full weekday name", "Thursday");
275     case 5:
276       return C_("full weekday name", "Friday");
277     case 6:
278       return C_("full weekday name", "Saturday");
279     case 7:
280       return C_("full weekday name", "Sunday");
281
282     default:
283       g_warning ("Invalid week day number %d", day);
284     }
285
286   return NULL;
287 }
288
289 static const gchar *
290 get_weekday_name_abbr (gint day)
291 {
292   switch (day)
293     {
294     case 1:
295       return C_("abbreviated weekday name", "Mon");
296     case 2:
297       return C_("abbreviated weekday name", "Tue");
298     case 3:
299       return C_("abbreviated weekday name", "Wed");
300     case 4:
301       return C_("abbreviated weekday name", "Thu");
302     case 5:
303       return C_("abbreviated weekday name", "Fri");
304     case 6:
305       return C_("abbreviated weekday name", "Sat");
306     case 7:
307       return C_("abbreviated weekday name", "Sun");
308
309     default:
310       g_warning ("Invalid week day number %d", day);
311     }
312
313   return NULL;
314 }
315
316 #define ZONEINFO_DIR            "zoneinfo"
317 #define TZ_MAGIC                "TZif"
318 #define TZ_MAGIC_LEN            (strlen (TZ_MAGIC))
319 #define TZ_HEADER_SIZE          44
320 #define TZ_TIMECNT_OFFSET       32
321 #define TZ_TYPECNT_OFFSET       36
322 #define TZ_TRANSITIONS_OFFSET   44
323 #define TZ_TTINFO_SIZE          6
324 #define TZ_TTINFO_GMTOFF_OFFSET 0
325 #define TZ_TTINFO_ISDST_OFFSET  4
326 #define TZ_TTINFO_NAME_OFFSET   5
327
328 static gchar *
329 get_tzdata_path (const gchar *tz_name)
330 {
331   gchar *retval = NULL;
332   const gchar *tz_dir = g_getenv ("TZDIR");
333
334   if (tz_dir != NULL)
335     retval = g_build_filename (tz_dir, tz_name, NULL);
336   else
337     {
338       if (strcmp (tz_name, "localtime") == 0)
339         retval = g_build_filename ("/", "etc", "localtime", NULL);
340       else
341         retval = g_build_filename ("/", "usr", "share", ZONEINFO_DIR, tz_name, NULL);
342     }
343
344   return retval;
345 }
346
347 static gboolean
348 parse_tzdata (GTimeZoneFile  *tz_file,
349               gint64          start,
350               gboolean        is_utc,
351               gint64         *_offset,
352               gboolean       *_is_dst,
353               gchar         **_name)
354 {
355   gchar *contents;
356   gsize length;
357   guint32 timecnt, typecnt;
358   gint transitions_size, ttinfo_map_size;
359   guint8 *ttinfo_map, *ttinfos;
360   gint start_transition = -1;
361   guint32 *transitions;
362   gint32 offset;
363   guint8 isdst;
364   guint8 name_offset;
365   gint i;
366
367   contents = g_mapped_file_get_contents (tz_file->file);
368   length = g_mapped_file_get_length (tz_file->file);
369
370   if (length < TZ_HEADER_SIZE ||
371       (strncmp (contents, TZ_MAGIC, TZ_MAGIC_LEN) != 0))
372     {
373       return FALSE;
374     }
375
376   timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
377   typecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TYPECNT_OFFSET));
378
379   transitions = (guint32 *)(contents + TZ_TRANSITIONS_OFFSET);
380   transitions_size = timecnt * sizeof (*transitions);
381   ttinfo_map = (void *)(contents + TZ_TRANSITIONS_OFFSET + transitions_size);
382   ttinfo_map_size = timecnt;
383   ttinfos = (void *)(ttinfo_map + ttinfo_map_size);
384
385   /*
386    * Find the first transition that contains the 'start' time
387    */
388   for (i = 1; i < timecnt && start_transition == -1; i++)
389     {
390       gint32 transition_time = GINT32_FROM_BE (transitions[i]);
391
392       /* if is_utc is not set, we need to add this time offset to compare with
393        * start, because it is already on the timezone time */
394       if (!is_utc)
395         {
396           gint32 off;
397
398           off = *(gint32 *)(ttinfos + ttinfo_map[i] * TZ_TTINFO_SIZE +
399                 TZ_TTINFO_GMTOFF_OFFSET);
400           off = GINT32_FROM_BE (off);
401
402           transition_time += off;
403         }
404
405       if (transition_time > start)
406         {
407           start_transition = ttinfo_map[i - 1];
408           break;
409         }
410     }
411
412   if (start_transition == -1)
413     {
414       if (timecnt)
415         start_transition = ttinfo_map[timecnt - 1];
416       else
417         start_transition = 0;
418     }
419
420   /* Copy the data out of the corresponding ttinfo structs */
421   offset = *(gint32 *)(ttinfos + start_transition * TZ_TTINFO_SIZE +
422            TZ_TTINFO_GMTOFF_OFFSET);
423   offset = GINT32_FROM_BE (offset);
424   isdst = *(ttinfos + start_transition * TZ_TTINFO_SIZE +
425           TZ_TTINFO_ISDST_OFFSET);
426   name_offset = *(ttinfos + start_transition * TZ_TTINFO_SIZE +
427                 TZ_TTINFO_NAME_OFFSET);
428
429   if (_name != NULL)
430     *_name = g_strdup ((gchar*) (ttinfos + TZ_TTINFO_SIZE * typecnt + name_offset));
431
432   if (_offset)
433     *_offset = offset;
434
435   if (_is_dst)
436     *_is_dst = isdst;
437
438   return TRUE;
439 }
440
441 static GTimeZoneFile *
442 g_time_zone_file_new (const gchar *filename)
443 {
444   GMappedFile *tz_file;
445   GTimeZoneFile *retval;
446
447   tz_file = g_mapped_file_new (filename, FALSE, NULL);
448   if (tz_file == NULL)
449     return NULL;
450
451   retval = g_slice_new (GTimeZoneFile);
452   retval->filename = g_strdup (filename);
453   retval->file = tz_file;
454   retval->ref_count = 1;
455
456   return retval;
457 }
458
459 static GTimeZoneFile *
460 g_time_zone_file_ref (GTimeZoneFile *tz_file)
461 {
462   if (tz_file == NULL)
463     return NULL;
464
465   g_atomic_int_inc (&tz_file->ref_count);
466
467   return tz_file;
468 }
469
470 static void
471 g_time_zone_file_unref (GTimeZoneFile *tz_file)
472 {
473   if (tz_file == NULL)
474     return;
475
476   if (g_atomic_int_dec_and_test (&tz_file->ref_count))
477     {
478       /* remove the TimeZoneFile from the hash table of known files */
479       G_LOCK (time_zone_files);
480       g_hash_table_remove (time_zone_files, tz_file->filename);
481       G_UNLOCK (time_zone_files);
482
483       g_mapped_file_unref (tz_file->file);
484       g_free (tz_file->filename);
485       g_slice_free (GTimeZoneFile, tz_file);
486     }
487 }
488
489 /*< internal >
490  * g_time_zone_file_get_for_path:
491  * @path: the full path for a time zone file
492  *
493  * Retrieves a #GTimeZoneFile for the given path.
494  *
495  * If a time zone file for the same path has been already requested,
496  * this function will return the same #GTimeZoneFile with its reference
497  * count increased by one; otherwise, a new #GTimeZoneFile will be created
498  * and added to the known time zone files.
499  *
500  * The time zone files are removed from the list of known files when their
501  * reference count reaches 0.
502  *
503  * This function holds the lock on the time_zone_files hash table.
504  *
505  * Return value: a #GTimeZoneFile or %NULL
506  */
507 static GTimeZoneFile *
508 g_time_zone_file_get_for_path (const gchar *path)
509 {
510   GTimeZoneFile *retval;
511
512   G_LOCK (time_zone_files);
513
514   if (G_LIKELY (time_zone_files != NULL))
515     {
516       retval = g_hash_table_lookup (time_zone_files, path);
517       if (retval != NULL)
518         {
519           retval = g_time_zone_file_ref (retval);
520           goto out;
521         }
522     }
523
524   retval = g_time_zone_file_new (path);
525   if (retval != NULL)
526     {
527       if (G_UNLIKELY (time_zone_files == NULL))
528         time_zone_files = g_hash_table_new (g_str_hash, g_str_equal);
529
530       g_hash_table_insert (time_zone_files, retval->filename, retval);
531     }
532
533 out:
534   G_UNLOCK (time_zone_files);
535
536   return retval;
537 }
538
539 /**
540  * g_time_zone_new:
541  * @offset: the timezone offset from UTC, in seconds
542  * @is_dst: whether the timezone is in Daylight Saving Time or not
543  *
544  * Creates a new #GTimeZone for the given @offset, to be used when
545  * creating a #GDateTime.
546  *
547  * The #GTimeZone created will not be floating.
548  *
549  * Return value: (transfer full): the newly allocated #GTimeZone
550  *
551  * Since: 2.26
552  */
553 GTimeZone *
554 g_time_zone_new (gint     offset,
555                  gboolean is_dst)
556 {
557   GTimeZone *tz;
558
559   g_return_val_if_fail (offset >= -12 * SECS_PER_HOUR && offset <= 12 * SECS_PER_HOUR, NULL);
560
561   tz = g_slice_new (GTimeZone);
562   tz->offset = offset;
563   tz->is_dst = is_dst;
564   tz->tz_file = NULL;
565   tz->is_floating = FALSE;
566
567   if (tz->offset == 0)
568     tz->name = g_strdup_printf ("UTC");
569   else
570     tz->name = g_strdup_printf ("UTC%c%02d:%02d",
571                                 tz->offset > 0 ? '+' : '-',
572                                 (int) tz->offset / 3600,
573                                 (int) tz->offset / 60 % 60);
574
575   return tz;
576 }
577
578 /**
579  * g_time_zone_new_for_name:
580  * @name: an ASCII string containing the Olson's database name of the
581  *   timezone, e.g. "America/New_York" or "Europe/London"
582  *
583  * Creates a new #GTimeZone for the given @name.
584  *
585  * The returned timezone is "floating": if queried, it will return invalid
586  * values. A floating #GTimeZone is "sunk" when it is bound to a #GDateTime
587  * object.
588  *
589  * For instance:
590  *
591  * |[
592  * /&ast; the time zone is "floating" &ast;/
593  * GTimeZone *tz = g_time_zone_new_for_name ("Europe/London");
594  *
595  * /&ast; this will print: "UTC offset: 0 seconds" &ast;/
596  * g_print ("UTC offset: %d seconds\n", g_time_zone_get_offset (tz));
597  *
598  * /&ast; the GDateTime object copies the time zone &ast;/
599  * GDateTime *dt = g_date_time_new_full (2010, 9, 15, 12, 0, 0, tz);
600  *
601  * /&ast; this will print: "UTC offset: 3600 seconds", because Europe/London
602  *  &ast; on that date is in daylight saving time
603  *  &ast;/
604  * g_print ("UTC offset: %d seconds\n",
605  *          g_date_time_get_utc_offset (dt) / G_USEC_PER_SEC);
606  * ]|
607  *
608  * Return value: (transfer full): the newly created, floating #GTimeZone
609  *   object for the given name, or %NULL if none was found
610  *
611  * Since: 2.26
612  */
613 GTimeZone *
614 g_time_zone_new_for_name (const gchar *name)
615 {
616   GTimeZone *tz;
617   gchar *filename;
618   GTimeZoneFile *tz_file;
619
620   g_return_val_if_fail (name != NULL, NULL);
621
622   filename = get_tzdata_path (name);
623   if (filename == NULL)
624     return NULL;
625
626   tz_file = g_time_zone_file_get_for_path (filename);
627   g_free (filename);
628
629   if (tz_file == NULL)
630     return NULL;
631
632   tz = g_slice_new (GTimeZone);
633   tz->tz_file = tz_file;
634   tz->name = NULL;
635   tz->offset = 0;
636   tz->is_dst = FALSE;
637   tz->is_utc = (strcmp (name, "UTC") == 0);
638   tz->is_floating = TRUE;
639
640   return tz;
641 }
642
643 /**
644  * g_time_zone_new_utc:
645  *
646  * Creates a new #GTimeZone for UTC.
647  *
648  * Return value: (transfer full): a newly created #GTimeZone for UTC.
649  *   Use g_time_zone_free() when done.
650  *
651  * Since: 2.26
652  */
653 GTimeZone *
654 g_time_zone_new_utc (void)
655 {
656   return g_time_zone_new (0, FALSE);
657 }
658
659 /**
660  * g_time_zone_new_local:
661  *
662  * Creates a new #GTimeZone for the local timezone.
663  *
664  * The returned #GTimeZone is floating.
665  *
666  * Return value: (transfer full): a newly created, floating #GTimeZone.
667  *   Use g_time_zone_free() when done.
668  *
669  * Since: 2.26
670  */
671 GTimeZone *
672 g_time_zone_new_local (void)
673 {
674   return g_time_zone_new_for_name ("localtime");
675 }
676
677 /**
678  * g_time_zone_copy:
679  * @time_zone: a #GTimeZone
680  *
681  * Copies a #GTimeZone. If @time_zone is floating, the returned copy
682  * will be floating as well.
683  *
684  * Return value: (transfer full): the newly created #GTimeZone
685  *
686  * Since: 2.26
687  */
688 GTimeZone *
689 g_time_zone_copy (const GTimeZone *time_zone)
690 {
691   GTimeZone *retval;
692
693   g_return_val_if_fail (time_zone != NULL, NULL);
694
695   retval = g_slice_dup (GTimeZone, time_zone);
696
697   if (time_zone->tz_file != NULL)
698     retval->tz_file = g_time_zone_file_ref (time_zone->tz_file);
699
700   if (time_zone->name != NULL)
701     retval->name = g_strdup (time_zone->name);
702
703   return retval;
704 }
705
706 /**
707  * g_time_zone_free:
708  * @time_zone: a #GTimeZone
709  *
710  * Frees the resources associated with a #GTimeZone
711  *
712  * Since: 2.26
713  */
714 void
715 g_time_zone_free (GTimeZone *time_zone)
716 {
717   g_return_if_fail (time_zone != NULL);
718
719   if (time_zone->tz_file != NULL)
720     g_time_zone_file_unref (time_zone->tz_file);
721
722   g_free (time_zone->name);
723   g_slice_free (GTimeZone, time_zone);
724 }
725
726 /**
727  * g_time_zone_get_name:
728  * @time_zone: a #GTimeZone
729  *
730  * Retrieves the name of the @time_zone, or %NULL if the #GTimeZone is
731  * floating.
732  *
733  * Return value: (transfer none): the name of the #GTimeZone. The returned
734  *   string is owned by the #GTimeZone and it should never be modified or
735  *   freed
736  *
737  * Since: 2.26
738  */
739 G_CONST_RETURN gchar *
740 g_time_zone_get_name (const GTimeZone *time_zone)
741 {
742   g_return_val_if_fail (time_zone != NULL, NULL);
743
744   if (!time_zone->is_floating)
745     return time_zone->name;
746
747   return NULL;
748 }
749
750 /**
751  * g_time_zone_get_offset:
752  * @time_zone: a #GTimeZone
753  *
754  * Retrieves the offset of the @time_zone, in seconds from UTC, or 0
755  * if the #GTimeZone is floating.
756  *
757  * Return value: the offset from UTC, in seconds
758  *
759  * Since: 2.26
760  */
761 gint
762 g_time_zone_get_offset (const GTimeZone *time_zone)
763 {
764   g_return_val_if_fail (time_zone != NULL, 0);
765
766   if (!time_zone->is_floating)
767     return time_zone->offset;
768
769   return 0;
770 }
771
772 /**
773  * g_time_zone_get_is_dst:
774  * @time_zone: a #GTimeZone
775  *
776  * Checks whether the @time_zone is in Daylight Saving Time.
777  * If the #GTimeZone is floating, %FALSE is always returned.
778  *
779  * Return value: %TRUE if the #GTimeZone is in DST, or %FALSE.
780  *
781  * Since: 2.26
782  */
783 gboolean
784 g_time_zone_get_is_dst (const GTimeZone *time_zone)
785 {
786   g_return_val_if_fail (time_zone != NULL, FALSE);
787
788   if (!time_zone->is_floating)
789     return time_zone->is_dst;
790
791   return FALSE;
792 }
793
794 /**
795  * g_time_zone_is_floating:
796  * @time_zone: a #GTimeZone
797  *
798  * Checks whether @time_zone is floating
799  *
800  * Return value: %TRUE if the #GTimeZone is floating, and %FALSE otherwise
801  *
802  * Since: 2.26
803  */
804 gboolean
805 g_time_zone_is_floating (const GTimeZone *time_zone)
806 {
807   g_return_val_if_fail (time_zone != NULL, FALSE);
808
809   return time_zone->is_floating;
810 }
811
812 /*< internal >
813  * g_time_zone_sink:
814  * @time_zone: a #GTimeZone
815  * @datetime: a #GDateTime
816  *
817  * Sinks the floating state of @time_zone by associating it with the
818  * given #GDateTime.
819  *
820  * If @time_zone is not floating, this function does not do anything
821  */
822 static void
823 g_time_zone_sink (GTimeZone *time_zone,
824                   GDateTime *datetime)
825 {
826   gint64 offset, epoch;
827   gboolean is_dst, is_utc;
828   gchar *abbrev;
829
830   if (!time_zone->is_floating)
831     return;
832
833   epoch = g_date_time_to_epoch (datetime);
834   is_utc = time_zone->is_utc;
835   offset = 0;
836   is_dst = FALSE;
837   abbrev = NULL;
838   if (parse_tzdata (time_zone->tz_file, epoch, is_utc, &offset, &is_dst, &abbrev))
839     {
840       time_zone->offset = offset;
841       time_zone->is_dst = is_dst;
842       time_zone->name = abbrev;
843       time_zone->is_utc = (offset == 0);
844       time_zone->is_floating = FALSE;
845     }
846 }
847
848 static inline gint
849 date_to_proleptic_gregorian (gint year,
850                              gint month,
851                              gint day)
852 {
853   gint64 days;
854
855   days = (year - 1) * 365 + ((year - 1) / 4) - ((year - 1) / 100)
856       + ((year - 1) / 400);
857
858   days += days_in_year[0][month - 1];
859   if (GREGORIAN_LEAP (year) && month > 2)
860     day++;
861
862   days += day;
863
864   return days;
865 }
866
867 static inline void g_date_time_add_usec (GDateTime *datetime,
868                                          gint64     usecs);
869
870 static inline void
871 g_date_time_add_days_internal (GDateTime *datetime,
872                                gint64     days)
873 {
874   gboolean was_dst = FALSE;
875   gint64 old_offset = 0;
876
877   if (datetime->tz != NULL && datetime->tz->tz_file != NULL)
878     {
879       was_dst = g_time_zone_get_is_dst (datetime->tz);
880       old_offset = g_time_zone_get_offset (datetime->tz);
881
882       datetime->tz->is_floating = TRUE;
883     }
884
885   datetime->days += days;
886
887   if (datetime->tz != NULL && datetime->tz->tz_file != NULL)
888     {
889       gint64 offset;
890
891       g_time_zone_sink (datetime->tz, datetime);
892
893       if (was_dst == g_time_zone_get_is_dst (datetime->tz))
894         return;
895
896       offset = old_offset - g_time_zone_get_offset (datetime->tz);
897       g_date_time_add_usec (datetime, offset * USEC_PER_SECOND * -1);
898     }
899 }
900
901 static inline void
902 g_date_time_add_usec (GDateTime *datetime,
903                       gint64     usecs)
904 {
905   gint64 u = datetime->usec + usecs;
906   gint d = u / USEC_PER_DAY;
907   gboolean was_dst = FALSE;
908   gint64 old_offset = 0;
909
910   /* if we are using a time zone from a zoneinfo we want to
911    * check for changes in the DST and update the DateTime
912    * accordingly in case we change for standard time to DST
913    * and vice versa
914    */
915   if (datetime->tz != NULL && datetime->tz->tz_file != NULL)
916     {
917       was_dst = g_time_zone_get_is_dst (datetime->tz);
918       old_offset = g_time_zone_get_offset (datetime->tz);
919
920       /* force the floating state */
921       datetime->tz->is_floating = TRUE;
922     }
923
924   if (u < 0)
925     d -= 1;
926
927   if (d != 0)
928     g_date_time_add_days_internal (datetime, d);
929
930   if (u < 0)
931     datetime->usec = USEC_PER_DAY + (u % USEC_PER_DAY);
932   else
933     datetime->usec = u % USEC_PER_DAY;
934
935   if (datetime->tz != NULL && datetime->tz->tz_file != NULL)
936     {
937       gint64 offset;
938
939       /* sink the timezone; if there were no changes in the
940        * DST state then bail out; otherwise, apply the change
941        * in the offset to the DateTime
942        */
943       g_time_zone_sink (datetime->tz, datetime);
944
945       if (was_dst == g_time_zone_get_is_dst (datetime->tz))
946         return;
947
948       offset = old_offset - g_time_zone_get_offset (datetime->tz);
949       g_date_time_add_usec (datetime, offset * USEC_PER_SECOND * -1);
950     }
951 }
952
953 /*< internal >
954  * g_date_time_add_ymd:
955  * @datetime: a #GDateTime
956  * @years: years to add, in the Gregorian calendar
957  * @months: months to add, in the Gregorian calendar
958  * @days: days to add, in the Gregorian calendar
959  *
960  * Updates @datetime by adding @years, @months and @days to it
961  *
962  * This function modifies the passed #GDateTime so public accessors
963  * should make always pass a copy
964  */
965 static inline void
966 g_date_time_add_ymd (GDateTime *datetime,
967                      gint       years,
968                      gint       months,
969                      gint       days)
970 {
971   gint y = g_date_time_get_year (datetime);
972   gint m = g_date_time_get_month (datetime);
973   gint d = g_date_time_get_day_of_month (datetime);
974   gint step, i;
975   const guint16 *max_days;
976
977   y += years;
978
979   /* subtract one day for leap years */
980   if (GREGORIAN_LEAP (y) && m == 2)
981     {
982       if (d == 29)
983         d -= 1;
984     }
985
986   /* add months */
987   step = months > 0 ? 1 : -1;
988   for (i = 0; i < ABS (months); i++)
989     {
990       m += step;
991
992       if (m < 1)
993         {
994           y -= 1;
995           m = 12;
996         }
997       else if (m > 12)
998         {
999           y += 1;
1000           m = 1;
1001         }
1002     }
1003
1004   /* clamp the days */
1005   max_days = days_in_months[GREGORIAN_LEAP (y) ? 1 : 0];
1006   if (max_days[m] < d)
1007     d = max_days[m];
1008
1009   datetime->days = date_to_proleptic_gregorian (y, m, d);
1010   g_date_time_add_days_internal (datetime, days);
1011 }
1012
1013 static GDateTime *
1014 g_date_time_new (void)
1015 {
1016   GDateTime *datetime;
1017
1018   datetime = g_slice_new0 (GDateTime);
1019   datetime->ref_count = 1;
1020
1021   return datetime;
1022 }
1023
1024 /*< internal >
1025  * g_date_time_copy:
1026  * @datetime: a #GDateTime
1027  *
1028  * Creates a copy of @datetime.
1029  *
1030  * Return value: the newly created #GDateTime which should be freed with
1031  *   g_date_time_unref().
1032  */
1033 static GDateTime *
1034 g_date_time_copy (const GDateTime *datetime)
1035 {
1036   GDateTime *copied;
1037
1038   g_return_val_if_fail (datetime != NULL, NULL);
1039
1040   copied = g_date_time_new ();
1041   copied->days = datetime->days;
1042   copied->usec = datetime->usec;
1043
1044   if (datetime->tz != NULL)
1045     copied->tz = g_time_zone_copy (datetime->tz);
1046
1047   return copied;
1048 }
1049
1050 static void
1051 g_date_time_free (GDateTime *datetime)
1052 {
1053   if (G_UNLIKELY (datetime == NULL))
1054     return;
1055
1056   if (datetime->tz != NULL)
1057     g_time_zone_free (datetime->tz);
1058
1059   g_slice_free (GDateTime, datetime);
1060 }
1061
1062 /**
1063  * g_date_time_ref:
1064  * @datetime: a #GDateTime
1065  *
1066  * Atomically increments the reference count of @datetime by one.
1067  *
1068  * Return value: the #GDateTime with the reference count increased
1069  *
1070  * Since: 2.26
1071  */
1072 GDateTime *
1073 g_date_time_ref (GDateTime *datetime)
1074 {
1075   g_return_val_if_fail (datetime != NULL, NULL);
1076   g_return_val_if_fail (datetime->ref_count > 0, NULL);
1077
1078   g_atomic_int_inc (&datetime->ref_count);
1079
1080   return datetime;
1081 }
1082
1083 /**
1084  * g_date_time_unref:
1085  * @datetime: a #GDateTime
1086  *
1087  * Atomically decrements the reference count of @datetime by one.
1088  *
1089  * When the reference count reaches zero, the resources allocated by
1090  * @datetime are freed
1091  *
1092  * Since: 2.26
1093  */
1094 void
1095 g_date_time_unref (GDateTime *datetime)
1096 {
1097   g_return_if_fail (datetime != NULL);
1098   g_return_if_fail (datetime->ref_count > 0);
1099
1100   if (g_atomic_int_dec_and_test (&datetime->ref_count))
1101     g_date_time_free (datetime);
1102 }
1103
1104 static void
1105 g_date_time_get_week_number (const GDateTime *datetime,
1106                              gint            *week_number,
1107                              gint            *day_of_week,
1108                              gint            *day_of_year)
1109 {
1110   gint a, b, c, d, e, f, g, n, s, month, day, year;
1111
1112   g_date_time_get_dmy (datetime, &day, &month, &year);
1113
1114   if (month <= 2)
1115     {
1116       a = g_date_time_get_year (datetime) - 1;
1117       b = (a / 4) - (a / 100) + (a / 400);
1118       c = ((a - 1) / 4) - ((a - 1) / 100) + ((a - 1) / 400);
1119       s = b - c;
1120       e = 0;
1121       f = day - 1 + (31 * (month - 1));
1122     }
1123   else
1124     {
1125       a = year;
1126       b = (a / 4) - (a / 100) + (a / 400);
1127       c = ((a - 1) / 4) - ((a - 1) / 100) + ((a - 1) / 400);
1128       s = b - c;
1129       e = s + 1;
1130       f = day + (((153 * (month - 3)) + 2) / 5) + 58 + s;
1131     }
1132
1133   g = (a + b) % 7;
1134   d = (f + g - e) % 7;
1135   n = f + 3 - d;
1136
1137   if (week_number)
1138     {
1139       if (n < 0)
1140         *week_number = 53 - ((g - s) / 5);
1141       else if (n > 364 + s)
1142         *week_number = 1;
1143       else
1144         *week_number = (n / 7) + 1;
1145     }
1146
1147   if (day_of_week)
1148     *day_of_week = d + 1;
1149
1150   if (day_of_year)
1151     *day_of_year = f + 1;
1152 }
1153
1154 /**
1155  * g_date_time_add:
1156  * @datetime: a #GDateTime
1157  * @timespan: a #GTimeSpan
1158  *
1159  * Creates a copy of @datetime and adds the specified timespan to the copy.
1160  *
1161  * Return value: the newly created #GDateTime which should be freed with
1162  *   g_date_time_unref().
1163  *
1164  * Since: 2.26
1165  */
1166 GDateTime*
1167 g_date_time_add (const GDateTime *datetime,
1168                  GTimeSpan        timespan)
1169 {
1170   GDateTime *dt;
1171
1172   g_return_val_if_fail (datetime != NULL, NULL);
1173
1174   dt = g_date_time_copy (datetime);
1175   g_date_time_add_usec (dt, timespan);
1176
1177   return dt;
1178 }
1179
1180 /**
1181  * g_date_time_add_years:
1182  * @datetime: a #GDateTime
1183  * @years: the number of years
1184  *
1185  * Creates a copy of @datetime and adds the specified number of years to the
1186  * copy.
1187  *
1188  * Return value: the newly created #GDateTime which should be freed with
1189  *   g_date_time_unref().
1190  *
1191  * Since: 2.26
1192  */
1193 GDateTime*
1194 g_date_time_add_years (const GDateTime *datetime,
1195                        gint             years)
1196 {
1197   GDateTime *dt;
1198
1199   g_return_val_if_fail (datetime != NULL, NULL);
1200
1201   dt = g_date_time_copy (datetime);
1202   g_date_time_add_ymd (dt, years, 0, 0);
1203
1204   return dt;
1205 }
1206
1207 /**
1208  * g_date_time_add_months:
1209  * @datetime: a #GDateTime
1210  * @months: the number of months
1211  *
1212  * Creates a copy of @datetime and adds the specified number of months to the
1213  * copy.
1214  *
1215  * Return value: the newly created #GDateTime which should be freed with
1216  *   g_date_time_unref().
1217  *
1218  * Since: 2.26
1219  */
1220 GDateTime*
1221 g_date_time_add_months (const GDateTime *datetime,
1222                         gint             months)
1223 {
1224   GDateTime *dt;
1225
1226   g_return_val_if_fail (datetime != NULL, NULL);
1227
1228   dt = g_date_time_copy (datetime);
1229   g_date_time_add_ymd (dt, 0, months, 0);
1230
1231   return dt;
1232 }
1233
1234 /**
1235  * g_date_time_add_weeks:
1236  * @datetime: a #GDateTime
1237  * @weeks: the number of weeks
1238  *
1239  * Creates a copy of @datetime and adds the specified number of weeks to the
1240  * copy.
1241  *
1242  * Return value: the newly created #GDateTime which should be freed with
1243  *   g_date_time_unref().
1244  *
1245  * Since: 2.26
1246  */
1247 GDateTime*
1248 g_date_time_add_weeks (const GDateTime *datetime,
1249                        gint             weeks)
1250 {
1251   g_return_val_if_fail (datetime != NULL, NULL);
1252
1253   return g_date_time_add_days (datetime, weeks * 7);
1254 }
1255
1256 /**
1257  * g_date_time_add_days:
1258  * @datetime: a #GDateTime
1259  * @days: the number of days
1260  *
1261  * Creates a copy of @datetime and adds the specified number of days to the
1262  * copy.
1263  *
1264  * Return value: the newly created #GDateTime which should be freed with
1265  *   g_date_time_unref().
1266  *
1267  * Since: 2.26
1268  */
1269 GDateTime*
1270 g_date_time_add_days (const GDateTime *datetime,
1271                       gint             days)
1272 {
1273   GDateTime *dt;
1274
1275   g_return_val_if_fail (datetime != NULL, NULL);
1276
1277   dt = g_date_time_copy (datetime);
1278   g_date_time_add_ymd (dt, 0, 0, days);
1279
1280   return dt;
1281 }
1282
1283 /**
1284  * g_date_time_add_hours:
1285  * @datetime: a #GDateTime
1286  * @hours: the number of hours to add
1287  *
1288  * Creates a copy of @datetime and adds the specified number of hours
1289  *
1290  * Return value: the newly created #GDateTime which should be freed with
1291  *   g_date_time_unref().
1292  *
1293  * Since: 2.26
1294  */
1295 GDateTime*
1296 g_date_time_add_hours (const GDateTime *datetime,
1297                        gint             hours)
1298 {
1299   GDateTime *dt;
1300
1301   g_return_val_if_fail (datetime != NULL, NULL);
1302
1303   dt = g_date_time_copy (datetime);
1304   g_date_time_add_usec (dt, (gint64) hours * USEC_PER_HOUR);
1305
1306   return dt;
1307 }
1308
1309 /**
1310  * g_date_time_add_seconds:
1311  * @datetime: a #GDateTime
1312  * @seconds: the number of seconds to add
1313  *
1314  * Creates a copy of @datetime and adds the specified number of seconds.
1315  *
1316  * Return value: the newly created #GDateTime which should be freed with
1317  *   g_date_time_unref().
1318  *
1319  * Since: 2.26
1320  */
1321 GDateTime*
1322 g_date_time_add_seconds (const GDateTime *datetime,
1323                          gint             seconds)
1324 {
1325   GDateTime *dt;
1326
1327   g_return_val_if_fail (datetime != NULL, NULL);
1328
1329   dt = g_date_time_copy (datetime);
1330   g_date_time_add_usec (dt, (gint64) seconds * USEC_PER_SECOND);
1331
1332   return dt;
1333 }
1334
1335 /**
1336  * g_date_time_add_milliseconds:
1337  * @datetime: a #GDateTime
1338  * @milliseconds: the number of milliseconds to add
1339  *
1340  * Creates a copy of @datetime adding the specified number of milliseconds.
1341  *
1342  * Return value: the newly created #GDateTime which should be freed with
1343  *   g_date_time_unref().
1344  *
1345  * Since: 2.26
1346  */
1347 GDateTime*
1348 g_date_time_add_milliseconds (const GDateTime *datetime,
1349                               gint             milliseconds)
1350 {
1351   GDateTime *dt;
1352
1353   g_return_val_if_fail (datetime != NULL, NULL);
1354
1355   dt = g_date_time_copy (datetime);
1356   g_date_time_add_usec (dt, (gint64) milliseconds * USEC_PER_MILLISECOND);
1357
1358   return dt;
1359 }
1360
1361 /**
1362  * g_date_time_add_minutes:
1363  * @datetime: a #GDateTime
1364  * @minutes: the number of minutes to add
1365  *
1366  * Creates a copy of @datetime adding the specified number of minutes.
1367  *
1368  * Return value: the newly created #GDateTime which should be freed with
1369  *   g_date_time_unref().
1370  *
1371  * Since: 2.26
1372  */
1373 GDateTime*
1374 g_date_time_add_minutes (const GDateTime *datetime,
1375                          gint             minutes)
1376 {
1377   GDateTime *dt;
1378
1379   g_return_val_if_fail (datetime != NULL, NULL);
1380
1381   dt = g_date_time_copy (datetime);
1382   g_date_time_add_usec (dt, (gint64) minutes * USEC_PER_MINUTE);
1383
1384   return dt;
1385 }
1386
1387 /**
1388  * g_date_time_add_full:
1389  * @datetime: a #GDateTime
1390  * @years: the number of years to add
1391  * @months: the number of months to add
1392  * @days: the number of days to add
1393  * @hours: the number of hours to add
1394  * @minutes: the number of minutes to add
1395  * @seconds: the number of seconds to add
1396  *
1397  * Creates a new #GDateTime adding the specified values to the current date and
1398  * time in @datetime.
1399  *
1400  * Return value: the newly created #GDateTime that should be freed with
1401  *   g_date_time_unref().
1402  *
1403  * Since: 2.26
1404  */
1405 GDateTime *
1406 g_date_time_add_full (const GDateTime *datetime,
1407                       gint             years,
1408                       gint             months,
1409                       gint             days,
1410                       gint             hours,
1411                       gint             minutes,
1412                       gint             seconds)
1413 {
1414   GDateTime *dt;
1415   gint64 usecs;
1416
1417   g_return_val_if_fail (datetime != NULL, NULL);
1418
1419   dt = g_date_time_copy (datetime);
1420
1421   /* add date */
1422   g_date_time_add_ymd (dt, years, months, days);
1423
1424   /* add time */
1425   usecs = (hours   * USEC_PER_HOUR)
1426         + (minutes * USEC_PER_MINUTE)
1427         + (seconds * USEC_PER_SECOND);
1428   g_date_time_add_usec (dt, usecs);
1429
1430   return dt;
1431 }
1432
1433 /**
1434  * g_date_time_compare:
1435  * @dt1: first #GDateTime to compare
1436  * @dt2: second #GDateTime to compare
1437  *
1438  * qsort()-style comparison for #GDateTime<!-- -->'s. Both #GDateTime<-- -->'s
1439  * must be non-%NULL.
1440  *
1441  * Return value: 0 for equal, less than zero if dt1 is less than dt2, greater
1442  *   than zero if dt2 is greator than dt1.
1443  *
1444  * Since: 2.26
1445  */
1446 gint
1447 g_date_time_compare (gconstpointer dt1,
1448                      gconstpointer dt2)
1449 {
1450   const GDateTime *a, *b;
1451
1452   a = dt1;
1453   b = dt2;
1454
1455   if ((a->days == b->days )&&
1456       (a->usec == b->usec))
1457     {
1458       return 0;
1459     }
1460   else if ((a->days > b->days) ||
1461            ((a->days == b->days) && a->usec > b->usec))
1462     {
1463       return 1;
1464     }
1465   else
1466     return -1;
1467 }
1468
1469 /**
1470  * g_date_time_day:
1471  * @datetime: a #GDateTime
1472  *
1473  * Creates a new #GDateTime at Midnight on the date represented by @datetime.
1474  *
1475  * Return value: the newly created #GDateTime which should be freed with
1476  *   g_date_time_unref().
1477  *
1478  * Since: 2.26
1479  */
1480 GDateTime*
1481 g_date_time_day (const GDateTime *datetime)
1482 {
1483   GDateTime *date;
1484
1485   g_return_val_if_fail (datetime != NULL, NULL);
1486
1487   date = g_date_time_copy (datetime);
1488   date->usec = 0;
1489
1490   return date;
1491 }
1492
1493 /**
1494  * g_date_time_difference:
1495  * @begin: a #GDateTime
1496  * @end: a #GDateTime
1497  *
1498  * Calculates the known difference in time between @begin and @end.
1499  *
1500  * Since the exact precision cannot always be known due to incomplete
1501  * historic information, an attempt is made to calculate the difference.
1502  *
1503  * Return value: the difference between the two #GDateTime, as a time
1504  *   span expressed in microseconds.
1505  *
1506  * Since: 2.26
1507  */
1508 GTimeSpan
1509 g_date_time_difference (const GDateTime *begin,
1510                         const GDateTime *end)
1511 {
1512   g_return_val_if_fail (begin != NULL, 0);
1513   g_return_val_if_fail (end != NULL, 0);
1514
1515   return (GTimeSpan) (((gint64) end->days - (gint64) begin->days)
1516       * USEC_PER_DAY) + ((gint64) end->usec - (gint64) begin->usec);
1517 }
1518
1519 /**
1520  * g_date_time_equal:
1521  * @dt1: a #GDateTime
1522  * @dt2: a #GDateTime
1523  *
1524  * Checks to see if @dt1 and @dt2 are equal.
1525  *
1526  * Equal here means that they represent the same moment after converting
1527  * them to the same timezone.
1528  *
1529  * Return value: %TRUE if @dt1 and @dt2 are equal
1530  *
1531  * Since: 2.26
1532  */
1533 gboolean
1534 g_date_time_equal (gconstpointer dt1,
1535                    gconstpointer dt2)
1536 {
1537   const GDateTime *a, *b;
1538   GDateTime *a_utc, *b_utc;
1539   gint64 a_epoch, b_epoch;
1540
1541   a = dt1;
1542   b = dt2;
1543
1544   a_utc = g_date_time_to_utc (a);
1545   b_utc = g_date_time_to_utc (b);
1546
1547   a_epoch = g_date_time_to_epoch (a_utc);
1548   b_epoch = g_date_time_to_epoch (b_utc);
1549
1550   g_date_time_unref (a_utc);
1551   g_date_time_unref (b_utc);
1552
1553   return a_epoch == b_epoch;
1554 }
1555
1556 /**
1557  * g_date_time_get_day_of_week:
1558  * @datetime: a #GDateTime
1559  *
1560  * Retrieves the day of the week represented by @datetime within the gregorian
1561  * calendar. 1 is Sunday, 2 is Monday, etc.
1562  *
1563  * Return value: the day of the week
1564  *
1565  * Since: 2.26
1566  */
1567 gint
1568 g_date_time_get_day_of_week (const GDateTime *datetime)
1569 {
1570   gint a, y, m,
1571        year  = 0,
1572        month = 0,
1573        day   = 0,
1574        dow;
1575
1576   g_return_val_if_fail (datetime != NULL, 0);
1577
1578   /*
1579    * See Calendar FAQ Section 2.6 for algorithm information
1580    * http://www.tondering.dk/claus/cal/calendar29.txt
1581    */
1582
1583   g_date_time_get_dmy (datetime, &day, &month, &year);
1584   a = (14 - month) / 12;
1585   y = year - a;
1586   m = month + (12 * a) - 2;
1587   dow = ((day + y + (y / 4) - (y / 100) + (y / 400) + (31 * m) / 12) % 7);
1588
1589   /* 1 is Monday and 7 is Sunday */
1590   return (dow == 0) ? 7 : dow;
1591 }
1592
1593 /**
1594  * g_date_time_get_day_of_month:
1595  * @datetime: a #GDateTime
1596  *
1597  * Retrieves the day of the month represented by @datetime in the gregorian
1598  * calendar.
1599  *
1600  * Return value: the day of the month
1601  *
1602  * Since: 2.26
1603  */
1604 gint
1605 g_date_time_get_day_of_month (const GDateTime *datetime)
1606 {
1607   gint           day_of_year,
1608                  i;
1609   const guint16 *days;
1610   guint16        last = 0;
1611
1612   g_return_val_if_fail (datetime != NULL, 0);
1613
1614   days = days_in_year[g_date_time_is_leap_year (datetime) ? 1 : 0];
1615   g_date_time_get_week_number (datetime, NULL, NULL, &day_of_year);
1616
1617   for (i = 1; i <= 12; i++)
1618     {
1619       if (days [i] >= day_of_year)
1620         return day_of_year - last;
1621       last = days [i];
1622     }
1623
1624   g_warn_if_reached ();
1625   return 0;
1626 }
1627
1628 /**
1629  * g_date_time_get_day_of_year:
1630  * @datetime: a #GDateTime
1631  *
1632  * Retrieves the day of the year represented by @datetime in the Gregorian
1633  * calendar.
1634  *
1635  * Return value: the day of the year
1636  *
1637  * Since: 2.26
1638  */
1639 gint
1640 g_date_time_get_day_of_year (const GDateTime *datetime)
1641 {
1642   gint doy = 0;
1643
1644   g_return_val_if_fail (datetime != NULL, 0);
1645
1646   g_date_time_get_week_number (datetime, NULL, NULL, &doy);
1647   return doy;
1648 }
1649
1650 /**
1651  * g_date_time_get_dmy:
1652  * @datetime: a #GDateTime.
1653  * @day: (out): the return location for the day of the month, or %NULL.
1654  * @month: (out): the return location for the monty of the year, or %NULL.
1655  * @year: (out): the return location for the gregorian year, or %NULL.
1656  *
1657  * Retrieves the Gregorian day, month, and year of a given #GDateTime.
1658  *
1659  * Since: 2.26
1660  */
1661 void
1662 g_date_time_get_dmy (const GDateTime *datetime,
1663                      gint            *day,
1664                      gint            *month,
1665                      gint            *year)
1666 {
1667   gint the_year;
1668   gint the_month;
1669   gint the_day;
1670   gint remaining_days;
1671   gint y100_cycles;
1672   gint y4_cycles;
1673   gint y1_cycles;
1674   gint preceding;
1675   gboolean leap;
1676
1677   g_return_if_fail (datetime != NULL);
1678
1679   remaining_days = datetime->days;
1680
1681   /*
1682    * We need to convert an offset in days to its year/month/day representation.
1683    * Leap years makes this a little trickier than it should be, so we use
1684    * 400, 100 and 4 years cycles here to get to the correct year.
1685    */
1686
1687   /* Our days offset starts sets 0001-01-01 as day 1, if it was day 0 our
1688    * math would be simpler, so let's do it */
1689   remaining_days--;
1690
1691   the_year = (remaining_days / DAYS_IN_400YEARS) * 400 + 1;
1692   remaining_days = remaining_days % DAYS_IN_400YEARS;
1693
1694   y100_cycles = remaining_days / DAYS_IN_100YEARS;
1695   remaining_days = remaining_days % DAYS_IN_100YEARS;
1696   the_year += y100_cycles * 100;
1697
1698   y4_cycles = remaining_days / DAYS_IN_4YEARS;
1699   remaining_days = remaining_days % DAYS_IN_4YEARS;
1700   the_year += y4_cycles * 4;
1701
1702   y1_cycles = remaining_days / 365;
1703   the_year += y1_cycles;
1704   remaining_days = remaining_days % 365;
1705
1706   if (y1_cycles == 4 || y100_cycles == 4) {
1707     g_assert (remaining_days == 0);
1708
1709     /* special case that indicates that the date is actually one year before,
1710      * in the 31th of December */
1711     the_year--;
1712     the_month = 12;
1713     the_day = 31;
1714     goto end;
1715   }
1716
1717   /* now get the month and the day */
1718   leap = y1_cycles == 3 && (y4_cycles != 24 || y100_cycles == 3);
1719
1720   g_assert (leap == GREGORIAN_LEAP(the_year));
1721
1722   the_month = (remaining_days + 50) >> 5;
1723   preceding = (days_in_year[0][the_month - 1] + (the_month > 2 && leap));
1724   if (preceding > remaining_days)
1725     {
1726       /* estimate is too large */
1727       the_month -= 1;
1728       preceding -= leap ? days_in_months[1][the_month]
1729                         : days_in_months[0][the_month];
1730     }
1731
1732   remaining_days -= preceding;
1733   g_assert(0 <= remaining_days);
1734
1735   the_day = remaining_days + 1;
1736
1737 end:
1738   if (year)
1739     *year = the_year;
1740   if (month)
1741     *month = the_month;
1742   if (day)
1743     *day = the_day;
1744 }
1745
1746 /**
1747  * g_date_time_get_hour:
1748  * @datetime: a #GDateTime
1749  *
1750  * Retrieves the hour of the day represented by @datetime
1751  *
1752  * Return value: the hour of the day
1753  *
1754  * Since: 2.26
1755  */
1756 gint
1757 g_date_time_get_hour (const GDateTime *datetime)
1758 {
1759   g_return_val_if_fail (datetime != NULL, 0);
1760
1761   return (datetime->usec / USEC_PER_HOUR);
1762 }
1763
1764 /**
1765  * g_date_time_get_julian:
1766  * @datetime: a #GDateTime
1767  * @period: (out): a location for the Julian period
1768  * @julian: (out): a location for the day in the Julian period
1769  * @hour: (out): a location for the hour of the day
1770  * @minute: (out): a location for the minute of the hour
1771  * @second: (out): a location for hte second of the minute
1772  *
1773  * Retrieves the Julian period, day, hour, minute, and second which @datetime
1774  * represents in the Julian calendar.
1775  *
1776  * Since: 2.26
1777  */
1778 void
1779 g_date_time_get_julian (const GDateTime *datetime,
1780                         gint            *period,
1781                         gint            *julian,
1782                         gint            *hour,
1783                         gint            *minute,
1784                         gint            *second)
1785 {
1786   gint y, m, d, a, b, c, e, f, j;
1787   g_return_if_fail (datetime != NULL);
1788
1789   g_date_time_get_dmy (datetime, &d, &m, &y);
1790
1791   /* FIXME: This is probably not optimal and doesn't handle the fact that the
1792    * julian calendar has its 0 hour on midday */
1793
1794   a = y / 100;
1795   b = a / 4;
1796   c = 2 - a + b;
1797   e = 365.25 * (y + 4716);
1798   f = 30.6001 * (m + 1);
1799   j = c + d + e + f - 1524;
1800
1801   if (period)
1802     *period = 0;
1803
1804   if (julian)
1805     *julian = j;
1806
1807   if (hour)
1808     *hour = (datetime->usec / USEC_PER_HOUR);
1809
1810   if (minute)
1811     *minute = (datetime->usec % USEC_PER_HOUR) / USEC_PER_MINUTE;
1812
1813   if (second)
1814     *second = (datetime->usec % USEC_PER_MINUTE) / USEC_PER_SECOND;
1815 }
1816
1817 /**
1818  * g_date_time_get_microsecond:
1819  * @datetime: a #GDateTime
1820  *
1821  * Retrieves the microsecond of the date represented by @datetime
1822  *
1823  * Return value: the microsecond of the second
1824  *
1825  * Since: 2.26
1826  */
1827 gint
1828 g_date_time_get_microsecond (const GDateTime *datetime)
1829 {
1830   g_return_val_if_fail (datetime != NULL, 0);
1831
1832   return (datetime->usec % USEC_PER_SECOND);
1833 }
1834
1835 /**
1836  * g_date_time_get_millisecond:
1837  * @datetime: a #GDateTime
1838  *
1839  * Retrieves the millisecond of the date represented by @datetime
1840  *
1841  * Return value: the millisecond of the second
1842  *
1843  * Since: 2.26
1844  */
1845 gint
1846 g_date_time_get_millisecond (const GDateTime *datetime)
1847 {
1848   g_return_val_if_fail (datetime != NULL, 0);
1849
1850   return (datetime->usec % USEC_PER_SECOND) / USEC_PER_MILLISECOND;
1851 }
1852
1853 /**
1854  * g_date_time_get_minute:
1855  * @datetime: a #GDateTime
1856  *
1857  * Retrieves the minute of the hour represented by @datetime
1858  *
1859  * Return value: the minute of the hour
1860  *
1861  * Since: 2.26
1862  */
1863 gint
1864 g_date_time_get_minute (const GDateTime *datetime)
1865 {
1866   g_return_val_if_fail (datetime != NULL, 0);
1867
1868   return (datetime->usec % USEC_PER_HOUR) / USEC_PER_MINUTE;
1869 }
1870
1871 /**
1872  * g_date_time_get_month:
1873  * @datetime: a #GDateTime
1874  *
1875  * Retrieves the month of the year represented by @datetime in the Gregorian
1876  * calendar.
1877  *
1878  * Return value: the month represented by @datetime
1879  *
1880  * Since: 2.26
1881  */
1882 gint
1883 g_date_time_get_month (const GDateTime *datetime)
1884 {
1885   gint month;
1886
1887   g_return_val_if_fail (datetime != NULL, 0);
1888
1889   g_date_time_get_dmy (datetime, NULL, &month, NULL);
1890
1891   return month;
1892 }
1893
1894 /**
1895  * g_date_time_get_second:
1896  * @datetime: a #GDateTime
1897  *
1898  * Retrieves the second of the minute represented by @datetime
1899  *
1900  * Return value: the second represented by @datetime
1901  *
1902  * Since: 2.26
1903  */
1904 gint
1905 g_date_time_get_second (const GDateTime *datetime)
1906 {
1907   g_return_val_if_fail (datetime != NULL, 0);
1908
1909   return (datetime->usec % USEC_PER_MINUTE) / USEC_PER_SECOND;
1910 }
1911
1912 /**
1913  * g_date_time_get_utc_offset:
1914  * @datetime: a #GDateTime
1915  *
1916  * Retrieves the offset from UTC that the local timezone specified by
1917  * @datetime represents.
1918  *
1919  * If @datetime represents UTC time, then the offset is zero.
1920  *
1921  * Return value: the offset, expressed as a time span expressed in
1922  *   microseconds.
1923  *
1924  * Since: 2.26
1925  */
1926 GTimeSpan
1927 g_date_time_get_utc_offset (const GDateTime *datetime)
1928 {
1929   gint offset = 0;
1930
1931   g_return_val_if_fail (datetime != NULL, 0);
1932
1933   if (datetime->tz != NULL)
1934     offset = g_time_zone_get_offset (datetime->tz);
1935
1936   return (gint64) offset * USEC_PER_SECOND;
1937 }
1938
1939 /**
1940  * g_date_time_get_timezone_name:
1941  * @datetime: a #GDateTime
1942  *
1943  * Retrieves the name of the timezone specified by @datetime, if any.
1944  *
1945  * Return value: (transfer none): the name of the timezone. The returned
1946  *   string is owned by the #GDateTime and it should not be modified or
1947  *   freed
1948  *
1949  * Since: 2.26
1950  */
1951 G_CONST_RETURN gchar *
1952 g_date_time_get_timezone_name (const GDateTime *datetime)
1953 {
1954   g_return_val_if_fail (datetime != NULL, NULL);
1955
1956   if (datetime->tz != NULL)
1957     return g_time_zone_get_name (datetime->tz);
1958
1959   return "UTC";
1960 }
1961
1962 /**
1963  * g_date_time_get_year:
1964  * @datetime: A #GDateTime
1965  *
1966  * Retrieves the year represented by @datetime in the Gregorian calendar.
1967  *
1968  * Return value: the year represented by @datetime
1969  *
1970  * Since: 2.26
1971  */
1972 gint
1973 g_date_time_get_year (const GDateTime *datetime)
1974 {
1975   gint year;
1976
1977   g_return_val_if_fail (datetime != NULL, 0);
1978
1979   g_date_time_get_dmy (datetime, NULL, NULL, &year);
1980
1981   return year;
1982 }
1983
1984 /**
1985  * g_date_time_hash:
1986  * @datetime: a #GDateTime
1987  *
1988  * Hashes @datetime into a #guint, suitable for use within #GHashTable.
1989  *
1990  * Return value: a #guint containing the hash
1991  *
1992  * Since: 2.26
1993  */
1994 guint
1995 g_date_time_hash (gconstpointer datetime)
1996 {
1997   return (guint) (*((guint64 *) datetime));
1998 }
1999
2000 /**
2001  * g_date_time_is_leap_year:
2002  * @datetime: a #GDateTime
2003  *
2004  * Determines if @datetime represents a date known to fall within
2005  * a leap year in the Gregorian calendar.
2006  *
2007  * Return value: %TRUE if @datetime is a leap year.
2008  *
2009  * Since: 2.26
2010  */
2011 gboolean
2012 g_date_time_is_leap_year (const GDateTime *datetime)
2013 {
2014   gint year;
2015
2016   g_return_val_if_fail (datetime != NULL, FALSE);
2017
2018   year = g_date_time_get_year (datetime);
2019
2020   return GREGORIAN_LEAP (year);
2021 }
2022
2023 /**
2024  * g_date_time_is_daylight_savings:
2025  * @datetime: a #GDateTime
2026  *
2027  * Determines if @datetime represents a date known to fall within daylight
2028  * savings time in the gregorian calendar.
2029  *
2030  * Return value: %TRUE if @datetime falls within daylight savings time.
2031  *
2032  * Since: 2.26
2033  */
2034 gboolean
2035 g_date_time_is_daylight_savings (const GDateTime *datetime)
2036 {
2037   g_return_val_if_fail (datetime != NULL, FALSE);
2038
2039   if (datetime->tz == NULL)
2040     return FALSE;
2041
2042   return datetime->tz->is_dst;
2043 }
2044
2045 /**
2046  * g_date_time_new_from_date:
2047  * @year: the Gregorian year
2048  * @month: the Gregorian month
2049  * @day: the day in the Gregorian month
2050  *
2051  * Creates a new #GDateTime using the specified date within the Gregorian
2052  * calendar.
2053  *
2054  * Return value: the newly created #GDateTime or %NULL if it is outside of
2055  *   the representable range.
2056  *
2057  * Since: 2.26
2058  */
2059 GDateTime *
2060 g_date_time_new_from_date (gint year,
2061                            gint month,
2062                            gint day)
2063 {
2064   GDateTime *dt;
2065
2066   g_return_val_if_fail (year > -4712 && year <= 3268, NULL);
2067   g_return_val_if_fail (month > 0 && month <= 12, NULL);
2068   g_return_val_if_fail (day > 0 && day <= 31, NULL);
2069
2070   dt = g_date_time_new ();
2071
2072   dt->days = date_to_proleptic_gregorian (year, month, day);
2073   dt->tz = g_time_zone_new_local ();
2074   g_time_zone_sink (dt->tz, dt);
2075
2076   return dt;
2077 }
2078
2079 /**
2080  * g_date_time_new_from_epoch:
2081  * @t: seconds from the Unix epoch
2082  *
2083  * Creates a new #GDateTime using the time since Jan 1, 1970 specified by @t.
2084  *
2085  * The timezone of the returned #GDateTime is the local time.
2086  *
2087  * Return value: the newly created #GDateTime
2088  *
2089  * Since: 2.26
2090  */
2091 GDateTime*
2092 g_date_time_new_from_epoch (gint64 t)
2093 {
2094   GDateTime *datetime;
2095   GTimeZone *tz;
2096   struct tm tm;
2097   time_t tt;
2098
2099   tt = (time_t) t;
2100   memset (&tm, 0, sizeof (tm));
2101
2102   /* XXX: GLib should probably have a wrapper for this */
2103 #ifdef HAVE_LOCALTIME_R
2104   localtime_r (&tt, &tm);
2105 #else
2106   {
2107     struct tm *ptm = localtime (&tt);
2108
2109     if (ptm == NULL)
2110       {
2111         /* Happens at least in Microsoft's C library if you pass a
2112          * negative time_t. Use 2000-01-01 as default date.
2113          */
2114 #ifndef G_DISABLE_CHECKS
2115         g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, "ptm != NULL");
2116 #endif
2117
2118         tm.tm_mon = 0;
2119         tm.tm_mday = 1;
2120         tm.tm_year = 100;
2121       }
2122     else
2123       memcpy ((void *) &tm, (void *) ptm, sizeof (struct tm));
2124   }
2125 #endif /* HAVE_LOCALTIME_R */
2126
2127   tz = g_time_zone_new_local ();
2128   datetime = g_date_time_new_full (tm.tm_year + 1900,
2129                                    tm.tm_mon  + 1,
2130                                    tm.tm_mday,
2131                                    tm.tm_hour,
2132                                    tm.tm_min,
2133                                    tm.tm_sec,
2134                                    tz);
2135   g_time_zone_free (tz);
2136
2137   return datetime;
2138 }
2139
2140 /**
2141  * g_date_time_new_from_timeval:
2142  * @tv: #GTimeVal
2143  *
2144  * Creates a new #GDateTime using the date and time specified by #GTimeVal.
2145  *
2146  * The timezone of the returned #GDateTime is UTC.
2147  *
2148  * Return value: the newly created #GDateTime
2149  *
2150  * Since: 2.26
2151  */
2152 GDateTime *
2153 g_date_time_new_from_timeval (GTimeVal *tv)
2154 {
2155   GDateTime *datetime;
2156
2157   g_return_val_if_fail (tv != NULL, NULL);
2158
2159   datetime = g_date_time_new_from_epoch (tv->tv_sec);
2160   datetime->usec += tv->tv_usec;
2161   datetime->tz = g_time_zone_new_local ();
2162   g_time_zone_sink (datetime->tz, datetime);
2163
2164   return datetime;
2165 }
2166
2167 /**
2168  * g_date_time_new_full:
2169  * @year: the Gregorian year
2170  * @month: the Gregorian month
2171  * @day: the day of the Gregorian month
2172  * @hour: the hour of the day
2173  * @minute: the minute of the hour
2174  * @second: the second of the minute, with eventual fractionary parts
2175  * @time_zone: (allow-none): a #GTimeZone, or %NULL for UTC
2176  *
2177  * Creates a new #GDateTime using the date and times in the Gregorian
2178  * calendar.
2179  *
2180  * If @time_zone is not %NULL, the #GDateTime will copy the #GTimeZone
2181  * and sink it, if floating.
2182  *
2183  * Return value: the newly created #GDateTime
2184  *
2185  * Since: 2.26
2186  */
2187 GDateTime *
2188 g_date_time_new_full (gint             year,
2189                       gint             month,
2190                       gint             day,
2191                       gint             hour,
2192                       gint             minute,
2193                       gdouble          second,
2194                       const GTimeZone *time_zone)
2195 {
2196   GDateTime *dt;
2197
2198   g_return_val_if_fail (hour >= 0 && hour < 24, NULL);
2199   g_return_val_if_fail (minute >= 0 && minute < 60, NULL);
2200   g_return_val_if_fail (second >= 0.0 && second <= 60.0, NULL);
2201
2202   dt = g_date_time_new ();
2203   dt->days = date_to_proleptic_gregorian (year, month, day);
2204   dt->usec = (hour   * USEC_PER_HOUR)
2205            + (minute * USEC_PER_MINUTE)
2206            + (second * USEC_PER_SECOND);
2207
2208   if (time_zone != NULL)
2209     {
2210       dt->tz = g_time_zone_copy (time_zone);
2211       g_time_zone_sink (dt->tz, dt);
2212     }
2213   else
2214     dt->tz = NULL;
2215
2216   return dt;
2217 }
2218
2219 /**
2220  * g_date_time_new_now:
2221  *
2222  * Creates a new #GDateTime representing the current date and time.
2223  *
2224  * Return value: the newly created #GDateTime which should be freed with
2225  *   g_date_time_unref().
2226  *
2227  * Since: 2.26
2228  */
2229 GDateTime*
2230 g_date_time_new_now (void)
2231 {
2232   GTimeVal tv;
2233
2234   g_get_current_time (&tv);
2235
2236   return g_date_time_new_from_timeval (&tv);
2237 }
2238
2239 /**
2240  * g_date_time_printf:
2241  * @datetime: A #GDateTime
2242  * @format: a valid UTF-8 string, containing the format for the #GDateTime
2243  *
2244  * Creates a newly allocated string representing the requested @format.
2245  *
2246  * The following format specifiers are supported:
2247  *
2248  * %%a  The abbreviated weekday name according to the current locale.
2249  * %%A  The full weekday name according to the current locale.
2250  * %%b  The abbreviated month name according to the current locale.
2251  * %%B  The full month name according to the current locale.
2252  * %%d  The day of the month as a decimal number (range 01 to 31).
2253  * %%e  The day of the month as a decimal number (range  1 to 31).
2254  * %%F  Equivalent to %Y-%m-%d (the ISO 8601 date format).
2255  * %%h  Equivalent to %b.
2256  * %%H  The hour as a decimal number using a 24-hour clock (range 00 to 23).
2257  * %%I  The hour as a decimal number using a 12-hour clock (range 01 to 12).
2258  * %%j  The day of the year as a decimal number (range 001 to 366).
2259  * %%k  The hour (24-hour clock) as a decimal number (range 0 to 23);
2260  *      single digits are preceded by a blank.
2261  * %%l  The hour (12-hour clock) as a decimal number (range 1 to 12);
2262  *      single digits are preceded by a blank.
2263  * %%m  The month as a decimal number (range 01 to 12).
2264  * %%M  The minute as a decimal number (range 00 to 59).
2265  * %%N  The micro-seconds as a decimal number.
2266  * %%p  Either "AM" or "PM" according to the given time  value, or the
2267  *      corresponding  strings  for the current locale.  Noon is treated
2268  *      as "PM" and midnight as "AM".
2269  * %%P  Like %%p but lowercase: "am" or "pm" or a corresponding string for
2270  *      the current locale.
2271  * %%r  The time in a.m. or p.m. notation.
2272  * %%R  The time in 24-hour notation (%H:%M).
2273  * %%s  The number of seconds since the Epoch, that is, since 1970-01-01
2274  *      00:00:00 UTC.
2275  * %%S  The second as a decimal number (range 00 to 60).
2276  * %%t  A tab character.
2277  * %%u  The day of the week as a decimal, range 1 to 7, Monday being 1.
2278  * %%W  The week number of the current year as a decimal number.
2279  * %%x  The preferred date representation for the current locale without
2280  *      the time.
2281  * %%X  The preferred date representation for the current locale without
2282  *      the date.
2283  * %%y  The year as a decimal number without the century.
2284  * %%Y  The year as a decimal number including the century.
2285  * %%z  The time-zone as hour offset from UTC
2286  * %%Z  The timezone or name or abbreviation
2287  * %%%  A literal %% character.
2288  *
2289  * Return value: a newly allocated string formatted to the requested format or
2290  *   %NULL in the case that there was an error.  The string should be freed
2291  *   with g_free().
2292  *
2293  * Since: 2.26
2294  */
2295 gchar *
2296 g_date_time_printf (const GDateTime *datetime,
2297                     const gchar     *format)
2298 {
2299   GString  *outstr;
2300   gchar    *tmp;
2301   gunichar  c;
2302   glong     utf8len;
2303   gboolean  in_mod;
2304
2305   g_return_val_if_fail (datetime != NULL, NULL);
2306   g_return_val_if_fail (format != NULL, NULL);
2307   g_return_val_if_fail (g_utf8_validate (format, -1, NULL), NULL);
2308
2309   outstr = g_string_sized_new (strlen (format) * 2);
2310   utf8len = g_utf8_strlen (format, -1);
2311   in_mod = FALSE;
2312
2313   for (; *format; format = g_utf8_next_char(format))
2314     {
2315       c = g_utf8_get_char (format);
2316
2317       switch (c)
2318         {
2319         case '%':
2320           if (!in_mod)
2321             {
2322               in_mod = TRUE;
2323               break;
2324             }
2325             /* Fall through */
2326         default:
2327           if (in_mod)
2328             {
2329               switch (c)
2330                 {
2331                 case 'a':
2332                   g_string_append (outstr, WEEKDAY_ABBR (datetime));
2333                   break;
2334                 case 'A':
2335                   g_string_append (outstr, WEEKDAY_FULL (datetime));
2336                   break;
2337                 case 'b':
2338                   g_string_append (outstr, MONTH_ABBR (datetime));
2339                   break;
2340                 case 'B':
2341                   g_string_append (outstr, MONTH_FULL (datetime));
2342                   break;
2343                 case 'd':
2344                   g_string_append_printf (outstr, "%02d", g_date_time_get_day_of_month (datetime));
2345                   break;
2346                 case 'e':
2347                   g_string_append_printf (outstr, "%2d", g_date_time_get_day_of_month (datetime));
2348                   break;
2349                 case 'F':
2350                   g_string_append_printf (outstr, "%d-%02d-%02d",
2351                                           g_date_time_get_year (datetime),
2352                                           g_date_time_get_month (datetime),
2353                                           g_date_time_get_day_of_month (datetime));
2354                   break;
2355                 case 'h':
2356                   g_string_append (outstr, MONTH_ABBR (datetime));
2357                   break;
2358                 case 'H':
2359                   g_string_append_printf (outstr, "%02d", g_date_time_get_hour (datetime));
2360                   break;
2361                 case 'I':
2362                   if (g_date_time_get_hour (datetime) == 0)
2363                     g_string_append (outstr, "12");
2364                   else
2365                     g_string_append_printf (outstr, "%02d", g_date_time_get_hour (datetime) % 12);
2366                   break;
2367                 case 'j':
2368                   g_string_append_printf (outstr, "%03d", g_date_time_get_day_of_year (datetime));
2369                   break;
2370                 case 'k':
2371                   g_string_append_printf (outstr, "%2d", g_date_time_get_hour (datetime));
2372                   break;
2373                 case 'l':
2374                   if (g_date_time_get_hour (datetime) == 0)
2375                     g_string_append (outstr, "12");
2376                   else
2377                     g_string_append_printf (outstr, "%2d", g_date_time_get_hour (datetime) % 12);
2378                   break;
2379                 case 'm':
2380                   g_string_append_printf (outstr, "%02d", g_date_time_get_month (datetime));
2381                   break;
2382                 case 'M':
2383                   g_string_append_printf (outstr, "%02d", g_date_time_get_minute (datetime));
2384                   break;
2385                 case 'N':
2386                   g_string_append_printf (outstr, "%"G_GUINT64_FORMAT, datetime->usec % USEC_PER_SECOND);
2387                   break;
2388                 case 'p':
2389                   g_string_append (outstr, GET_AMPM (datetime, FALSE));
2390                   break;
2391                 case 'P':
2392                   g_string_append (outstr, GET_AMPM (datetime, TRUE));
2393                   break;
2394                 case 'r':
2395                   {
2396                     gint hour = g_date_time_get_hour (datetime) % 12;
2397                     if (hour == 0)
2398                       hour = 12;
2399                     g_string_append_printf (outstr, "%02d:%02d:%02d %s",
2400                                             hour,
2401                                             g_date_time_get_minute (datetime),
2402                                             g_date_time_get_second (datetime),
2403                                             GET_AMPM (datetime, FALSE));
2404                   }
2405                   break;
2406                 case 'R':
2407                   g_string_append_printf (outstr, "%02d:%02d",
2408                                           g_date_time_get_hour (datetime),
2409                                           g_date_time_get_minute (datetime));
2410                   break;
2411                 case 's':
2412                   g_string_append_printf (outstr, "%" G_GINT64_FORMAT, g_date_time_to_epoch (datetime));
2413                   break;
2414                 case 'S':
2415                   g_string_append_printf (outstr, "%02d", g_date_time_get_second (datetime));
2416                   break;
2417                 case 't':
2418                   g_string_append_c (outstr, '\t');
2419                   break;
2420                 case 'u':
2421                   g_string_append_printf (outstr, "%d", g_date_time_get_day_of_week (datetime));
2422                   break;
2423                 case 'W':
2424                   g_string_append_printf (outstr, "%d", g_date_time_get_day_of_year (datetime) / 7);
2425                   break;
2426                 case 'x':
2427                   {
2428                     tmp = GET_PREFERRED_DATE (datetime);
2429                     g_string_append (outstr, tmp);
2430                     g_free (tmp);
2431                   }
2432                   break;
2433                 case 'X':
2434                   {
2435                     tmp = GET_PREFERRED_TIME (datetime);
2436                     g_string_append (outstr, tmp);
2437                     g_free (tmp);
2438                   }
2439                   break;
2440                 case 'y':
2441                   g_string_append_printf (outstr, "%02d", g_date_time_get_year (datetime) % 100);
2442                   break;
2443                 case 'Y':
2444                   g_string_append_printf (outstr, "%d", g_date_time_get_year (datetime));
2445                   break;
2446                 case 'z':
2447                   if (datetime->tz != NULL)
2448                     {
2449                       gint64 offset = g_date_time_get_utc_offset (datetime)
2450                                     / USEC_PER_SECOND;
2451
2452                       g_string_append_printf (outstr, "%c%02d%02d",
2453                                               offset >= 0 ? '+' : '-',
2454                                               (int) offset / 3600,
2455                                               (int) offset / 60 % 60);
2456                     }
2457                   else
2458                     g_string_append (outstr, "+0000");
2459                   break;
2460                 case 'Z':
2461                   if (datetime->tz != NULL)
2462                     g_string_append (outstr, g_date_time_get_timezone_name (datetime));
2463                   else
2464                     g_string_append (outstr, "UTC");
2465                   break;
2466                 case '%':
2467                   g_string_append_c (outstr, '%');
2468                   break;
2469                 case 'n':
2470                   g_string_append_c (outstr, '\n');
2471                   break;
2472                 default:
2473                   goto bad_format;
2474                 }
2475               in_mod = FALSE;
2476             }
2477           else
2478             g_string_append_unichar (outstr, c);
2479         }
2480     }
2481
2482   return g_string_free (outstr, FALSE);
2483
2484 bad_format:
2485   g_string_free (outstr, TRUE);
2486   return NULL;
2487 }
2488
2489 /**
2490  * g_date_time_to_local:
2491  * @datetime: a #GDateTime
2492  *
2493  * Creates a new #GDateTime with @datetime converted to local time.
2494  *
2495  * Return value: the newly created #GDateTime
2496  *
2497  * Since: 2.26
2498  */
2499 GDateTime *
2500 g_date_time_to_local (const GDateTime *datetime)
2501 {
2502   GDateTime *dt;
2503
2504   g_return_val_if_fail (datetime != NULL, NULL);
2505
2506   dt = g_date_time_copy (datetime);
2507   if (dt->tz == NULL)
2508     {
2509       dt->tz = g_time_zone_new_local ();
2510       if (dt->tz == NULL)
2511         return dt;
2512
2513       g_time_zone_sink (dt->tz, dt);
2514       g_date_time_add_usec (dt, dt->tz->offset * USEC_PER_SECOND);
2515     }
2516
2517   return dt;
2518 }
2519
2520 /**
2521  * g_date_time_to_epoch:
2522  * @datetime: a #GDateTime
2523  *
2524  * Converts @datetime into an integer representing seconds since the
2525  * Unix epoch
2526  *
2527  * Return value: @datetime as seconds since the Unix epoch
2528  *
2529  * Since: 2.26
2530  */
2531 gint64
2532 g_date_time_to_epoch (const GDateTime *datetime)
2533 {
2534   gint64 result;
2535
2536   g_return_val_if_fail (datetime != NULL, 0);
2537
2538   if (datetime->days <= 0)
2539     return G_MININT64;
2540
2541   result = (datetime->days - UNIX_EPOCH_START) * SEC_PER_DAY
2542          + datetime->usec / USEC_PER_SECOND
2543          - g_date_time_get_utc_offset (datetime) / USEC_PER_SECOND;
2544
2545   return result;
2546 }
2547
2548 /**
2549  * g_date_time_to_timeval:
2550  * @datetime: a #GDateTime
2551  * @tv: A #GTimeVal
2552  *
2553  * Converts @datetime into a #GTimeVal and stores the result into @timeval.
2554  *
2555  * Since: 2.26
2556  */
2557 void
2558 g_date_time_to_timeval (const GDateTime *datetime,
2559                         GTimeVal        *tv)
2560 {
2561   g_return_if_fail (datetime != NULL);
2562   g_return_if_fail (tv != NULL);
2563
2564   tv->tv_sec = g_date_time_to_epoch (datetime);
2565   tv->tv_usec = datetime->usec % USEC_PER_SECOND;
2566 }
2567
2568 /**
2569  * g_date_time_to_utc:
2570  * @datetime: a #GDateTime
2571  *
2572  * Creates a new #GDateTime that reprents @datetime in Universal coordinated
2573  * time.
2574  *
2575  * Return value: the newly created #GDateTime which should be freed with
2576  *   g_date_time_unref().
2577  *
2578  * Since: 2.26
2579  */
2580 GDateTime *
2581 g_date_time_to_utc (const GDateTime *datetime)
2582 {
2583   GDateTime *dt;
2584   GTimeSpan ts;
2585
2586   g_return_val_if_fail (datetime != NULL, NULL);
2587
2588   ts = g_date_time_get_utc_offset (datetime) * -1;
2589   dt = g_date_time_add (datetime, ts);
2590   if (dt->tz != NULL)
2591     {
2592       g_time_zone_free (dt->tz);
2593       dt->tz = NULL;
2594     }
2595
2596   return dt;
2597 }
2598
2599 /**
2600  * g_date_time_new_today:
2601  *
2602  * Createsa new #GDateTime that represents Midnight on the current day.
2603  *
2604  * Return value: the newly created #GDateTime which should be freed with
2605  *   g_date_time_unref().
2606  *
2607  * Since: 2.26
2608  */
2609 GDateTime*
2610 g_date_time_new_today (void)
2611 {
2612   GDateTime *dt;
2613
2614   dt = g_date_time_new_now ();
2615   dt->usec = 0;
2616
2617   return dt;
2618 }
2619
2620 /**
2621  * g_date_time_new_utc_now:
2622  *
2623  * Creates a new #GDateTime that represents the current instant in Universal
2624  * Coordinated Time (UTC).
2625  *
2626  * Return value: the newly created #GDateTime which should be freed with
2627  *   g_date_time_unref().
2628  *
2629  * Since: 2.26
2630  */
2631 GDateTime *
2632 g_date_time_new_utc_now (void)
2633 {
2634   GDateTime *utc, *now;
2635
2636   now = g_date_time_new_now ();
2637   utc = g_date_time_to_utc (now);
2638   g_date_time_unref (now);
2639
2640   return utc;
2641 }
2642
2643 /**
2644  * g_date_time_get_week_of_year:
2645  *
2646  * Returns the numeric week of the respective year.
2647  *
2648  * Return value: the week of the year
2649  *
2650  * Since: 2.26
2651  */
2652 gint
2653 g_date_time_get_week_of_year (const GDateTime *datetime)
2654 {
2655   gint weeknum;
2656
2657   g_return_val_if_fail (datetime != NULL, 0);
2658
2659   g_date_time_get_week_number (datetime, &weeknum, NULL, NULL);
2660
2661   return weeknum;
2662 }