3 * Copyright (C) 2009-2010 Christian Hergert <chris@dronelabs.com>
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.
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.
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
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
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
33 * This document is provided "as is". No warranties are made as
51 #endif /* !G_OS_WIN32 */
55 #include "gdatetime.h"
60 * @short_description: A Date and Time structure
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.
66 * #GDateTime is an immutable object: once it has been created it cannot be
67 * modified further. All modifiers will create a new #GDateTime.
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.
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.
78 * #GDateTime is available since GLib 2.26.
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))
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))
91 #define ADD_DAYS(d,n) G_STMT_START { \
92 gint __day = d->julian + (n); \
95 d->period += -1 + (__day / DAYS_PER_PERIOD); \
96 d->period += DAYS_PER_PERIOD + (__day % DAYS_PER_PERIOD); \
98 else if (__day > DAYS_PER_PERIOD) \
100 d->period += (d->julian + (n)) / DAYS_PER_PERIOD; \
101 d->julian = (d->julian + (n)) % DAYS_PER_PERIOD; \
104 d->julian += n; } G_STMT_END
106 #define ADD_USEC(d,n) G_STMT_START { \
109 __usec = (d)->usec + (n); \
110 __days = __usec / USEC_PER_DAY; \
114 ADD_DAYS ((d), __days); \
116 d->usec = USEC_PER_DAY + (__usec % USEC_PER_DAY); \
118 d->usec = __usec % USEC_PER_DAY; } G_STMT_END
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")))
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)))
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)))
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")))
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")))
136 typedef struct _GTimeZone GTimeZone;
138 static const guint16 days_in_months[2][13] =
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 }
144 static const guint16 days_in_year[2][13] =
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 }
151 get_month_name (gint month)
156 return C_("GDateTime", "January");
158 return C_("GDateTime", "February");
160 return C_("GDateTime", "March");
162 return C_("GDateTime", "April");
164 return C_("GDateTime", "May");
166 return C_("GDateTime", "June");
168 return C_("GDateTime", "July");
170 return C_("GDateTime", "August");
172 return C_("GDateTime", "September");
174 return C_("GDateTime", "October");
176 return C_("GDateTime", "November");
178 return C_("GDateTime", "December");
181 g_warning ("Invalid month number %d", month);
188 get_month_name_abbr (gint month)
193 return C_("GDateTime", "Jan");
195 return C_("GDateTime", "Feb");
197 return C_("GDateTime", "Mar");
199 return C_("GDateTime", "Apr");
201 return C_("GDateTime", "May");
203 return C_("GDateTime", "Jun");
205 return C_("GDateTime", "Jul");
207 return C_("GDateTime", "Aug");
209 return C_("GDateTime", "Sep");
211 return C_("GDateTime", "Oct");
213 return C_("GDateTime", "Nov");
215 return C_("GDateTime", "Dec");
218 g_warning ("Invalid month number %d", month);
225 get_weekday_name (gint day)
230 return C_("GDateTime", "Monday");
232 return C_("GDateTime", "Tuesday");
234 return C_("GDateTime", "Wednesday");
236 return C_("GDateTime", "Thursday");
238 return C_("GDateTime", "Friday");
240 return C_("GDateTime", "Saturday");
242 return C_("GDateTime", "Sunday");
245 g_warning ("Invalid week day number %d", day);
252 get_weekday_name_abbr (gint day)
257 return C_("GDateTime", "Mon");
259 return C_("GDateTime", "Tue");
261 return C_("GDateTime", "Wed");
263 return C_("GDateTime", "Thu");
265 return C_("GDateTime", "Fri");
267 return C_("GDateTime", "Sat");
269 return C_("GDateTime", "Sun");
272 g_warning ("Invalid week day number %d", day);
280 /* Julian Period, 0 is Initial Epoch */
283 /* Day within Julian Period */
286 /* Microsecond timekeeping within Day */
291 /* TimeZone information, NULL is UTC */
294 volatile gint ref_count;
299 /* TZ abbreviation (e.g. PST) */
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
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
321 get_tzdata_path (const gchar *tz_name)
327 const gchar *tz_dir = g_getenv ("TZDIR");
330 retval = g_build_filename (tz_dir, tz_name, NULL);
332 retval = g_build_filename ("/", "usr", "share", ZONEINFO_DIR, tz_name, NULL);
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
343 * in any case, this path should resolve correctly.
345 retval = g_build_filename ("/", "etc", "localtime", NULL);
352 * Parses tzdata database times to get timezone info.
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
361 parse_tzdata (const gchar *tzname,
368 gchar *filename, *contents;
370 guint32 timecnt, typecnt;
371 gint transitions_size, ttinfo_map_size;
372 guint8 *ttinfo_map, *ttinfos;
373 gint start_transition = -1;
374 guint32 *transitions;
381 filename = get_tzdata_path (tzname);
383 /* XXX: should we be caching this in memory for faster access?
384 * and if so, how do we expire the cache?
387 if (!g_file_get_contents (filename, &contents, &length, &error))
395 if (length < TZ_HEADER_SIZE ||
396 (strncmp (contents, TZ_MAGIC, TZ_MAGIC_LEN) != 0))
402 timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
403 typecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TYPECNT_OFFSET));
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);
412 * Find the first transition that contains the 'start' time
414 for (i = 1; i < timecnt && start_transition == -1; i++)
416 gint32 transition_time = GINT32_FROM_BE (transitions[i]);
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 */
424 off = *(gint32 *)(ttinfos + ttinfo_map[i] * TZ_TTINFO_SIZE +
425 TZ_TTINFO_GMTOFF_OFFSET);
426 off = GINT32_FROM_BE (off);
428 transition_time += off;
431 if (transition_time > start)
433 start_transition = ttinfo_map[i - 1];
438 if (start_transition == -1)
441 start_transition = ttinfo_map[timecnt - 1];
443 start_transition = 0;
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);
456 *_name = g_strdup ((gchar*) (ttinfos + TZ_TTINFO_SIZE * typecnt + name_offset));
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
475 * Creates a new timezone
478 g_time_zone_new_from_epoch (const gchar *tzname,
482 GTimeZone *tz = NULL;
487 if (parse_tzdata (tzname, epoch, is_utc, &is_dst, &offset, &name))
489 tz = g_slice_new (GTimeZone);
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)
505 g_date_time_secs_offset (GDateTime * dt)
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);
517 /* FIXME this is an approximation */
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;
532 * g_date_time_create_time_zone:
534 * @tzname: the name of the timezone
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.
540 * Return value: a newly created #GTimeZone
543 g_date_time_create_time_zone (GDateTime *dt,
548 secs = g_date_time_secs_offset (dt);
550 return g_time_zone_new_from_epoch (tzname, secs, FALSE);
554 g_date_time_new (void)
558 datetime = g_slice_new0 (GDateTime);
559 datetime->ref_count = 1;
565 g_time_zone_copy (const GTimeZone *timezone)
569 if (G_UNLIKELY (timezone == NULL))
572 tz = g_slice_new (GTimeZone);
573 memcpy (tz, timezone, sizeof (GTimeZone));
575 tz->name = g_strdup (timezone->name);
581 g_time_zone_free (GTimeZone *timezone)
583 if (G_LIKELY (timezone != NULL))
585 g_free (timezone->name);
586 g_slice_free (GTimeZone, timezone);
591 g_date_time_free (GDateTime *datetime)
593 if (G_UNLIKELY (datetime == NULL))
597 g_time_zone_free (datetime->tz);
599 g_slice_free (GDateTime, datetime);
603 g_date_time_get_week_number (const GDateTime *datetime,
608 gint a, b, c, d, e, f, g, n, s, month, day, year;
610 g_date_time_get_dmy (datetime, &day, &month, &year);
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);
619 f = day - 1 + (31 * (month - 1));
624 b = (a / 4) - (a / 100) + (a / 400);
625 c = ((a - 1) / 4) - ((a - 1) / 100) + ((a - 1) / 400);
628 f = day + (((153 * (month - 3)) + 2) / 5) + 58 + s;
638 *week_number = 53 - ((g - s) / 5);
639 else if (n > 364 + s)
642 *week_number = (n / 7) + 1;
646 *day_of_week = d + 1;
649 *day_of_year = f + 1;
654 * @datetime: a #GDateTime
655 * @timespan: a #GTimeSpan
657 * Creates a copy of @datetime and adds the specified timespan to the copy.
659 * Return value: the newly created #GDateTime which should be freed with
660 * g_date_time_unref().
665 g_date_time_add (const GDateTime *datetime,
670 g_return_val_if_fail (datetime != NULL, NULL);
672 dt = g_date_time_copy (datetime);
673 ADD_USEC (dt, timespan);
679 * g_date_time_add_years:
680 * @datetime: a #GDateTime
681 * @years: the number of years
683 * Creates a copy of @datetime and adds the specified number of years to the
686 * Return value: the newly created #GDateTime which should be freed with
687 * g_date_time_unref().
692 g_date_time_add_years (const GDateTime *datetime,
698 g_return_val_if_fail (datetime != NULL, NULL);
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)
708 dt = g_date_time_new_from_date (g_date_time_get_year (datetime) + years,
709 g_date_time_get_month (datetime),
711 dt->usec = datetime->usec;
717 * g_date_time_add_months:
718 * @datetime: a #GDateTime
719 * @months: the number of months
721 * Creates a copy of @datetime and adds the specified number of months to the
724 * Return value: the newly created #GDateTime which should be freed with
725 * g_date_time_unref().
730 g_date_time_add_months (const GDateTime *datetime,
741 g_return_val_if_fail (datetime != NULL, NULL);
742 g_return_val_if_fail (months != 0, NULL);
744 month = g_date_time_get_month (datetime);
745 year = g_date_time_get_year (datetime);
746 a = months > 0 ? 1 : -1;
748 for (i = 0; i < ABS (months); i++)
763 day = g_date_time_get_day_of_month (datetime);
764 days = days_in_months [GREGORIAN_LEAP (year) ? 1 : 0];
766 if (days[month] < day)
769 dt = g_date_time_new_from_date (year, month, day);
770 dt->usec = datetime->usec;
776 * g_date_time_add_weeks:
777 * @datetime: a #GDateTime
778 * @weeks: the number of weeks
780 * Creates a copy of @datetime and adds the specified number of weeks to the
783 * Return value: the newly created #GDateTime which should be freed with
784 * g_date_time_unref().
789 g_date_time_add_weeks (const GDateTime *datetime,
792 g_return_val_if_fail (datetime != NULL, NULL);
794 return g_date_time_add_days (datetime, weeks * 7);
798 * g_date_time_add_days:
799 * @datetime: a #GDateTime
800 * @days: the number of days
802 * Creates a copy of @datetime and adds the specified number of days to the
805 * Return value: the newly created #GDateTime which should be freed with
806 * g_date_time_unref().
811 g_date_time_add_days (const GDateTime *datetime,
816 g_return_val_if_fail (datetime != NULL, NULL);
818 dt = g_date_time_copy (datetime);
825 * g_date_time_add_hours:
826 * @datetime: a #GDateTime
827 * @hours: the number of hours to add
829 * Creates a copy of @datetime and adds the specified number of hours
831 * Return value: the newly created #GDateTime which should be freed with
832 * g_date_time_unref().
837 g_date_time_add_hours (const GDateTime *datetime,
843 g_return_val_if_fail (datetime != NULL, NULL);
845 usec = hours * USEC_PER_HOUR;
846 dt = g_date_time_copy (datetime);
853 * g_date_time_add_seconds:
854 * @datetime: a #GDateTime
855 * @seconds: the number of seconds to add
857 * Creates a copy of @datetime and adds the specified number of seconds.
859 * Return value: the newly created #GDateTime which should be freed with
860 * g_date_time_unref().
865 g_date_time_add_seconds (const GDateTime *datetime,
871 g_return_val_if_fail (datetime != NULL, NULL);
873 dt = g_date_time_copy (datetime);
874 usec = seconds * USEC_PER_SECOND;
881 * g_date_time_add_milliseconds:
882 * @datetime: a #GDateTime
883 * @milliseconds: the number of milliseconds to add
885 * Creates a copy of @datetime adding the specified number of milliseconds.
887 * Return value: the newly created #GDateTime which should be freed with
888 * g_date_time_unref().
893 g_date_time_add_milliseconds (const GDateTime *datetime,
899 g_return_val_if_fail (datetime != NULL, NULL);
901 dt = g_date_time_copy (datetime);
902 usec = milliseconds * USEC_PER_MILLISECOND;
909 * g_date_time_add_minutes:
910 * @datetime: a #GDateTime
911 * @minutes: the number of minutes to add
913 * Creates a copy of @datetime adding the specified number of minutes.
915 * Return value: the newly created #GDateTime which should be freed with
916 * g_date_time_unref().
921 g_date_time_add_minutes (const GDateTime *datetime,
926 g_return_val_if_fail (datetime != NULL, NULL);
928 dt = g_date_time_copy (datetime);
929 ADD_USEC (dt, minutes * USEC_PER_MINUTE);
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
944 * Creates a new #GDateTime adding the specified values to the current date and
947 * Return value: the newly created #GDateTime that should be freed with
948 * g_date_time_unref().
953 g_date_time_add_full (const GDateTime *datetime,
963 g_return_val_if_fail (datetime != NULL, NULL);
965 dt = g_date_time_add_years (datetime, years);
968 dt = g_date_time_add_months (tmp, months);
969 g_date_time_unref (tmp);
972 dt = g_date_time_add_days (tmp, days);
973 g_date_time_unref (tmp);
976 dt = g_date_time_add_hours (tmp, hours);
977 g_date_time_unref (tmp);
980 dt = g_date_time_add_minutes (tmp, minutes);
981 g_date_time_unref (tmp);
984 dt = g_date_time_add_seconds (tmp, seconds);
985 g_date_time_unref (tmp);
991 * g_date_time_compare:
992 * @dt1: first #GDateTime to compare
993 * @dt2: second #GDateTime to compare
995 * qsort()-style comparison for #GDateTime<!-- -->'s. Both #GDateTime<-- -->'s
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.
1004 g_date_time_compare (gconstpointer dt1,
1007 const GDateTime *a, *b;
1012 if ((a->period == b->period) &&
1013 (a->julian == b->julian) &&
1014 (a->usec == b->usec))
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))
1030 * @datetime: a #GDateTime
1032 * Creates a copy of @datetime.
1034 * Return value: the newly created #GDateTime which should be freed with
1035 * g_date_time_unref().
1040 g_date_time_copy (const GDateTime *datetime)
1044 g_return_val_if_fail (datetime != NULL, NULL);
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);
1057 * @datetime: a #GDateTime
1059 * Creates a new #GDateTime at Midnight on the date represented by @datetime.
1061 * Return value: the newly created #GDateTime which should be freed with
1062 * g_date_time_unref().
1067 g_date_time_day (const GDateTime *datetime)
1071 g_return_val_if_fail (datetime != NULL, NULL);
1073 date = g_date_time_copy (datetime);
1080 * g_date_time_difference:
1081 * @begin: a #GDateTime
1082 * @end: a #GDateTime
1084 * Calculates the known difference in time between @begin and @end.
1086 * Since the exact precision cannot always be known due to incomplete
1087 * historic information, an attempt is made to calculate the difference.
1089 * Return value: the difference between the two #GDateTime, as a time
1090 * span expressed in microseconds.
1095 g_date_time_difference (const GDateTime *begin,
1096 const GDateTime *end)
1098 g_return_val_if_fail (begin != NULL, 0);
1099 g_return_val_if_fail (end != NULL, 0);
1101 if (begin->period != 0 || end->period != 0)
1103 g_warning ("GDateTime only supports the current Julian period");
1107 return ((end->julian - begin->julian) * USEC_PER_DAY) + (end->usec - begin->usec);
1111 * g_date_time_equal:
1112 * @dt1: a #GDateTime
1113 * @dt2: a #GDateTime
1115 * Checks to see if @dt1 and @dt2 are equal.
1117 * Equal here means that they represent the same moment after converting
1118 * them to the same timezone.
1120 * Return value: %TRUE if @dt1 and @dt2 are equal
1125 g_date_time_equal (gconstpointer dt1,
1128 const GDateTime *a, *b;
1129 GDateTime *a_utc, *b_utc;
1130 gint64 a_epoch, b_epoch;
1135 a_utc = g_date_time_to_utc ((GDateTime *) a);
1136 b_utc = g_date_time_to_utc ((GDateTime *) b);
1138 a_epoch = g_date_time_to_epoch (a_utc);
1139 b_epoch = g_date_time_to_epoch (b_utc);
1141 g_date_time_unref (a_utc);
1142 g_date_time_unref (b_utc);
1144 return a_epoch == b_epoch;
1148 * g_date_time_get_day_of_week:
1149 * @datetime: a #GDateTime
1151 * Retrieves the day of the week represented by @datetime within the gregorian
1152 * calendar. 1 is Sunday, 2 is Monday, etc.
1154 * Return value: the day of the week
1159 g_date_time_get_day_of_week (const GDateTime *datetime)
1167 g_return_val_if_fail (datetime != NULL, 0);
1170 * See Calendar FAQ Section 2.6 for algorithm information
1171 * http://www.tondering.dk/claus/cal/calendar29.txt
1174 g_date_time_get_dmy (datetime, &day, &month, &year);
1175 a = (14 - month) / 12;
1177 m = month + (12 * a) - 2;
1178 dow = ((day + y + (y / 4) - (y / 100) + (y / 400) + (31 * m) / 12) % 7);
1180 /* 1 is Monday and 7 is Sunday */
1181 return (dow == 0) ? 7 : dow;
1185 * g_date_time_get_day_of_month:
1186 * @datetime: a #GDateTime
1188 * Retrieves the day of the month represented by @datetime in the gregorian
1191 * Return value: the day of the month
1196 g_date_time_get_day_of_month (const GDateTime *datetime)
1200 const guint16 *days;
1203 g_return_val_if_fail (datetime != NULL, 0);
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);
1208 for (i = 1; i <= 12; i++)
1210 if (days [i] >= day_of_year)
1211 return day_of_year - last;
1215 g_warn_if_reached ();
1220 * g_date_time_get_day_of_year:
1221 * @datetime: a #GDateTime
1223 * Retrieves the day of the year represented by @datetime in the Gregorian
1226 * Return value: the day of the year
1231 g_date_time_get_day_of_year (const GDateTime *datetime)
1235 g_return_val_if_fail (datetime != NULL, 0);
1237 g_date_time_get_week_number (datetime, NULL, NULL, &doy);
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.
1248 * Retrieves the Gregorian day, month, and year of a given #GDateTime.
1253 g_date_time_get_dmy (const GDateTime *datetime,
1258 gint a, b, c, d, e, m;
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;
1268 *day = e - (((153 * m) + 2) / 5) + 1;
1271 *month = m + 3 - (12 * (m / 10));
1274 *year = (b * 100) + d - 4800 + (m / 10);
1278 * g_date_time_get_hour:
1279 * @datetime: a #GDateTime
1281 * Retrieves the hour of the day represented by @datetime
1283 * Return value: the hour of the day
1288 g_date_time_get_hour (const GDateTime *datetime)
1290 g_return_val_if_fail (datetime != NULL, 0);
1292 return (datetime->usec / USEC_PER_HOUR);
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
1304 * Retrieves the Julian period, day, hour, minute, and second which @datetime
1305 * represents in the Julian calendar.
1310 g_date_time_get_julian (const GDateTime *datetime,
1317 g_return_if_fail (datetime != NULL);
1320 *period = datetime->period;
1323 *julian = datetime->julian;
1326 *hour = (datetime->usec / USEC_PER_HOUR);
1329 *minute = (datetime->usec % USEC_PER_HOUR) / USEC_PER_MINUTE;
1332 *second = (datetime->usec % USEC_PER_MINUTE) / USEC_PER_SECOND;
1336 * g_date_time_get_microsecond:
1337 * @datetime: a #GDateTime
1339 * Retrieves the microsecond of the date represented by @datetime
1341 * Return value: the microsecond of the second
1346 g_date_time_get_microsecond (const GDateTime *datetime)
1348 g_return_val_if_fail (datetime != NULL, 0);
1350 return (datetime->usec % USEC_PER_SECOND);
1354 * g_date_time_get_millisecond:
1355 * @datetime: a #GDateTime
1357 * Retrieves the millisecond of the date represented by @datetime
1359 * Return value: the millisecond of the second
1364 g_date_time_get_millisecond (const GDateTime *datetime)
1366 g_return_val_if_fail (datetime != NULL, 0);
1368 return (datetime->usec % USEC_PER_SECOND) / USEC_PER_MILLISECOND;
1372 * g_date_time_get_minute:
1373 * @datetime: a #GDateTime
1375 * Retrieves the minute of the hour represented by @datetime
1377 * Return value: the minute of the hour
1382 g_date_time_get_minute (const GDateTime *datetime)
1384 g_return_val_if_fail (datetime != NULL, 0);
1386 return (datetime->usec % USEC_PER_HOUR) / USEC_PER_MINUTE;
1390 * g_date_time_get_month:
1391 * @datetime: a #GDateTime
1393 * Retrieves the month of the year represented by @datetime in the Gregorian
1396 * Return value: the month represented by @datetime
1401 g_date_time_get_month (const GDateTime *datetime)
1405 g_return_val_if_fail (datetime != NULL, 0);
1407 g_date_time_get_dmy (datetime, NULL, &month, NULL);
1413 * g_date_time_get_second:
1414 * @datetime: a #GDateTime
1416 * Retrieves the second of the minute represented by @datetime
1418 * Return value: the second represented by @datetime
1423 g_date_time_get_second (const GDateTime *datetime)
1425 g_return_val_if_fail (datetime != NULL, 0);
1427 return (datetime->usec % USEC_PER_MINUTE) / USEC_PER_SECOND;
1431 * g_date_time_get_utc_offset:
1432 * @datetime: a #GDateTime
1434 * Retrieves the offset from UTC that the local timezone specified by
1435 * @datetime represents.
1437 * If @datetime represents UTC time, then the offset is zero.
1439 * Return value: the offset, expressed as a time span expressed in
1445 g_date_time_get_utc_offset (const GDateTime *datetime)
1449 g_return_val_if_fail (datetime != NULL, 0);
1451 if (datetime->tz != NULL)
1452 offset = datetime->tz->offset;
1454 return (gint64) offset * USEC_PER_SECOND;
1458 * g_date_time_get_timezone_name:
1459 * @datetime: a #GDateTime
1461 * Retrieves the Olson's database timezone name of the timezone specified
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
1470 G_CONST_RETURN gchar *
1471 g_date_time_get_timezone_name (const GDateTime *datetime)
1473 g_return_val_if_fail (datetime != NULL, NULL);
1475 if (datetime->tz != NULL)
1476 return datetime->tz->name;
1482 * g_date_time_get_year:
1483 * @datetime: A #GDateTime
1485 * Retrieves the year represented by @datetime in the Gregorian calendar.
1487 * Return value: the year represented by @datetime
1492 g_date_time_get_year (const GDateTime *datetime)
1496 g_return_val_if_fail (datetime != NULL, 0);
1498 g_date_time_get_dmy (datetime, NULL, NULL, &year);
1505 * @datetime: a #GDateTime
1507 * Hashes @datetime into a #guint, suitable for use within #GHashTable.
1509 * Return value: a #guint containing the hash
1514 g_date_time_hash (gconstpointer datetime)
1516 return (guint) (*((guint64 *) datetime));
1520 * g_date_time_is_leap_year:
1521 * @datetime: a #GDateTime
1523 * Determines if @datetime represents a date known to fall within
1524 * a leap year in the Gregorian calendar.
1526 * Return value: %TRUE if @datetime is a leap year.
1531 g_date_time_is_leap_year (const GDateTime *datetime)
1535 g_return_val_if_fail (datetime != NULL, FALSE);
1537 year = g_date_time_get_year (datetime);
1539 return GREGORIAN_LEAP (year);
1543 * g_date_time_is_daylight_savings:
1544 * @datetime: a #GDateTime
1546 * Determines if @datetime represents a date known to fall within daylight
1547 * savings time in the gregorian calendar.
1549 * Return value: %TRUE if @datetime falls within daylight savings time.
1554 g_date_time_is_daylight_savings (const GDateTime *datetime)
1556 g_return_val_if_fail (datetime != NULL, FALSE);
1561 return datetime->tz->is_dst;
1565 date_to_julian (gint year,
1569 gint a = (14 - month) / 12;
1570 gint y = year + 4800 - a;
1571 gint m = month + (12 * a) - 3;
1574 + (((153 * m) + 2) / 5)
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
1588 * Creates a new #GDateTime using the specified date within the Gregorian
1591 * Return value: the newly created #GDateTime or %NULL if it is outside of
1592 * the representable range.
1597 g_date_time_new_from_date (gint year,
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);
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);
1615 * g_date_time_new_from_epoch:
1616 * @t: seconds from the Unix epoch
1618 * Creates a new #GDateTime using the time since Jan 1, 1970 specified by @t.
1620 * Return value: the newly created #GDateTime
1625 g_date_time_new_from_epoch (gint64 t) /* IN */
1631 memset (&tm, 0, sizeof (tm));
1633 /* XXX: GLib should probably have a wrapper for this */
1634 #ifdef HAVE_LOCALTIME_R
1635 localtime_r (&tt, &tm);
1638 struct tm *ptm = localtime (&timet);
1642 /* Happens at least in Microsoft's C library if you pass a
1643 * negative time_t. Use 2000-01-01 as default date.
1645 #ifndef G_DISABLE_CHECKS
1646 g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, "ptm != NULL");
1654 memcpy ((void *) &tm, (void *) ptm, sizeof (struct tm));
1656 #endif /* HAVE_LOCALTIME_R */
1658 return g_date_time_new_full (tm.tm_year + 1900,
1668 * g_date_time_new_from_timeval:
1671 * Creates a new #GDateTime using the date and time specified by #GTimeVal.
1673 * Return value: the newly created #GDateTime
1678 g_date_time_new_from_timeval (GTimeVal *tv)
1680 GDateTime *datetime;
1682 g_return_val_if_fail (tv != NULL, NULL);
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);
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)
1702 * Creates a new #GDateTime using the date and times in the Gregorian calendar.
1704 * Return value: the newly created #GDateTime
1709 g_date_time_new_full (gint year,
1715 const gchar *timezone)
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);
1723 if ((dt = g_date_time_new_from_date (year, month, day)) == NULL)
1726 dt->usec = (hour * USEC_PER_HOUR)
1727 + (minute * USEC_PER_MINUTE)
1728 + (second * USEC_PER_SECOND);
1730 dt->tz = g_date_time_create_time_zone (dt, timezone);
1731 if (timezone != NULL && dt->tz == NULL)
1733 /* timezone creation failed */
1734 g_date_time_unref (dt);
1742 * g_date_time_new_now:
1744 * Creates a new #GDateTime representing the current date and time.
1746 * Return value: the newly created #GDateTime which should be freed with
1747 * g_date_time_unref().
1752 g_date_time_new_now (void)
1756 g_get_current_time (&tv);
1758 return g_date_time_new_from_timeval (&tv);
1762 * g_date_time_printf:
1763 * @datetime: A #GDateTime
1764 * @format: a valid UTF-8 string, containing the format for the #GDateTime
1766 * Creates a newly allocated string representing the requested @format.
1768 * The following format specifiers are supported:
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
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
1803 * %%X The preferred date representation for the current locale without
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.
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
1817 g_date_time_printf (const GDateTime *datetime,
1818 const gchar *format)
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);
1832 outstr = g_string_sized_new (strlen (format) * 2);
1833 utf8len = g_utf8_strlen (format, -1);
1836 for (i = 0; i < utf8len; i++)
1838 tmp = g_utf8_offset_to_pointer (format, i);
1839 c = g_utf8_get_char (tmp);
1854 g_string_append (outstr, WEEKDAY_ABBR (datetime));
1857 g_string_append (outstr, WEEKDAY_FULL (datetime));
1860 g_string_append (outstr, MONTH_ABBR (datetime));
1863 g_string_append (outstr, MONTH_FULL (datetime));
1866 g_string_append_printf (outstr, "%02d",
1867 g_date_time_get_day_of_month (datetime));
1870 g_string_append_printf (outstr, "%2d",
1871 g_date_time_get_day_of_month (datetime));
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));
1880 g_string_append (outstr, MONTH_ABBR (datetime));
1883 g_string_append_printf (outstr, "%02d",
1884 g_date_time_get_hour (datetime));
1887 if (g_date_time_get_hour (datetime) == 0)
1888 g_string_append (outstr, "12");
1890 g_string_append_printf (outstr, "%02d",
1891 g_date_time_get_hour (datetime) % 12);
1894 g_string_append_printf (outstr, "%03d",
1895 g_date_time_get_day_of_year (datetime));
1898 g_string_append_printf (outstr, "%2d",
1899 g_date_time_get_hour (datetime));
1902 if (g_date_time_get_hour (datetime) == 0)
1903 g_string_append (outstr, "12");
1905 g_string_append_printf (outstr, "%2d",
1906 g_date_time_get_hour (datetime) % 12);
1909 g_string_append_printf (outstr, "%02d",
1910 g_date_time_get_month (datetime));
1913 g_string_append_printf (outstr, "%02d",
1914 g_date_time_get_minute (datetime));
1917 g_string_append_printf (outstr, "%"G_GUINT64_FORMAT,
1918 datetime->usec % USEC_PER_SECOND);
1921 g_string_append (outstr, GET_AMPM (datetime, FALSE));
1924 g_string_append (outstr, GET_AMPM (datetime, TRUE));
1927 gint hour = g_date_time_get_hour (datetime) % 12;
1930 g_string_append_printf (outstr, "%02d:%02d:%02d %s",
1932 g_date_time_get_minute (datetime),
1933 g_date_time_get_second (datetime),
1934 GET_AMPM (datetime, FALSE));
1938 g_string_append_printf (outstr, "%02d:%02d",
1939 g_date_time_get_hour (datetime),
1940 g_date_time_get_minute (datetime));
1943 g_string_append_printf (outstr, "%" G_GINT64_FORMAT,
1944 g_date_time_to_epoch (datetime));
1947 g_string_append_printf (outstr, "%02d",
1948 g_date_time_get_second (datetime));
1951 g_string_append_c (outstr, '\t');
1954 g_string_append_printf (outstr, "%d",
1955 g_date_time_get_day_of_week (datetime));
1958 g_string_append_printf (outstr, "%d",
1959 g_date_time_get_day_of_year (datetime) / 7);
1962 tmp2 = GET_PREFERRED_DATE (datetime);
1963 g_string_append (outstr, tmp2);
1968 tmp2 = GET_PREFERRED_TIME (datetime);
1969 g_string_append (outstr, tmp2);
1974 g_string_append_printf (outstr, "%02d",
1975 g_date_time_get_year (datetime) % 100);
1978 g_string_append_printf (outstr, "%d",
1979 g_date_time_get_year (datetime));
1983 g_string_append_printf (outstr, "%s", datetime->tz->name);
1985 g_string_append_printf (outstr, "UTC");
1988 g_string_append_c (outstr, '%');
1991 g_string_append_c (outstr, '\n');
1999 g_string_append_unichar (outstr, c);
2004 g_string_free (outstr, FALSE);
2009 g_string_free (outstr, TRUE);
2015 * @datetime: a #GDateTime
2017 * Atomically increments the reference count of @datetime by one.
2019 * Return value: the #GDateTime with the reference count increased
2024 g_date_time_ref (GDateTime *datetime)
2026 g_return_val_if_fail (datetime != NULL, NULL);
2027 g_return_val_if_fail (datetime->ref_count > 0, NULL);
2029 g_atomic_int_inc (&datetime->ref_count);
2035 * g_date_time_unref:
2036 * @datetime: a #GDateTime
2038 * Atomically decrements the reference count of @datetime by one.
2040 * When the reference count reaches zero, the resources allocated by
2041 * @datetime are freed
2046 g_date_time_unref (GDateTime *datetime)
2048 g_return_if_fail (datetime != NULL);
2049 g_return_if_fail (datetime->ref_count > 0);
2051 if (g_atomic_int_dec_and_test (&datetime->ref_count))
2052 g_date_time_free (datetime);
2056 * g_date_time_to_local:
2057 * @datetime: a #GDateTime
2059 * Creates a new #GDateTime with @datetime converted to local time.
2061 * Return value: the newly created #GDateTime
2066 g_date_time_to_local (const GDateTime *datetime)
2073 g_return_val_if_fail (datetime != NULL, NULL);
2075 dt = g_date_time_copy (datetime);
2079 year = g_date_time_get_year (dt);
2080 dt->tz = g_date_time_create_time_zone (dt, NULL);
2082 offset = dt->tz->offset;
2084 usec = offset * USEC_PER_SECOND;
2085 ADD_USEC (dt, usec);
2092 * g_date_time_to_epoch:
2093 * @datetime: a #GDateTime
2095 * Converts @datetime into an integer representing seconds since the
2098 * Return value: @datetime as seconds since the Unix epoch
2103 g_date_time_to_epoch (const GDateTime *datetime)
2110 g_return_val_if_fail (datetime != NULL, 0);
2111 g_return_val_if_fail (datetime->period == 0, 0);
2113 g_date_time_get_dmy (datetime, &day, &month, &year);
2115 /* FIXME we use gint64, we shold expand these limits */
2118 else if (year > 2037)
2121 memset (&tm, 0, sizeof (tm));
2123 tm.tm_year = year - 1900;
2124 tm.tm_mon = month - 1;
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);
2131 return (gint64) mktime (&tm);
2135 * g_date_time_to_timeval:
2136 * @datetime: a #GDateTime
2139 * Converts @datetime into a #GTimeVal and stores the result into @timeval.
2144 g_date_time_to_timeval (const GDateTime *datetime,
2147 g_return_if_fail (datetime != NULL);
2152 if (G_LIKELY (datetime->period == 0))
2154 tv->tv_sec = g_date_time_to_epoch (datetime);
2155 tv->tv_usec = datetime->usec % USEC_PER_SECOND;
2160 * g_date_time_to_utc:
2161 * @datetime: a #GDateTime
2163 * Creates a new #GDateTime that reprents @datetime in Universal coordinated
2166 * Return value: the newly created #GDateTime which should be freed with
2167 * g_date_time_unref().
2172 g_date_time_to_utc (const GDateTime *datetime)
2177 g_return_val_if_fail (datetime != NULL, NULL);
2179 ts = g_date_time_get_utc_offset (datetime) * -1;
2180 dt = g_date_time_add (datetime, ts);
2187 * g_date_time_new_today:
2189 * Createsa new #GDateTime that represents Midnight on the current day.
2191 * Return value: the newly created #GDateTime which should be freed with
2192 * g_date_time_unref().
2197 g_date_time_new_today (void)
2201 dt = g_date_time_new_now ();
2208 * g_date_time_new_utc_now:
2210 * Creates a new #GDateTime that represents the current instant in Universal
2211 * Coordinated Time (UTC).
2213 * Return value: the newly created #GDateTime which should be freed with
2214 * g_date_time_unref().
2219 g_date_time_new_utc_now (void)
2221 GDateTime *utc, *now;
2223 now = g_date_time_new_now ();
2224 utc = g_date_time_to_utc (now);
2225 g_date_time_unref (now);