Whitespace fixes
[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     {
1339       /* estimate is too large */
1340       the_month -= 1;
1341       preceding -= leap ? days_in_months[1][the_month]
1342                         : days_in_months[0][the_month];
1343     }
1344
1345   remaining_days -= preceding;
1346   g_assert(0 <= remaining_days);
1347
1348   the_day = remaining_days + 1;
1349
1350 end:
1351   if (year)
1352     *year = the_year;
1353   if (month)
1354     *month = the_month;
1355   if (day)
1356     *day = the_day;
1357 }
1358
1359 /**
1360  * g_date_time_get_hour:
1361  * @datetime: a #GDateTime
1362  *
1363  * Retrieves the hour of the day represented by @datetime
1364  *
1365  * Return value: the hour of the day
1366  *
1367  * Since: 2.26
1368  */
1369 gint
1370 g_date_time_get_hour (const GDateTime *datetime)
1371 {
1372   g_return_val_if_fail (datetime != NULL, 0);
1373
1374   return (datetime->usec / USEC_PER_HOUR);
1375 }
1376
1377 /**
1378  * g_date_time_get_julian:
1379  * @datetime: a #GDateTime
1380  * @period: (out): a location for the Julian period
1381  * @julian: (out): a location for the day in the Julian period
1382  * @hour: (out): a location for the hour of the day
1383  * @minute: (out): a location for the minute of the hour
1384  * @second: (out): a location for hte second of the minute
1385  *
1386  * Retrieves the Julian period, day, hour, minute, and second which @datetime
1387  * represents in the Julian calendar.
1388  *
1389  * Since: 2.26
1390  */
1391 void
1392 g_date_time_get_julian (const GDateTime *datetime,
1393                         gint            *period,
1394                         gint            *julian,
1395                         gint            *hour,
1396                         gint            *minute,
1397                         gint            *second)
1398 {
1399   gint y, m, d, a, b, c, e, f, j;
1400   g_return_if_fail (datetime != NULL);
1401
1402   g_date_time_get_dmy (datetime, &d, &m, &y);
1403
1404   /* FIXME: This is probably not optimal and doesn't handle the fact that the
1405    * julian calendar has its 0 hour on midday */
1406
1407   a = y / 100;
1408   b = a / 4;
1409   c = 2 - a + b;
1410   e = 365.25 * (y + 4716);
1411   f = 30.6001 * (m + 1);
1412   j = c + d + e + f - 1524;
1413
1414   if (period)
1415     *period = 0;
1416
1417   if (julian)
1418     *julian = j;
1419
1420   if (hour)
1421     *hour = (datetime->usec / USEC_PER_HOUR);
1422
1423   if (minute)
1424     *minute = (datetime->usec % USEC_PER_HOUR) / USEC_PER_MINUTE;
1425
1426   if (second)
1427     *second = (datetime->usec % USEC_PER_MINUTE) / USEC_PER_SECOND;
1428 }
1429
1430 /**
1431  * g_date_time_get_microsecond:
1432  * @datetime: a #GDateTime
1433  *
1434  * Retrieves the microsecond of the date represented by @datetime
1435  *
1436  * Return value: the microsecond of the second
1437  *
1438  * Since: 2.26
1439  */
1440 gint
1441 g_date_time_get_microsecond (const GDateTime *datetime)
1442 {
1443   g_return_val_if_fail (datetime != NULL, 0);
1444
1445   return (datetime->usec % USEC_PER_SECOND);
1446 }
1447
1448 /**
1449  * g_date_time_get_millisecond:
1450  * @datetime: a #GDateTime
1451  *
1452  * Retrieves the millisecond of the date represented by @datetime
1453  *
1454  * Return value: the millisecond of the second
1455  *
1456  * Since: 2.26
1457  */
1458 gint
1459 g_date_time_get_millisecond (const GDateTime *datetime)
1460 {
1461   g_return_val_if_fail (datetime != NULL, 0);
1462
1463   return (datetime->usec % USEC_PER_SECOND) / USEC_PER_MILLISECOND;
1464 }
1465
1466 /**
1467  * g_date_time_get_minute:
1468  * @datetime: a #GDateTime
1469  *
1470  * Retrieves the minute of the hour represented by @datetime
1471  *
1472  * Return value: the minute of the hour
1473  *
1474  * Since: 2.26
1475  */
1476 gint
1477 g_date_time_get_minute (const GDateTime *datetime)
1478 {
1479   g_return_val_if_fail (datetime != NULL, 0);
1480
1481   return (datetime->usec % USEC_PER_HOUR) / USEC_PER_MINUTE;
1482 }
1483
1484 /**
1485  * g_date_time_get_month:
1486  * @datetime: a #GDateTime
1487  *
1488  * Retrieves the month of the year represented by @datetime in the Gregorian
1489  * calendar.
1490  *
1491  * Return value: the month represented by @datetime
1492  *
1493  * Since: 2.26
1494  */
1495 gint
1496 g_date_time_get_month (const GDateTime *datetime)
1497 {
1498   gint month;
1499
1500   g_return_val_if_fail (datetime != NULL, 0);
1501
1502   g_date_time_get_dmy (datetime, NULL, &month, NULL);
1503
1504   return month;
1505 }
1506
1507 /**
1508  * g_date_time_get_second:
1509  * @datetime: a #GDateTime
1510  *
1511  * Retrieves the second of the minute represented by @datetime
1512  *
1513  * Return value: the second represented by @datetime
1514  *
1515  * Since: 2.26
1516  */
1517 gint
1518 g_date_time_get_second (const GDateTime *datetime)
1519 {
1520   g_return_val_if_fail (datetime != NULL, 0);
1521
1522   return (datetime->usec % USEC_PER_MINUTE) / USEC_PER_SECOND;
1523 }
1524
1525 /**
1526  * g_date_time_get_utc_offset:
1527  * @datetime: a #GDateTime
1528  *
1529  * Retrieves the offset from UTC that the local timezone specified by
1530  * @datetime represents.
1531  *
1532  * If @datetime represents UTC time, then the offset is zero.
1533  *
1534  * Return value: the offset, expressed as a time span expressed in
1535  *   microseconds.
1536  *
1537  * Since: 2.26
1538  */
1539 GTimeSpan
1540 g_date_time_get_utc_offset (const GDateTime *datetime)
1541 {
1542   gint offset = 0;
1543
1544   g_return_val_if_fail (datetime != NULL, 0);
1545
1546   if (datetime->tz != NULL)
1547     offset = datetime->tz->offset;
1548
1549   return (gint64) offset * USEC_PER_SECOND;
1550 }
1551
1552 /**
1553  * g_date_time_get_timezone_name:
1554  * @datetime: a #GDateTime
1555  *
1556  * Retrieves the Olson's database timezone name of the timezone specified
1557  * by @datetime.
1558  *
1559  * Return value: (transfer none): the name of the timezone. The returned
1560  *   string is owned by the #GDateTime and it should not be modified or
1561  *   freed
1562  *
1563  * Since: 2.26
1564  */
1565 G_CONST_RETURN gchar *
1566 g_date_time_get_timezone_name (const GDateTime *datetime)
1567 {
1568   g_return_val_if_fail (datetime != NULL, NULL);
1569
1570   if (datetime->tz != NULL)
1571     return datetime->tz->name;
1572
1573   return "UTC";
1574 }
1575
1576 /**
1577  * g_date_time_get_year:
1578  * @datetime: A #GDateTime
1579  *
1580  * Retrieves the year represented by @datetime in the Gregorian calendar.
1581  *
1582  * Return value: the year represented by @datetime
1583  *
1584  * Since: 2.26
1585  */
1586 gint
1587 g_date_time_get_year (const GDateTime *datetime)
1588 {
1589   gint year;
1590
1591   g_return_val_if_fail (datetime != NULL, 0);
1592
1593   g_date_time_get_dmy (datetime, NULL, NULL, &year);
1594
1595   return year;
1596 }
1597
1598 /**
1599  * g_date_time_hash:
1600  * @datetime: a #GDateTime
1601  *
1602  * Hashes @datetime into a #guint, suitable for use within #GHashTable.
1603  *
1604  * Return value: a #guint containing the hash
1605  *
1606  * Since: 2.26
1607  */
1608 guint
1609 g_date_time_hash (gconstpointer datetime)
1610 {
1611   return (guint) (*((guint64 *) datetime));
1612 }
1613
1614 /**
1615  * g_date_time_is_leap_year:
1616  * @datetime: a #GDateTime
1617  *
1618  * Determines if @datetime represents a date known to fall within
1619  * a leap year in the Gregorian calendar.
1620  *
1621  * Return value: %TRUE if @datetime is a leap year.
1622  *
1623  * Since: 2.26
1624  */
1625 gboolean
1626 g_date_time_is_leap_year (const GDateTime *datetime)
1627 {
1628   gint year;
1629
1630   g_return_val_if_fail (datetime != NULL, FALSE);
1631
1632   year = g_date_time_get_year (datetime);
1633
1634   return GREGORIAN_LEAP (year);
1635 }
1636
1637 /**
1638  * g_date_time_is_daylight_savings:
1639  * @datetime: a #GDateTime
1640  *
1641  * Determines if @datetime represents a date known to fall within daylight
1642  * savings time in the gregorian calendar.
1643  *
1644  * Return value: %TRUE if @datetime falls within daylight savings time.
1645  *
1646  * Since: 2.26
1647  */
1648 gboolean
1649 g_date_time_is_daylight_savings (const GDateTime *datetime)
1650 {
1651   g_return_val_if_fail (datetime != NULL, FALSE);
1652
1653   if (!datetime->tz)
1654     return FALSE;
1655
1656   return datetime->tz->is_dst;
1657 }
1658
1659 /**
1660  * g_date_time_new_from_date:
1661  * @year: the Gregorian year
1662  * @month: the Gregorian month
1663  * @day: the day in the Gregorian month
1664  *
1665  * Creates a new #GDateTime using the specified date within the Gregorian
1666  * calendar.
1667  *
1668  * Return value: the newly created #GDateTime or %NULL if it is outside of
1669  *   the representable range.
1670  *
1671  * Since: 2.26
1672  */
1673 GDateTime *
1674 g_date_time_new_from_date (gint year,
1675                            gint month,
1676                            gint day)
1677 {
1678   GDateTime *dt;
1679
1680   g_return_val_if_fail (year > -4712 && year <= 3268, NULL);
1681   g_return_val_if_fail (month > 0 && month <= 12, NULL);
1682   g_return_val_if_fail (day > 0 && day <= 31, NULL);
1683
1684   dt = g_date_time_new ();
1685
1686   dt->days = date_to_proleptic_gregorian (year, month, day);
1687   dt->tz = g_date_time_create_time_zone (dt, NULL);
1688
1689   return dt;
1690 }
1691
1692 /**
1693  * g_date_time_new_from_epoch:
1694  * @t: seconds from the Unix epoch
1695  *
1696  * Creates a new #GDateTime using the time since Jan 1, 1970 specified by @t.
1697  *
1698  * Return value: the newly created #GDateTime
1699  *
1700  * Since: 2.26
1701  */
1702 GDateTime*
1703 g_date_time_new_from_epoch (gint64 t) /* IN */
1704 {
1705   struct tm tm;
1706   time_t tt;
1707
1708   tt = (time_t) t;
1709   memset (&tm, 0, sizeof (tm));
1710
1711   /* XXX: GLib should probably have a wrapper for this */
1712 #ifdef HAVE_LOCALTIME_R
1713   localtime_r (&tt, &tm);
1714 #else
1715   {
1716     struct tm *ptm = localtime (&tt);
1717
1718     if (ptm == NULL)
1719       {
1720         /* Happens at least in Microsoft's C library if you pass a
1721          * negative time_t. Use 2000-01-01 as default date.
1722          */
1723 #ifndef G_DISABLE_CHECKS
1724         g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, "ptm != NULL");
1725 #endif
1726
1727         tm.tm_mon = 0;
1728         tm.tm_mday = 1;
1729         tm.tm_year = 100;
1730       }
1731     else
1732       memcpy ((void *) &tm, (void *) ptm, sizeof (struct tm));
1733   }
1734 #endif /* HAVE_LOCALTIME_R */
1735
1736   return g_date_time_new_full (tm.tm_year + 1900,
1737                                tm.tm_mon  + 1,
1738                                tm.tm_mday,
1739                                tm.tm_hour,
1740                                tm.tm_min,
1741                                tm.tm_sec,
1742                                NULL);
1743 }
1744
1745 /**
1746  * g_date_time_new_from_timeval:
1747  * @tv: #GTimeVal
1748  *
1749  * Creates a new #GDateTime using the date and time specified by #GTimeVal.
1750  *
1751  * Return value: the newly created #GDateTime
1752  *
1753  * Since: 2.26
1754  */
1755 GDateTime *
1756 g_date_time_new_from_timeval (GTimeVal *tv)
1757 {
1758   GDateTime *datetime;
1759
1760   g_return_val_if_fail (tv != NULL, NULL);
1761
1762   datetime = g_date_time_new_from_epoch (tv->tv_sec);
1763   datetime->usec += tv->tv_usec;
1764   datetime->tz = g_date_time_create_time_zone (datetime, NULL);
1765
1766   return datetime;
1767 }
1768
1769 /**
1770  * g_date_time_new_full:
1771  * @year: the Gregorian year
1772  * @month: the Gregorian month
1773  * @day: the day of the Gregorian month
1774  * @hour: the hour of the day
1775  * @minute: the minute of the hour
1776  * @second: the second of the minute
1777  * @time_zone: (allow-none): the Olson's database timezone name, or %NULL
1778  *   for local (e.g. America/New_York)
1779  *
1780  * Creates a new #GDateTime using the date and times in the Gregorian calendar.
1781  *
1782  * Return value: the newly created #GDateTime
1783  *
1784  * Since: 2.26
1785  */
1786 GDateTime *
1787 g_date_time_new_full (gint         year,
1788                       gint         month,
1789                       gint         day,
1790                       gint         hour,
1791                       gint         minute,
1792                       gint         second,
1793                       const gchar *time_zone)
1794 {
1795   GDateTime *dt;
1796
1797   g_return_val_if_fail (hour >= 0 && hour < 24, NULL);
1798   g_return_val_if_fail (minute >= 0 && minute < 60, NULL);
1799   g_return_val_if_fail (second >= 0 && second <= 60, NULL);
1800
1801   if ((dt = g_date_time_new_from_date (year, month, day)) == NULL)
1802     return NULL;
1803
1804   dt->usec = (hour   * USEC_PER_HOUR)
1805            + (minute * USEC_PER_MINUTE)
1806            + (second * USEC_PER_SECOND);
1807
1808   dt->tz = g_date_time_create_time_zone (dt, time_zone);
1809   if (time_zone != NULL && dt->tz == NULL)
1810     {
1811       /* timezone creation failed */
1812       g_date_time_unref (dt);
1813       dt = NULL;
1814     }
1815
1816   return dt;
1817 }
1818
1819 /**
1820  * g_date_time_new_now:
1821  *
1822  * Creates a new #GDateTime representing the current date and time.
1823  *
1824  * Return value: the newly created #GDateTime which should be freed with
1825  *   g_date_time_unref().
1826  *
1827  * Since: 2.26
1828  */
1829 GDateTime*
1830 g_date_time_new_now (void)
1831 {
1832   GTimeVal tv;
1833
1834   g_get_current_time (&tv);
1835
1836   return g_date_time_new_from_timeval (&tv);
1837 }
1838
1839 /**
1840  * g_date_time_printf:
1841  * @datetime: A #GDateTime
1842  * @format: a valid UTF-8 string, containing the format for the #GDateTime
1843  *
1844  * Creates a newly allocated string representing the requested @format.
1845  *
1846  * The following format specifiers are supported:
1847  *
1848  * %%a  The abbreviated weekday name according to the current locale.
1849  * %%A  The full weekday name according to the current locale.
1850  * %%b  The abbreviated month name according to the current locale.
1851  * %%B  The full month name according to the current locale.
1852  * %%d  The day of the month as a decimal number (range 01 to 31).
1853  * %%e  The day of the month as a decimal number (range  1 to 31).
1854  * %%F  Equivalent to %Y-%m-%d (the ISO 8601 date format).
1855  * %%h  Equivalent to %b.
1856  * %%H  The hour as a decimal number using a 24-hour clock (range 00 to 23).
1857  * %%I  The hour as a decimal number using a 12-hour clock (range 01 to 12).
1858  * %%j  The day of the year as a decimal number (range 001 to 366).
1859  * %%k  The hour (24-hour clock) as a decimal number (range 0 to 23);
1860  *      single digits are preceded by a blank.
1861  * %%l  The hour (12-hour clock) as a decimal number (range 1 to 12);
1862  *      single digits are preceded by a blank.
1863  * %%m  The month as a decimal number (range 01 to 12).
1864  * %%M  The minute as a decimal number (range 00 to 59).
1865  * %%N  The micro-seconds as a decimal number.
1866  * %%p  Either "AM" or "PM" according to the given time  value, or the
1867  *      corresponding  strings  for the current locale.  Noon is treated
1868  *      as "PM" and midnight as "AM".
1869  * %%P  Like %%p but lowercase: "am" or "pm" or a corresponding string for
1870  *      the current locale.
1871  * %%r  The time in a.m. or p.m. notation.
1872  * %%R  The time in 24-hour notation (%H:%M).
1873  * %%s  The number of seconds since the Epoch, that is, since 1970-01-01
1874  *      00:00:00 UTC.
1875  * %%S  The second as a decimal number (range 00 to 60).
1876  * %%t  A tab character.
1877  * %%u  The day of the week as a decimal, range 1 to 7, Monday being 1.
1878  * %%W  The week number of the current year as a decimal number.
1879  * %%x  The preferred date representation for the current locale without
1880  *      the time.
1881  * %%X  The preferred date representation for the current locale without
1882  *      the date.
1883  * %%y  The year as a decimal number without the century.
1884  * %%Y  The year as a decimal number including the century.
1885  * %%Z  Alphabetic time zone abbreviation (e.g. EDT).
1886  * %%%  A literal %% character.
1887  *
1888  * Return value: a newly allocated string formatted to the requested format or
1889  *   %NULL in the case that there was an error.  The string should be freed
1890  *   with g_free().
1891  *
1892  * Since: 2.26
1893  */
1894 gchar *
1895 g_date_time_printf (const GDateTime *datetime,
1896                     const gchar     *format)
1897 {
1898   GString  *outstr;
1899   gchar    *tmp;
1900   gunichar  c;
1901   glong     utf8len;
1902   gboolean  in_mod;
1903
1904   g_return_val_if_fail (datetime != NULL, NULL);
1905   g_return_val_if_fail (format != NULL, NULL);
1906   g_return_val_if_fail (g_utf8_validate (format, -1, NULL), NULL);
1907
1908   outstr = g_string_sized_new (strlen (format) * 2);
1909   utf8len = g_utf8_strlen (format, -1);
1910   in_mod = FALSE;
1911
1912   for (; *format; format = g_utf8_next_char(format))
1913     {
1914       c = g_utf8_get_char (format);
1915
1916       switch (c)
1917         {
1918         case '%':
1919           if (!in_mod)
1920             {
1921               in_mod = TRUE;
1922               break;
1923             }
1924             /* Fall through */
1925         default:
1926           if (in_mod)
1927             {
1928               switch (c)
1929                 {
1930                 case 'a':
1931                   g_string_append (outstr, WEEKDAY_ABBR (datetime));
1932                   break;
1933                 case 'A':
1934                   g_string_append (outstr, WEEKDAY_FULL (datetime));
1935                   break;
1936                 case 'b':
1937                   g_string_append (outstr, MONTH_ABBR (datetime));
1938                   break;
1939                 case 'B':
1940                   g_string_append (outstr, MONTH_FULL (datetime));
1941                   break;
1942                 case 'd':
1943                   g_string_append_printf (outstr, "%02d", g_date_time_get_day_of_month (datetime));
1944                   break;
1945                 case 'e':
1946                   g_string_append_printf (outstr, "%2d", g_date_time_get_day_of_month (datetime));
1947                   break;
1948                 case 'F':
1949                   g_string_append_printf (outstr, "%d-%02d-%02d",
1950                                           g_date_time_get_year (datetime),
1951                                           g_date_time_get_month (datetime),
1952                                           g_date_time_get_day_of_month (datetime));
1953                   break;
1954                 case 'h':
1955                   g_string_append (outstr, MONTH_ABBR (datetime));
1956                   break;
1957                 case 'H':
1958                   g_string_append_printf (outstr, "%02d", g_date_time_get_hour (datetime));
1959                   break;
1960                 case 'I':
1961                   if (g_date_time_get_hour (datetime) == 0)
1962                     g_string_append (outstr, "12");
1963                   else
1964                     g_string_append_printf (outstr, "%02d", g_date_time_get_hour (datetime) % 12);
1965                   break;
1966                 case 'j':
1967                   g_string_append_printf (outstr, "%03d", g_date_time_get_day_of_year (datetime));
1968                   break;
1969                 case 'k':
1970                   g_string_append_printf (outstr, "%2d", g_date_time_get_hour (datetime));
1971                   break;
1972                 case 'l':
1973                   if (g_date_time_get_hour (datetime) == 0)
1974                     g_string_append (outstr, "12");
1975                   else
1976                     g_string_append_printf (outstr, "%2d", g_date_time_get_hour (datetime) % 12);
1977                   break;
1978                 case 'm':
1979                   g_string_append_printf (outstr, "%02d", g_date_time_get_month (datetime));
1980                   break;
1981                 case 'M':
1982                   g_string_append_printf (outstr, "%02d", g_date_time_get_minute (datetime));
1983                   break;
1984                 case 'N':
1985                   g_string_append_printf (outstr, "%"G_GUINT64_FORMAT, datetime->usec % USEC_PER_SECOND);
1986                   break;
1987                 case 'p':
1988                   g_string_append (outstr, GET_AMPM (datetime, FALSE));
1989                   break;
1990                 case 'P':
1991                   g_string_append (outstr, GET_AMPM (datetime, TRUE));
1992                   break;
1993                 case 'r':
1994                   {
1995                     gint hour = g_date_time_get_hour (datetime) % 12;
1996                     if (hour == 0)
1997                       hour = 12;
1998                     g_string_append_printf (outstr, "%02d:%02d:%02d %s",
1999                                             hour,
2000                                             g_date_time_get_minute (datetime),
2001                                             g_date_time_get_second (datetime),
2002                                             GET_AMPM (datetime, FALSE));
2003                   }
2004                   break;
2005                 case 'R':
2006                   g_string_append_printf (outstr, "%02d:%02d",
2007                                           g_date_time_get_hour (datetime),
2008                                           g_date_time_get_minute (datetime));
2009                   break;
2010                 case 's':
2011                   g_string_append_printf (outstr, "%" G_GINT64_FORMAT, g_date_time_to_epoch (datetime));
2012                   break;
2013                 case 'S':
2014                   g_string_append_printf (outstr, "%02d", g_date_time_get_second (datetime));
2015                   break;
2016                 case 't':
2017                   g_string_append_c (outstr, '\t');
2018                   break;
2019                 case 'u':
2020                   g_string_append_printf (outstr, "%d", g_date_time_get_day_of_week (datetime));
2021                   break;
2022                 case 'W':
2023                   g_string_append_printf (outstr, "%d", g_date_time_get_day_of_year (datetime) / 7);
2024                   break;
2025                 case 'x':
2026                   {
2027                     tmp = GET_PREFERRED_DATE (datetime);
2028                     g_string_append (outstr, tmp);
2029                     g_free (tmp);
2030                   }
2031                   break;
2032                 case 'X':
2033                   {
2034                     tmp = GET_PREFERRED_TIME (datetime);
2035                     g_string_append (outstr, tmp);
2036                     g_free (tmp);
2037                   }
2038                   break;
2039                 case 'y':
2040                   g_string_append_printf (outstr, "%02d", g_date_time_get_year (datetime) % 100);
2041                   break;
2042                 case 'Y':
2043                   g_string_append_printf (outstr, "%d", g_date_time_get_year (datetime));
2044                   break;
2045                 case 'Z':
2046                   if (datetime->tz != NULL)
2047                     g_string_append_printf (outstr, "%s", datetime->tz->name);
2048                   else
2049                     g_string_append_printf (outstr, "UTC");
2050                   break;
2051                 case '%':
2052                   g_string_append_c (outstr, '%');
2053                   break;
2054                 case 'n':
2055                   g_string_append_c (outstr, '\n');
2056                   break;
2057                 default:
2058                   goto bad_format;
2059                 }
2060               in_mod = FALSE;
2061             }
2062           else
2063             g_string_append_unichar (outstr, c);
2064         }
2065     }
2066
2067   return g_string_free (outstr, FALSE);
2068
2069 bad_format:
2070   g_string_free (outstr, TRUE);
2071   return NULL;
2072 }
2073
2074 /**
2075  * g_date_time_ref:
2076  * @datetime: a #GDateTime
2077  *
2078  * Atomically increments the reference count of @datetime by one.
2079  *
2080  * Return value: the #GDateTime with the reference count increased
2081  *
2082  * Since: 2.26
2083  */
2084 GDateTime *
2085 g_date_time_ref (GDateTime *datetime)
2086 {
2087   g_return_val_if_fail (datetime != NULL, NULL);
2088   g_return_val_if_fail (datetime->ref_count > 0, NULL);
2089
2090   g_atomic_int_inc (&datetime->ref_count);
2091
2092   return datetime;
2093 }
2094
2095 /**
2096  * g_date_time_unref:
2097  * @datetime: a #GDateTime
2098  *
2099  * Atomically decrements the reference count of @datetime by one.
2100  *
2101  * When the reference count reaches zero, the resources allocated by
2102  * @datetime are freed
2103  *
2104  * Since: 2.26
2105  */
2106 void
2107 g_date_time_unref (GDateTime *datetime)
2108 {
2109   g_return_if_fail (datetime != NULL);
2110   g_return_if_fail (datetime->ref_count > 0);
2111
2112   if (g_atomic_int_dec_and_test (&datetime->ref_count))
2113     g_date_time_free (datetime);
2114 }
2115
2116 /**
2117  * g_date_time_to_local:
2118  * @datetime: a #GDateTime
2119  *
2120  * Creates a new #GDateTime with @datetime converted to local time.
2121  *
2122  * Return value: the newly created #GDateTime
2123  *
2124  * Since: 2.26
2125  */
2126 GDateTime *
2127 g_date_time_to_local (const GDateTime *datetime)
2128 {
2129   GDateTime *dt;
2130
2131   g_return_val_if_fail (datetime != NULL, NULL);
2132
2133   dt = g_date_time_copy (datetime);
2134   if (dt->tz == NULL)
2135     {
2136       dt->tz = g_date_time_create_time_zone (dt, NULL);
2137       if (dt->tz == NULL)
2138         return dt;
2139
2140       g_date_time_add_usec (dt, dt->tz->offset * USEC_PER_SECOND);
2141     }
2142
2143   return dt;
2144 }
2145
2146 /**
2147  * g_date_time_to_epoch:
2148  * @datetime: a #GDateTime
2149  *
2150  * Converts @datetime into an integer representing seconds since the
2151  * Unix epoch
2152  *
2153  * Return value: @datetime as seconds since the Unix epoch
2154  *
2155  * Since: 2.26
2156  */
2157 gint64
2158 g_date_time_to_epoch (const GDateTime *datetime)
2159 {
2160   gint64 result;
2161
2162   g_return_val_if_fail (datetime != NULL, 0);
2163
2164   if (datetime->days <= 0)
2165     return G_MININT64;
2166
2167   result = (datetime->days - UNIX_EPOCH_START) * SEC_PER_DAY
2168          + datetime->usec / USEC_PER_SECOND
2169          - g_date_time_get_utc_offset (datetime) / 1000000;
2170
2171   return result;
2172 }
2173
2174 /**
2175  * g_date_time_to_timeval:
2176  * @datetime: a #GDateTime
2177  * @tv: A #GTimeVal
2178  *
2179  * Converts @datetime into a #GTimeVal and stores the result into @timeval.
2180  *
2181  * Since: 2.26
2182  */
2183 void
2184 g_date_time_to_timeval (const GDateTime *datetime,
2185                         GTimeVal        *tv)
2186 {
2187   g_return_if_fail (datetime != NULL);
2188
2189   tv->tv_sec = 0;
2190   tv->tv_usec = 0;
2191
2192   tv->tv_sec = g_date_time_to_epoch (datetime);
2193   tv->tv_usec = datetime->usec % USEC_PER_SECOND;
2194 }
2195
2196 /**
2197  * g_date_time_to_utc:
2198  * @datetime: a #GDateTime
2199  *
2200  * Creates a new #GDateTime that reprents @datetime in Universal coordinated
2201  * time.
2202  *
2203  * Return value: the newly created #GDateTime which should be freed with
2204  *   g_date_time_unref().
2205  *
2206  * Since: 2.26
2207  */
2208 GDateTime *
2209 g_date_time_to_utc (const GDateTime *datetime)
2210 {
2211   GDateTime *dt;
2212   GTimeSpan  ts;
2213
2214   g_return_val_if_fail (datetime != NULL, NULL);
2215
2216   ts = g_date_time_get_utc_offset (datetime) * -1;
2217   dt = g_date_time_add (datetime, ts);
2218   dt->tz = NULL;
2219
2220   return dt;
2221 }
2222
2223 /**
2224  * g_date_time_new_today:
2225  *
2226  * Createsa new #GDateTime that represents Midnight on the current day.
2227  *
2228  * Return value: the newly created #GDateTime which should be freed with
2229  *   g_date_time_unref().
2230  *
2231  * Since: 2.26
2232  */
2233 GDateTime*
2234 g_date_time_new_today (void)
2235 {
2236   GDateTime *dt;
2237
2238   dt = g_date_time_new_now ();
2239   dt->usec = 0;
2240
2241   return dt;
2242 }
2243
2244 /**
2245  * g_date_time_new_utc_now:
2246  *
2247  * Creates a new #GDateTime that represents the current instant in Universal
2248  * Coordinated Time (UTC).
2249  *
2250  * Return value: the newly created #GDateTime which should be freed with
2251  *   g_date_time_unref().
2252  *
2253  * Since: 2.26
2254  */
2255 GDateTime *
2256 g_date_time_new_utc_now (void)
2257 {
2258   GDateTime *utc, *now;
2259
2260   now = g_date_time_new_now ();
2261   utc = g_date_time_to_utc (now);
2262   g_date_time_unref (now);
2263
2264   return utc;
2265 }
2266
2267 /**
2268  * g_date_time_get_week_of_year:
2269  *
2270  * Returns the numeric week of the respective year.
2271  *
2272  * Return value: the week of the year
2273  *
2274  * Since: 2.26
2275  */
2276 gint
2277 g_date_time_get_week_of_year (const GDateTime *datetime)
2278 {
2279   gint weeknum;
2280
2281   g_return_val_if_fail (datetime != NULL, 0);
2282
2283   g_date_time_get_week_number (datetime, &weeknum, NULL, NULL);
2284
2285   return weeknum;
2286 }