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