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