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>
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.
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.
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
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
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
35 * This document is provided "as is". No warranties are made as
53 #endif /* !G_OS_WIN32 */
57 #include "gdatetime.h"
62 * @short_description: A Date and Time structure
64 * #GDateTime is a structure that combines a date and time into a single
65 * structure. It provides many conversion and methods to manipulate dates
66 * and times. Time precision is provided down to microseconds.
68 * #GDateTime is an immutable object: once it has been created it cannot be
69 * modified further. All modifiers will create a new #GDateTime.
71 * #GDateTime is reference counted: the reference count is increased by calling
72 * g_date_time_ref() and decreased by calling g_date_time_unref(). When the
73 * reference count drops to 0, the resources allocated by the #GDateTime
74 * structure are released.
76 * Internally, #GDateTime uses the Julian Day Number since the
77 * initial Julian Period (-4712 BC). However, the public API uses the
78 * internationally accepted Gregorian Calendar.
80 * #GDateTime is available since GLib 2.26.
83 #define USEC_PER_SECOND (G_GINT64_CONSTANT (1000000))
84 #define USEC_PER_MINUTE (G_GINT64_CONSTANT (60000000))
85 #define USEC_PER_HOUR (G_GINT64_CONSTANT (3600000000))
86 #define USEC_PER_MILLISECOND (G_GINT64_CONSTANT (1000))
87 #define USEC_PER_DAY (G_GINT64_CONSTANT (86400000000))
89 #define GREGORIAN_LEAP(y) (((y % 4) == 0) && (!(((y % 100) == 0) && ((y % 400) != 0))))
90 #define JULIAN_YEAR(d) ((d)->julian / 365.25)
91 #define DAYS_PER_PERIOD (G_GINT64_CONSTANT (2914695))
93 #define GET_AMPM(d,l) ((g_date_time_get_hour (d) < 12) \
94 ? (l ? C_("GDateTime", "am") : C_("GDateTime", "AM")) \
95 : (l ? C_("GDateTime", "pm") : C_("GDateTime", "PM")))
97 #define WEEKDAY_ABBR(d) (get_weekday_name_abbr (g_date_time_get_day_of_week (datetime)))
98 #define WEEKDAY_FULL(d) (get_weekday_name (g_date_time_get_day_of_week (datetime)))
100 #define MONTH_ABBR(d) (get_month_name_abbr (g_date_time_get_month (datetime)))
101 #define MONTH_FULL(d) (get_month_name (g_date_time_get_month (datetime)))
103 /* Translators: this is the preferred format for expressing the date */
104 #define GET_PREFERRED_DATE(d) (g_date_time_printf ((d), C_("GDateTime", "%m/%d/%y")))
106 /* Translators: this is the preferred format for expressing the time */
107 #define GET_PREFERRED_TIME(d) (g_date_time_printf ((d), C_("GDateTime", "%H:%M:%S")))
109 typedef struct _GTimeZone GTimeZone;
113 /* Julian Period, 0 is Initial Epoch */
116 /* Day within Julian Period */
119 /* Microsecond timekeeping within Day */
124 /* TimeZone information, NULL is UTC */
127 volatile gint ref_count;
132 /* TZ abbreviation (e.g. PST) */
140 static const guint16 days_in_months[2][13] =
142 { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
143 { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
146 static const guint16 days_in_year[2][13] =
148 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
149 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
153 get_month_name (gint month)
158 return C_("GDateTime", "January");
160 return C_("GDateTime", "February");
162 return C_("GDateTime", "March");
164 return C_("GDateTime", "April");
166 return C_("GDateTime", "May");
168 return C_("GDateTime", "June");
170 return C_("GDateTime", "July");
172 return C_("GDateTime", "August");
174 return C_("GDateTime", "September");
176 return C_("GDateTime", "October");
178 return C_("GDateTime", "November");
180 return C_("GDateTime", "December");
183 g_warning ("Invalid month number %d", month);
190 get_month_name_abbr (gint month)
195 return C_("GDateTime", "Jan");
197 return C_("GDateTime", "Feb");
199 return C_("GDateTime", "Mar");
201 return C_("GDateTime", "Apr");
203 return C_("GDateTime", "May");
205 return C_("GDateTime", "Jun");
207 return C_("GDateTime", "Jul");
209 return C_("GDateTime", "Aug");
211 return C_("GDateTime", "Sep");
213 return C_("GDateTime", "Oct");
215 return C_("GDateTime", "Nov");
217 return C_("GDateTime", "Dec");
220 g_warning ("Invalid month number %d", month);
227 get_weekday_name (gint day)
232 return C_("GDateTime", "Monday");
234 return C_("GDateTime", "Tuesday");
236 return C_("GDateTime", "Wednesday");
238 return C_("GDateTime", "Thursday");
240 return C_("GDateTime", "Friday");
242 return C_("GDateTime", "Saturday");
244 return C_("GDateTime", "Sunday");
247 g_warning ("Invalid week day number %d", day);
254 get_weekday_name_abbr (gint day)
259 return C_("GDateTime", "Mon");
261 return C_("GDateTime", "Tue");
263 return C_("GDateTime", "Wed");
265 return C_("GDateTime", "Thu");
267 return C_("GDateTime", "Fri");
269 return C_("GDateTime", "Sat");
271 return C_("GDateTime", "Sun");
274 g_warning ("Invalid week day number %d", day);
281 g_date_time_add_days_internal (GDateTime *datetime,
284 gint __day = datetime->julian + days;
287 datetime->period += -1 + (__day / DAYS_PER_PERIOD);
288 datetime->period += DAYS_PER_PERIOD + (__day % DAYS_PER_PERIOD);
290 else if (__day > DAYS_PER_PERIOD)
292 datetime->period += (datetime->julian + days) / DAYS_PER_PERIOD;
293 datetime->julian = (datetime->julian + days) % DAYS_PER_PERIOD;
296 datetime->julian += days;
300 g_date_time_add_usec (GDateTime *datetime,
303 gint64 __usec = datetime->usec + usecs;
304 gint __days = __usec / USEC_PER_DAY;
310 g_date_time_add_days_internal (datetime, __days);
313 datetime->usec = USEC_PER_DAY + (__usec % USEC_PER_DAY);
315 datetime->usec = __usec % USEC_PER_DAY;
318 #define ZONEINFO_DIR "zoneinfo"
319 #define TZ_MAGIC "TZif"
320 #define TZ_MAGIC_LEN (strlen (TZ_MAGIC))
321 #define TZ_HEADER_SIZE 44
322 #define TZ_TIMECNT_OFFSET 32
323 #define TZ_TYPECNT_OFFSET 36
324 #define TZ_TRANSITIONS_OFFSET 44
326 #define TZ_TTINFO_SIZE 6
327 #define TZ_TTINFO_GMTOFF_OFFSET 0
328 #define TZ_TTINFO_ISDST_OFFSET 4
329 #define TZ_TTINFO_NAME_OFFSET 5
332 get_tzdata_path (const gchar *tz_name)
338 const gchar *tz_dir = g_getenv ("TZDIR");
341 retval = g_build_filename (tz_dir, tz_name, NULL);
343 retval = g_build_filename ("/", "usr", "share", ZONEINFO_DIR, tz_name, NULL);
347 /* an empty tz_name means "the current timezone file". tzset(3) defines
348 * it to be /usr/share/zoneinfo/localtime, and it also allows an
349 * /etc/localtime as a symlink to the localtime file under
350 * /usr/share/zoneinfo or to the correct timezone file. Fedora does not
351 * have /usr/share/zoneinfo/localtime, but it does have a real
354 * in any case, this path should resolve correctly.
356 retval = g_build_filename ("/", "etc", "localtime", NULL);
363 * Parses tzdata database times to get timezone info.
365 * @tzname: Olson database name for the timezone
366 * @start: Time offset from epoch we want to know the timezone
367 * @_is_dst: Returns if this time in the timezone is in DST
368 * @_offset: Returns the offset from UTC for this timezone
369 * @_name: Returns the abreviated name for thie timezone
372 parse_tzdata (const gchar *tzname,
379 gchar *filename, *contents;
381 guint32 timecnt, typecnt;
382 gint transitions_size, ttinfo_map_size;
383 guint8 *ttinfo_map, *ttinfos;
384 gint start_transition = -1;
385 guint32 *transitions;
392 filename = get_tzdata_path (tzname);
394 /* XXX: should we be caching this in memory for faster access?
395 * and if so, how do we expire the cache?
398 if (!g_file_get_contents (filename, &contents, &length, &error))
406 if (length < TZ_HEADER_SIZE ||
407 (strncmp (contents, TZ_MAGIC, TZ_MAGIC_LEN) != 0))
413 timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
414 typecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TYPECNT_OFFSET));
416 transitions = (guint32 *)(contents + TZ_TRANSITIONS_OFFSET);
417 transitions_size = timecnt * sizeof (*transitions);
418 ttinfo_map = (void *)(contents + TZ_TRANSITIONS_OFFSET + transitions_size);
419 ttinfo_map_size = timecnt;
420 ttinfos = (void *)(ttinfo_map + ttinfo_map_size);
423 * Find the first transition that contains the 'start' time
425 for (i = 1; i < timecnt && start_transition == -1; i++)
427 gint32 transition_time = GINT32_FROM_BE (transitions[i]);
429 /* if is_utc is not set, we need to add this time offset to compare with
430 * start, because it is already on the timezone time */
435 off = *(gint32 *)(ttinfos + ttinfo_map[i] * TZ_TTINFO_SIZE +
436 TZ_TTINFO_GMTOFF_OFFSET);
437 off = GINT32_FROM_BE (off);
439 transition_time += off;
442 if (transition_time > start)
444 start_transition = ttinfo_map[i - 1];
449 if (start_transition == -1)
452 start_transition = ttinfo_map[timecnt - 1];
454 start_transition = 0;
457 /* Copy the data out of the corresponding ttinfo structs */
458 offset = *(gint32 *)(ttinfos + start_transition * TZ_TTINFO_SIZE +
459 TZ_TTINFO_GMTOFF_OFFSET);
460 offset = GINT32_FROM_BE (offset);
461 isdst = *(ttinfos + start_transition * TZ_TTINFO_SIZE +
462 TZ_TTINFO_ISDST_OFFSET);
463 name_offset = *(ttinfos + start_transition * TZ_TTINFO_SIZE +
464 TZ_TTINFO_NAME_OFFSET);
467 *_name = g_strdup ((gchar*) (ttinfos + TZ_TTINFO_SIZE * typecnt + name_offset));
481 * g_time_zone_new_from_epoc:
482 * @tzname: The Olson's database timezone name
483 * @epoch: The epoch offset
484 * @is_utc: If the @epoch is in UTC or already in the @tzname timezone
486 * Creates a new timezone
489 g_time_zone_new_from_epoch (const gchar *tzname,
493 GTimeZone *tz = NULL;
498 if (parse_tzdata (tzname, epoch, is_utc, &is_dst, &offset, &name))
500 tz = g_slice_new (GTimeZone);
509 #define SECS_PER_MINUTE (60)
510 #define SECS_PER_HOUR (60 * SECS_PER_MINUTE)
511 #define SECS_PER_DAY (24 * SECS_PER_HOUR)
512 #define SECS_PER_YEAR (365 * SECS_PER_DAY)
513 #define SECS_PER_JULIAN (DAYS_PER_PERIOD * SECS_PER_DAY)
516 g_date_time_secs_offset (GDateTime * dt)
522 y = g_date_time_get_year (dt) - 1970;
523 d = g_date_time_get_day_of_year (dt);
524 h = g_date_time_get_hour (dt);
525 m = g_date_time_get_minute (dt);
526 s = g_date_time_get_second (dt);
528 /* FIXME this is an approximation */
532 secs += y * SECS_PER_YEAR;
533 secs += d * SECS_PER_DAY;
534 secs += leaps * SECS_PER_DAY;
535 secs += h * SECS_PER_HOUR;
536 secs += m * SECS_PER_MINUTE;
543 * g_date_time_create_time_zone:
545 * @tzname: the name of the timezone
547 * Creates a timezone from a #GDateTime (disregarding its own timezone).
548 * This function transforms the #GDateTime into seconds since the epoch
549 * and creates a timezone for it in the @tzname zone.
551 * Return value: a newly created #GTimeZone
554 g_date_time_create_time_zone (GDateTime *dt,
559 secs = g_date_time_secs_offset (dt);
561 return g_time_zone_new_from_epoch (tzname, secs, FALSE);
565 g_date_time_new (void)
569 datetime = g_slice_new0 (GDateTime);
570 datetime->ref_count = 1;
576 g_time_zone_copy (const GTimeZone *timezone)
580 if (G_UNLIKELY (timezone == NULL))
583 tz = g_slice_new (GTimeZone);
584 memcpy (tz, timezone, sizeof (GTimeZone));
586 tz->name = g_strdup (timezone->name);
592 g_time_zone_free (GTimeZone *timezone)
594 if (G_LIKELY (timezone != NULL))
596 g_free (timezone->name);
597 g_slice_free (GTimeZone, timezone);
602 g_date_time_free (GDateTime *datetime)
604 if (G_UNLIKELY (datetime == NULL))
608 g_time_zone_free (datetime->tz);
610 g_slice_free (GDateTime, datetime);
614 g_date_time_get_week_number (const GDateTime *datetime,
619 gint a, b, c, d, e, f, g, n, s, month, day, year;
621 g_date_time_get_dmy (datetime, &day, &month, &year);
625 a = g_date_time_get_year (datetime) - 1;
626 b = (a / 4) - (a / 100) + (a / 400);
627 c = ((a - 1) / 4) - ((a - 1) / 100) + ((a - 1) / 400);
630 f = day - 1 + (31 * (month - 1));
635 b = (a / 4) - (a / 100) + (a / 400);
636 c = ((a - 1) / 4) - ((a - 1) / 100) + ((a - 1) / 400);
639 f = day + (((153 * (month - 3)) + 2) / 5) + 58 + s;
649 *week_number = 53 - ((g - s) / 5);
650 else if (n > 364 + s)
653 *week_number = (n / 7) + 1;
657 *day_of_week = d + 1;
660 *day_of_year = f + 1;
665 * @datetime: a #GDateTime
666 * @timespan: a #GTimeSpan
668 * Creates a copy of @datetime and adds the specified timespan to the copy.
670 * Return value: the newly created #GDateTime which should be freed with
671 * g_date_time_unref().
676 g_date_time_add (const GDateTime *datetime,
681 g_return_val_if_fail (datetime != NULL, NULL);
683 dt = g_date_time_copy (datetime);
684 g_date_time_add_usec (dt, timespan);
690 * g_date_time_add_years:
691 * @datetime: a #GDateTime
692 * @years: the number of years
694 * Creates a copy of @datetime and adds the specified number of years to the
697 * Return value: the newly created #GDateTime which should be freed with
698 * g_date_time_unref().
703 g_date_time_add_years (const GDateTime *datetime,
709 g_return_val_if_fail (datetime != NULL, NULL);
711 day = g_date_time_get_day_of_month (datetime);
712 if (g_date_time_is_leap_year (datetime) &&
713 g_date_time_get_month (datetime) == 2)
719 dt = g_date_time_new_from_date (g_date_time_get_year (datetime) + years,
720 g_date_time_get_month (datetime),
722 dt->usec = datetime->usec;
728 * g_date_time_add_months:
729 * @datetime: a #GDateTime
730 * @months: the number of months
732 * Creates a copy of @datetime and adds the specified number of months to the
735 * Return value: the newly created #GDateTime which should be freed with
736 * g_date_time_unref().
741 g_date_time_add_months (const GDateTime *datetime,
752 g_return_val_if_fail (datetime != NULL, NULL);
753 g_return_val_if_fail (months != 0, NULL);
755 month = g_date_time_get_month (datetime);
756 year = g_date_time_get_year (datetime);
757 a = months > 0 ? 1 : -1;
759 for (i = 0; i < ABS (months); i++)
774 day = g_date_time_get_day_of_month (datetime);
775 days = days_in_months [GREGORIAN_LEAP (year) ? 1 : 0];
777 if (days[month] < day)
780 dt = g_date_time_new_from_date (year, month, day);
781 dt->usec = datetime->usec;
787 * g_date_time_add_weeks:
788 * @datetime: a #GDateTime
789 * @weeks: the number of weeks
791 * Creates a copy of @datetime and adds the specified number of weeks to the
794 * Return value: the newly created #GDateTime which should be freed with
795 * g_date_time_unref().
800 g_date_time_add_weeks (const GDateTime *datetime,
803 g_return_val_if_fail (datetime != NULL, NULL);
805 return g_date_time_add_days (datetime, weeks * 7);
809 * g_date_time_add_days:
810 * @datetime: a #GDateTime
811 * @days: the number of days
813 * Creates a copy of @datetime and adds the specified number of days to the
816 * Return value: the newly created #GDateTime which should be freed with
817 * g_date_time_unref().
822 g_date_time_add_days (const GDateTime *datetime,
827 g_return_val_if_fail (datetime != NULL, NULL);
829 dt = g_date_time_copy (datetime);
830 g_date_time_add_days_internal (dt, days);
836 * g_date_time_add_hours:
837 * @datetime: a #GDateTime
838 * @hours: the number of hours to add
840 * Creates a copy of @datetime and adds the specified number of hours
842 * Return value: the newly created #GDateTime which should be freed with
843 * g_date_time_unref().
848 g_date_time_add_hours (const GDateTime *datetime,
853 g_return_val_if_fail (datetime != NULL, NULL);
855 dt = g_date_time_copy (datetime);
856 g_date_time_add_usec (dt, (gint64) hours * USEC_PER_HOUR);
862 * g_date_time_add_seconds:
863 * @datetime: a #GDateTime
864 * @seconds: the number of seconds to add
866 * Creates a copy of @datetime and adds the specified number of seconds.
868 * Return value: the newly created #GDateTime which should be freed with
869 * g_date_time_unref().
874 g_date_time_add_seconds (const GDateTime *datetime,
879 g_return_val_if_fail (datetime != NULL, NULL);
881 dt = g_date_time_copy (datetime);
882 g_date_time_add_usec (dt, (gint64) seconds * USEC_PER_SECOND);
888 * g_date_time_add_milliseconds:
889 * @datetime: a #GDateTime
890 * @milliseconds: the number of milliseconds to add
892 * Creates a copy of @datetime adding the specified number of milliseconds.
894 * Return value: the newly created #GDateTime which should be freed with
895 * g_date_time_unref().
900 g_date_time_add_milliseconds (const GDateTime *datetime,
905 g_return_val_if_fail (datetime != NULL, NULL);
907 dt = g_date_time_copy (datetime);
908 g_date_time_add_usec (dt, (gint64) milliseconds * USEC_PER_MILLISECOND);
914 * g_date_time_add_minutes:
915 * @datetime: a #GDateTime
916 * @minutes: the number of minutes to add
918 * Creates a copy of @datetime adding the specified number of minutes.
920 * Return value: the newly created #GDateTime which should be freed with
921 * g_date_time_unref().
926 g_date_time_add_minutes (const GDateTime *datetime,
931 g_return_val_if_fail (datetime != NULL, NULL);
933 dt = g_date_time_copy (datetime);
934 g_date_time_add_usec (dt, (gint64) minutes * USEC_PER_MINUTE);
940 * g_date_time_add_full:
941 * @datetime: a #GDateTime
942 * @years: the number of years to add
943 * @months: the number of months to add
944 * @days: the number of days to add
945 * @hours: the number of hours to add
946 * @minutes: the number of minutes to add
947 * @seconds: the number of seconds to add
949 * Creates a new #GDateTime adding the specified values to the current date and
952 * Return value: the newly created #GDateTime that should be freed with
953 * g_date_time_unref().
958 g_date_time_add_full (const GDateTime *datetime,
968 g_return_val_if_fail (datetime != NULL, NULL);
970 dt = g_date_time_add_years (datetime, years);
973 dt = g_date_time_add_months (tmp, months);
974 g_date_time_unref (tmp);
977 dt = g_date_time_add_days (tmp, days);
978 g_date_time_unref (tmp);
981 dt = g_date_time_add_hours (tmp, hours);
982 g_date_time_unref (tmp);
985 dt = g_date_time_add_minutes (tmp, minutes);
986 g_date_time_unref (tmp);
989 dt = g_date_time_add_seconds (tmp, seconds);
990 g_date_time_unref (tmp);
996 * g_date_time_compare:
997 * @dt1: first #GDateTime to compare
998 * @dt2: second #GDateTime to compare
1000 * qsort()-style comparison for #GDateTime<!-- -->'s. Both #GDateTime<-- -->'s
1001 * must be non-%NULL.
1003 * Return value: 0 for equal, less than zero if dt1 is less than dt2, greater
1004 * than zero if dt2 is greator than dt1.
1009 g_date_time_compare (gconstpointer dt1,
1012 const GDateTime *a, *b;
1017 if ((a->period == b->period) &&
1018 (a->julian == b->julian) &&
1019 (a->usec == b->usec))
1023 else if ((a->period > b->period) ||
1024 ((a->period == b->period) && (a->julian > b->julian)) ||
1025 ((a->period == b->period) && (a->julian == b->julian) && a->usec > b->usec))
1035 * @datetime: a #GDateTime
1037 * Creates a copy of @datetime.
1039 * Return value: the newly created #GDateTime which should be freed with
1040 * g_date_time_unref().
1045 g_date_time_copy (const GDateTime *datetime)
1049 g_return_val_if_fail (datetime != NULL, NULL);
1051 copied = g_date_time_new ();
1052 copied->period = datetime->period;
1053 copied->julian = datetime->julian;
1054 copied->usec = datetime->usec;
1055 copied->tz = g_time_zone_copy (datetime->tz);
1062 * @datetime: a #GDateTime
1064 * Creates a new #GDateTime at Midnight on the date represented by @datetime.
1066 * Return value: the newly created #GDateTime which should be freed with
1067 * g_date_time_unref().
1072 g_date_time_day (const GDateTime *datetime)
1076 g_return_val_if_fail (datetime != NULL, NULL);
1078 date = g_date_time_copy (datetime);
1085 * g_date_time_difference:
1086 * @begin: a #GDateTime
1087 * @end: a #GDateTime
1089 * Calculates the known difference in time between @begin and @end.
1091 * Since the exact precision cannot always be known due to incomplete
1092 * historic information, an attempt is made to calculate the difference.
1094 * Return value: the difference between the two #GDateTime, as a time
1095 * span expressed in microseconds.
1100 g_date_time_difference (const GDateTime *begin,
1101 const GDateTime *end)
1103 g_return_val_if_fail (begin != NULL, 0);
1104 g_return_val_if_fail (end != NULL, 0);
1106 if (begin->period != 0 || end->period != 0)
1108 g_warning ("GDateTime only supports the current Julian period");
1112 return ((end->julian - begin->julian) * USEC_PER_DAY) + (end->usec - begin->usec);
1116 * g_date_time_equal:
1117 * @dt1: a #GDateTime
1118 * @dt2: a #GDateTime
1120 * Checks to see if @dt1 and @dt2 are equal.
1122 * Equal here means that they represent the same moment after converting
1123 * them to the same timezone.
1125 * Return value: %TRUE if @dt1 and @dt2 are equal
1130 g_date_time_equal (gconstpointer dt1,
1133 const GDateTime *a, *b;
1134 GDateTime *a_utc, *b_utc;
1135 gint64 a_epoch, b_epoch;
1140 a_utc = g_date_time_to_utc ((GDateTime *) a);
1141 b_utc = g_date_time_to_utc ((GDateTime *) b);
1143 a_epoch = g_date_time_to_epoch (a_utc);
1144 b_epoch = g_date_time_to_epoch (b_utc);
1146 g_date_time_unref (a_utc);
1147 g_date_time_unref (b_utc);
1149 return a_epoch == b_epoch;
1153 * g_date_time_get_day_of_week:
1154 * @datetime: a #GDateTime
1156 * Retrieves the day of the week represented by @datetime within the gregorian
1157 * calendar. 1 is Sunday, 2 is Monday, etc.
1159 * Return value: the day of the week
1164 g_date_time_get_day_of_week (const GDateTime *datetime)
1172 g_return_val_if_fail (datetime != NULL, 0);
1175 * See Calendar FAQ Section 2.6 for algorithm information
1176 * http://www.tondering.dk/claus/cal/calendar29.txt
1179 g_date_time_get_dmy (datetime, &day, &month, &year);
1180 a = (14 - month) / 12;
1182 m = month + (12 * a) - 2;
1183 dow = ((day + y + (y / 4) - (y / 100) + (y / 400) + (31 * m) / 12) % 7);
1185 /* 1 is Monday and 7 is Sunday */
1186 return (dow == 0) ? 7 : dow;
1190 * g_date_time_get_day_of_month:
1191 * @datetime: a #GDateTime
1193 * Retrieves the day of the month represented by @datetime in the gregorian
1196 * Return value: the day of the month
1201 g_date_time_get_day_of_month (const GDateTime *datetime)
1205 const guint16 *days;
1208 g_return_val_if_fail (datetime != NULL, 0);
1210 days = days_in_year[g_date_time_is_leap_year (datetime) ? 1 : 0];
1211 g_date_time_get_week_number (datetime, NULL, NULL, &day_of_year);
1213 for (i = 1; i <= 12; i++)
1215 if (days [i] >= day_of_year)
1216 return day_of_year - last;
1220 g_warn_if_reached ();
1225 * g_date_time_get_day_of_year:
1226 * @datetime: a #GDateTime
1228 * Retrieves the day of the year represented by @datetime in the Gregorian
1231 * Return value: the day of the year
1236 g_date_time_get_day_of_year (const GDateTime *datetime)
1240 g_return_val_if_fail (datetime != NULL, 0);
1242 g_date_time_get_week_number (datetime, NULL, NULL, &doy);
1247 * g_date_time_get_dmy:
1248 * @datetime: a #GDateTime.
1249 * @day: (out): the return location for the day of the month, or %NULL.
1250 * @month: (out): the return location for the monty of the year, or %NULL.
1251 * @year: (out): the return location for the gregorian year, or %NULL.
1253 * Retrieves the Gregorian day, month, and year of a given #GDateTime.
1258 g_date_time_get_dmy (const GDateTime *datetime,
1263 gint a, b, c, d, e, m;
1265 a = datetime->julian + 32044;
1266 b = ((4 * a) + 3) / 146097;
1267 c = a - ((b * 146097) / 4);
1268 d = ((4 * c) + 3) / 1461;
1269 e = c - (1461 * d) / 4;
1270 m = (5 * e + 2) / 153;
1273 *day = e - (((153 * m) + 2) / 5) + 1;
1276 *month = m + 3 - (12 * (m / 10));
1279 *year = (b * 100) + d - 4800 + (m / 10);
1283 * g_date_time_get_hour:
1284 * @datetime: a #GDateTime
1286 * Retrieves the hour of the day represented by @datetime
1288 * Return value: the hour of the day
1293 g_date_time_get_hour (const GDateTime *datetime)
1295 g_return_val_if_fail (datetime != NULL, 0);
1297 return (datetime->usec / USEC_PER_HOUR);
1301 * g_date_time_get_julian:
1302 * @datetime: a #GDateTime
1303 * @period: (out): a location for the Julian period
1304 * @julian: (out): a location for the day in the Julian period
1305 * @hour: (out): a location for the hour of the day
1306 * @minute: (out): a location for the minute of the hour
1307 * @second: (out): a location for hte second of the minute
1309 * Retrieves the Julian period, day, hour, minute, and second which @datetime
1310 * represents in the Julian calendar.
1315 g_date_time_get_julian (const GDateTime *datetime,
1322 g_return_if_fail (datetime != NULL);
1325 *period = datetime->period;
1328 *julian = datetime->julian;
1331 *hour = (datetime->usec / USEC_PER_HOUR);
1334 *minute = (datetime->usec % USEC_PER_HOUR) / USEC_PER_MINUTE;
1337 *second = (datetime->usec % USEC_PER_MINUTE) / USEC_PER_SECOND;
1341 * g_date_time_get_microsecond:
1342 * @datetime: a #GDateTime
1344 * Retrieves the microsecond of the date represented by @datetime
1346 * Return value: the microsecond of the second
1351 g_date_time_get_microsecond (const GDateTime *datetime)
1353 g_return_val_if_fail (datetime != NULL, 0);
1355 return (datetime->usec % USEC_PER_SECOND);
1359 * g_date_time_get_millisecond:
1360 * @datetime: a #GDateTime
1362 * Retrieves the millisecond of the date represented by @datetime
1364 * Return value: the millisecond of the second
1369 g_date_time_get_millisecond (const GDateTime *datetime)
1371 g_return_val_if_fail (datetime != NULL, 0);
1373 return (datetime->usec % USEC_PER_SECOND) / USEC_PER_MILLISECOND;
1377 * g_date_time_get_minute:
1378 * @datetime: a #GDateTime
1380 * Retrieves the minute of the hour represented by @datetime
1382 * Return value: the minute of the hour
1387 g_date_time_get_minute (const GDateTime *datetime)
1389 g_return_val_if_fail (datetime != NULL, 0);
1391 return (datetime->usec % USEC_PER_HOUR) / USEC_PER_MINUTE;
1395 * g_date_time_get_month:
1396 * @datetime: a #GDateTime
1398 * Retrieves the month of the year represented by @datetime in the Gregorian
1401 * Return value: the month represented by @datetime
1406 g_date_time_get_month (const GDateTime *datetime)
1410 g_return_val_if_fail (datetime != NULL, 0);
1412 g_date_time_get_dmy (datetime, NULL, &month, NULL);
1418 * g_date_time_get_second:
1419 * @datetime: a #GDateTime
1421 * Retrieves the second of the minute represented by @datetime
1423 * Return value: the second represented by @datetime
1428 g_date_time_get_second (const GDateTime *datetime)
1430 g_return_val_if_fail (datetime != NULL, 0);
1432 return (datetime->usec % USEC_PER_MINUTE) / USEC_PER_SECOND;
1436 * g_date_time_get_utc_offset:
1437 * @datetime: a #GDateTime
1439 * Retrieves the offset from UTC that the local timezone specified by
1440 * @datetime represents.
1442 * If @datetime represents UTC time, then the offset is zero.
1444 * Return value: the offset, expressed as a time span expressed in
1450 g_date_time_get_utc_offset (const GDateTime *datetime)
1454 g_return_val_if_fail (datetime != NULL, 0);
1456 if (datetime->tz != NULL)
1457 offset = datetime->tz->offset;
1459 return (gint64) offset * USEC_PER_SECOND;
1463 * g_date_time_get_timezone_name:
1464 * @datetime: a #GDateTime
1466 * Retrieves the Olson's database timezone name of the timezone specified
1469 * Return value: (transfer none): the name of the timezone. The returned
1470 * string is owned by the #GDateTime and it should not be modified or
1475 G_CONST_RETURN gchar *
1476 g_date_time_get_timezone_name (const GDateTime *datetime)
1478 g_return_val_if_fail (datetime != NULL, NULL);
1480 if (datetime->tz != NULL)
1481 return datetime->tz->name;
1487 * g_date_time_get_year:
1488 * @datetime: A #GDateTime
1490 * Retrieves the year represented by @datetime in the Gregorian calendar.
1492 * Return value: the year represented by @datetime
1497 g_date_time_get_year (const GDateTime *datetime)
1501 g_return_val_if_fail (datetime != NULL, 0);
1503 g_date_time_get_dmy (datetime, NULL, NULL, &year);
1510 * @datetime: a #GDateTime
1512 * Hashes @datetime into a #guint, suitable for use within #GHashTable.
1514 * Return value: a #guint containing the hash
1519 g_date_time_hash (gconstpointer datetime)
1521 return (guint) (*((guint64 *) datetime));
1525 * g_date_time_is_leap_year:
1526 * @datetime: a #GDateTime
1528 * Determines if @datetime represents a date known to fall within
1529 * a leap year in the Gregorian calendar.
1531 * Return value: %TRUE if @datetime is a leap year.
1536 g_date_time_is_leap_year (const GDateTime *datetime)
1540 g_return_val_if_fail (datetime != NULL, FALSE);
1542 year = g_date_time_get_year (datetime);
1544 return GREGORIAN_LEAP (year);
1548 * g_date_time_is_daylight_savings:
1549 * @datetime: a #GDateTime
1551 * Determines if @datetime represents a date known to fall within daylight
1552 * savings time in the gregorian calendar.
1554 * Return value: %TRUE if @datetime falls within daylight savings time.
1559 g_date_time_is_daylight_savings (const GDateTime *datetime)
1561 g_return_val_if_fail (datetime != NULL, FALSE);
1566 return datetime->tz->is_dst;
1570 date_to_julian (gint year,
1574 gint a = (14 - month) / 12;
1575 gint y = year + 4800 - a;
1576 gint m = month + (12 * a) - 3;
1579 + (((153 * m) + 2) / 5)
1588 * g_date_time_new_from_date:
1589 * @year: the Gregorian year
1590 * @month: the Gregorian month
1591 * @day: the day in the Gregorian month
1593 * Creates a new #GDateTime using the specified date within the Gregorian
1596 * Return value: the newly created #GDateTime or %NULL if it is outside of
1597 * the representable range.
1602 g_date_time_new_from_date (gint year,
1608 g_return_val_if_fail (year > -4712 && year <= 3268, NULL);
1609 g_return_val_if_fail (month > 0 && month <= 12, NULL);
1610 g_return_val_if_fail (day > 0 && day <= 31, NULL);
1612 dt = g_date_time_new ();
1613 dt->julian = date_to_julian (year, month, day);
1614 dt->tz = g_date_time_create_time_zone (dt, NULL);
1620 * g_date_time_new_from_epoch:
1621 * @t: seconds from the Unix epoch
1623 * Creates a new #GDateTime using the time since Jan 1, 1970 specified by @t.
1625 * Return value: the newly created #GDateTime
1630 g_date_time_new_from_epoch (gint64 t) /* IN */
1636 memset (&tm, 0, sizeof (tm));
1638 /* XXX: GLib should probably have a wrapper for this */
1639 #ifdef HAVE_LOCALTIME_R
1640 localtime_r (&tt, &tm);
1643 struct tm *ptm = localtime (&timet);
1647 /* Happens at least in Microsoft's C library if you pass a
1648 * negative time_t. Use 2000-01-01 as default date.
1650 #ifndef G_DISABLE_CHECKS
1651 g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, "ptm != NULL");
1659 memcpy ((void *) &tm, (void *) ptm, sizeof (struct tm));
1661 #endif /* HAVE_LOCALTIME_R */
1663 return g_date_time_new_full (tm.tm_year + 1900,
1673 * g_date_time_new_from_timeval:
1676 * Creates a new #GDateTime using the date and time specified by #GTimeVal.
1678 * Return value: the newly created #GDateTime
1683 g_date_time_new_from_timeval (GTimeVal *tv)
1685 GDateTime *datetime;
1687 g_return_val_if_fail (tv != NULL, NULL);
1689 datetime = g_date_time_new_from_epoch (tv->tv_sec);
1690 datetime->usec += tv->tv_usec;
1691 datetime->tz = g_date_time_create_time_zone (datetime, NULL);
1697 * g_date_time_new_full:
1698 * @year: the Gregorian year
1699 * @month: the Gregorian month
1700 * @day: the day of the Gregorian month
1701 * @hour: the hour of the day
1702 * @minute: the minute of the hour
1703 * @second: the second of the minute
1704 * @timezone: (allow-none): the Olson's database timezone name, or %NULL
1705 * for local (e.g. America/New_York)
1707 * Creates a new #GDateTime using the date and times in the Gregorian calendar.
1709 * Return value: the newly created #GDateTime
1714 g_date_time_new_full (gint year,
1720 const gchar *timezone)
1724 g_return_val_if_fail (hour >= 0 && hour < 24, NULL);
1725 g_return_val_if_fail (minute >= 0 && minute < 60, NULL);
1726 g_return_val_if_fail (second >= 0 && second <= 60, NULL);
1728 if ((dt = g_date_time_new_from_date (year, month, day)) == NULL)
1731 dt->usec = (hour * USEC_PER_HOUR)
1732 + (minute * USEC_PER_MINUTE)
1733 + (second * USEC_PER_SECOND);
1735 dt->tz = g_date_time_create_time_zone (dt, timezone);
1736 if (timezone != NULL && dt->tz == NULL)
1738 /* timezone creation failed */
1739 g_date_time_unref (dt);
1747 * g_date_time_new_now:
1749 * Creates a new #GDateTime representing the current date and time.
1751 * Return value: the newly created #GDateTime which should be freed with
1752 * g_date_time_unref().
1757 g_date_time_new_now (void)
1761 g_get_current_time (&tv);
1763 return g_date_time_new_from_timeval (&tv);
1767 * g_date_time_printf:
1768 * @datetime: A #GDateTime
1769 * @format: a valid UTF-8 string, containing the format for the #GDateTime
1771 * Creates a newly allocated string representing the requested @format.
1773 * The following format specifiers are supported:
1775 * %%a The abbreviated weekday name according to the current locale.
1776 * %%A The full weekday name according to the current locale.
1777 * %%b The abbreviated month name according to the current locale.
1778 * %%B The full month name according to the current locale.
1779 * %%d The day of the month as a decimal number (range 01 to 31).
1780 * %%e The day of the month as a decimal number (range 1 to 31).
1781 * %%F Equivalent to %Y-%m-%d (the ISO 8601 date format).
1782 * %%h Equivalent to %b.
1783 * %%H The hour as a decimal number using a 24-hour clock (range 00 to 23).
1784 * %%I The hour as a decimal number using a 12-hour clock (range 01 to 12).
1785 * %%j The day of the year as a decimal number (range 001 to 366).
1786 * %%k The hour (24-hour clock) as a decimal number (range 0 to 23);
1787 * single digits are preceded by a blank.
1788 * %%l The hour (12-hour clock) as a decimal number (range 1 to 12);
1789 * single digits are preceded by a blank.
1790 * %%m The month as a decimal number (range 01 to 12).
1791 * %%M The minute as a decimal number (range 00 to 59).
1792 * %%N The micro-seconds as a decimal number.
1793 * %%p Either "AM" or "PM" according to the given time value, or the
1794 * corresponding strings for the current locale. Noon is treated
1795 * as "PM" and midnight as "AM".
1796 * %%P Like %%p but lowercase: "am" or "pm" or a corresponding string for
1797 * the current locale.
1798 * %%r The time in a.m. or p.m. notation.
1799 * %%R The time in 24-hour notation (%H:%M).
1800 * %%s The number of seconds since the Epoch, that is, since 1970-01-01
1802 * %%S The second as a decimal number (range 00 to 60).
1803 * %%t A tab character.
1804 * %%u The day of the week as a decimal, range 1 to 7, Monday being 1.
1805 * %%W The week number of the current year as a decimal number.
1806 * %%x The preferred date representation for the current locale without
1808 * %%X The preferred date representation for the current locale without
1810 * %%y The year as a decimal number without the century.
1811 * %%Y The year as a decimal number including the century.
1812 * %%Z Alphabetic time zone abbreviation (e.g. EDT).
1813 * %%% A literal %% character.
1815 * Return value: a newly allocated string formatted to the requested format or
1816 * %NULL in the case that there was an error. The string should be freed
1822 g_date_time_printf (const GDateTime *datetime,
1823 const gchar *format)
1833 g_return_val_if_fail (datetime != NULL, NULL);
1834 g_return_val_if_fail (format != NULL, NULL);
1835 g_return_val_if_fail (g_utf8_validate (format, -1, NULL), NULL);
1837 outstr = g_string_sized_new (strlen (format) * 2);
1838 utf8len = g_utf8_strlen (format, -1);
1841 for (i = 0; i < utf8len; i++)
1843 tmp = g_utf8_offset_to_pointer (format, i);
1844 c = g_utf8_get_char (tmp);
1859 g_string_append (outstr, WEEKDAY_ABBR (datetime));
1862 g_string_append (outstr, WEEKDAY_FULL (datetime));
1865 g_string_append (outstr, MONTH_ABBR (datetime));
1868 g_string_append (outstr, MONTH_FULL (datetime));
1871 g_string_append_printf (outstr, "%02d",
1872 g_date_time_get_day_of_month (datetime));
1875 g_string_append_printf (outstr, "%2d",
1876 g_date_time_get_day_of_month (datetime));
1879 g_string_append_printf (outstr, "%d-%02d-%02d",
1880 g_date_time_get_year (datetime),
1881 g_date_time_get_month (datetime),
1882 g_date_time_get_day_of_month (datetime));
1885 g_string_append (outstr, MONTH_ABBR (datetime));
1888 g_string_append_printf (outstr, "%02d",
1889 g_date_time_get_hour (datetime));
1892 if (g_date_time_get_hour (datetime) == 0)
1893 g_string_append (outstr, "12");
1895 g_string_append_printf (outstr, "%02d",
1896 g_date_time_get_hour (datetime) % 12);
1899 g_string_append_printf (outstr, "%03d",
1900 g_date_time_get_day_of_year (datetime));
1903 g_string_append_printf (outstr, "%2d",
1904 g_date_time_get_hour (datetime));
1907 if (g_date_time_get_hour (datetime) == 0)
1908 g_string_append (outstr, "12");
1910 g_string_append_printf (outstr, "%2d",
1911 g_date_time_get_hour (datetime) % 12);
1914 g_string_append_printf (outstr, "%02d",
1915 g_date_time_get_month (datetime));
1918 g_string_append_printf (outstr, "%02d",
1919 g_date_time_get_minute (datetime));
1922 g_string_append_printf (outstr, "%"G_GUINT64_FORMAT,
1923 datetime->usec % USEC_PER_SECOND);
1926 g_string_append (outstr, GET_AMPM (datetime, FALSE));
1929 g_string_append (outstr, GET_AMPM (datetime, TRUE));
1932 gint hour = g_date_time_get_hour (datetime) % 12;
1935 g_string_append_printf (outstr, "%02d:%02d:%02d %s",
1937 g_date_time_get_minute (datetime),
1938 g_date_time_get_second (datetime),
1939 GET_AMPM (datetime, FALSE));
1943 g_string_append_printf (outstr, "%02d:%02d",
1944 g_date_time_get_hour (datetime),
1945 g_date_time_get_minute (datetime));
1948 g_string_append_printf (outstr, "%" G_GINT64_FORMAT,
1949 g_date_time_to_epoch (datetime));
1952 g_string_append_printf (outstr, "%02d",
1953 g_date_time_get_second (datetime));
1956 g_string_append_c (outstr, '\t');
1959 g_string_append_printf (outstr, "%d",
1960 g_date_time_get_day_of_week (datetime));
1963 g_string_append_printf (outstr, "%d",
1964 g_date_time_get_day_of_year (datetime) / 7);
1967 tmp2 = GET_PREFERRED_DATE (datetime);
1968 g_string_append (outstr, tmp2);
1973 tmp2 = GET_PREFERRED_TIME (datetime);
1974 g_string_append (outstr, tmp2);
1979 g_string_append_printf (outstr, "%02d",
1980 g_date_time_get_year (datetime) % 100);
1983 g_string_append_printf (outstr, "%d",
1984 g_date_time_get_year (datetime));
1988 g_string_append_printf (outstr, "%s", datetime->tz->name);
1990 g_string_append_printf (outstr, "UTC");
1993 g_string_append_c (outstr, '%');
1996 g_string_append_c (outstr, '\n');
2004 g_string_append_unichar (outstr, c);
2009 g_string_free (outstr, FALSE);
2014 g_string_free (outstr, TRUE);
2020 * @datetime: a #GDateTime
2022 * Atomically increments the reference count of @datetime by one.
2024 * Return value: the #GDateTime with the reference count increased
2029 g_date_time_ref (GDateTime *datetime)
2031 g_return_val_if_fail (datetime != NULL, NULL);
2032 g_return_val_if_fail (datetime->ref_count > 0, NULL);
2034 g_atomic_int_inc (&datetime->ref_count);
2040 * g_date_time_unref:
2041 * @datetime: a #GDateTime
2043 * Atomically decrements the reference count of @datetime by one.
2045 * When the reference count reaches zero, the resources allocated by
2046 * @datetime are freed
2051 g_date_time_unref (GDateTime *datetime)
2053 g_return_if_fail (datetime != NULL);
2054 g_return_if_fail (datetime->ref_count > 0);
2056 if (g_atomic_int_dec_and_test (&datetime->ref_count))
2057 g_date_time_free (datetime);
2061 * g_date_time_to_local:
2062 * @datetime: a #GDateTime
2064 * Creates a new #GDateTime with @datetime converted to local time.
2066 * Return value: the newly created #GDateTime
2071 g_date_time_to_local (const GDateTime *datetime)
2075 g_return_val_if_fail (datetime != NULL, NULL);
2077 dt = g_date_time_copy (datetime);
2080 dt->tz = g_date_time_create_time_zone (dt, NULL);
2084 g_date_time_add_usec (dt, dt->tz->offset * USEC_PER_SECOND);
2091 * g_date_time_to_epoch:
2092 * @datetime: a #GDateTime
2094 * Converts @datetime into an integer representing seconds since the
2097 * Return value: @datetime as seconds since the Unix epoch
2102 g_date_time_to_epoch (const GDateTime *datetime)
2109 g_return_val_if_fail (datetime != NULL, 0);
2110 g_return_val_if_fail (datetime->period == 0, 0);
2112 g_date_time_get_dmy (datetime, &day, &month, &year);
2114 /* FIXME we use gint64, we shold expand these limits */
2117 else if (year > 2037)
2120 memset (&tm, 0, sizeof (tm));
2122 tm.tm_year = year - 1900;
2123 tm.tm_mon = month - 1;
2125 tm.tm_hour = g_date_time_get_hour (datetime);
2126 tm.tm_min = g_date_time_get_minute (datetime);
2127 tm.tm_sec = g_date_time_get_second (datetime);
2130 return (gint64) mktime (&tm);
2134 * g_date_time_to_timeval:
2135 * @datetime: a #GDateTime
2138 * Converts @datetime into a #GTimeVal and stores the result into @timeval.
2143 g_date_time_to_timeval (const GDateTime *datetime,
2146 g_return_if_fail (datetime != NULL);
2151 if (G_LIKELY (datetime->period == 0))
2153 tv->tv_sec = g_date_time_to_epoch (datetime);
2154 tv->tv_usec = datetime->usec % USEC_PER_SECOND;
2159 * g_date_time_to_utc:
2160 * @datetime: a #GDateTime
2162 * Creates a new #GDateTime that reprents @datetime in Universal coordinated
2165 * Return value: the newly created #GDateTime which should be freed with
2166 * g_date_time_unref().
2171 g_date_time_to_utc (const GDateTime *datetime)
2176 g_return_val_if_fail (datetime != NULL, NULL);
2178 ts = g_date_time_get_utc_offset (datetime) * -1;
2179 dt = g_date_time_add (datetime, ts);
2186 * g_date_time_new_today:
2188 * Createsa new #GDateTime that represents Midnight on the current day.
2190 * Return value: the newly created #GDateTime which should be freed with
2191 * g_date_time_unref().
2196 g_date_time_new_today (void)
2200 dt = g_date_time_new_now ();
2207 * g_date_time_new_utc_now:
2209 * Creates a new #GDateTime that represents the current instant in Universal
2210 * Coordinated Time (UTC).
2212 * Return value: the newly created #GDateTime which should be freed with
2213 * g_date_time_unref().
2218 g_date_time_new_utc_now (void)
2220 GDateTime *utc, *now;
2222 now = g_date_time_new_now ();
2223 utc = g_date_time_to_utc (now);
2224 g_date_time_unref (now);