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