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
51 #endif /* !G_OS_WIN32 */
53 #include "gdatetime.h"
56 #include "gfileutils.h"
59 #include "gmappedfile.h"
60 #include "gstrfuncs.h"
61 #include "gtestutils.h"
69 * @short_description: A structure representing Date and Time
71 * #GDateTime is a structure that combines a date and time into a single
72 * structure. It provides many conversion and methods to manipulate dates
73 * and times. Time precision is provided down to microseconds.
75 * #GDateTime is an immutable object: once it has been created it cannot be
76 * modified further. All modifiers will create a new #GDateTime.
78 * #GDateTime is reference counted: the reference count is increased by calling
79 * g_date_time_ref() and decreased by calling g_date_time_unref(). When the
80 * reference count drops to 0, the resources allocated by the #GDateTime
81 * structure are released.
83 * Internally, #GDateTime uses the Proleptic Gregorian Calendar, the first
84 * representable date is 0001-01-01. However, the public API uses the
85 * internationally accepted Gregorian Calendar.
87 * #GDateTime is available since GLib 2.26.
90 #define UNIX_EPOCH_START 719163
92 #define DAYS_IN_4YEARS 1461 /* days in 4 years */
93 #define DAYS_IN_100YEARS 36524 /* days in 100 years */
94 #define DAYS_IN_400YEARS 146097 /* days in 400 years */
96 #define USEC_PER_SECOND (G_GINT64_CONSTANT (1000000))
97 #define USEC_PER_MINUTE (G_GINT64_CONSTANT (60000000))
98 #define USEC_PER_HOUR (G_GINT64_CONSTANT (3600000000))
99 #define USEC_PER_MILLISECOND (G_GINT64_CONSTANT (1000))
100 #define USEC_PER_DAY (G_GINT64_CONSTANT (86400000000))
101 #define SEC_PER_DAY (G_GINT64_CONSTANT (86400))
103 #define GREGORIAN_LEAP(y) ((((y) % 4) == 0) && (!((((y) % 100) == 0) && (((y) % 400) != 0))))
104 #define JULIAN_YEAR(d) ((d)->julian / 365.25)
105 #define DAYS_PER_PERIOD (G_GINT64_CONSTANT (2914695))
107 #define GET_AMPM(d,l) ((g_date_time_get_hour (d) < 12) \
108 /* Translators: 'before midday' indicator */ \
109 ? (l ? C_("GDateTime", "am") \
110 /* Translators: 'before midday' indicator */ \
111 : C_("GDateTime", "AM")) \
112 /* Translators: 'after midday' indicator */ \
113 : (l ? C_("GDateTime", "pm") \
114 /* Translators: 'after midday' indicator */ \
115 : C_("GDateTime", "PM")))
117 #define WEEKDAY_ABBR(d) (get_weekday_name_abbr (g_date_time_get_day_of_week (datetime)))
118 #define WEEKDAY_FULL(d) (get_weekday_name (g_date_time_get_day_of_week (datetime)))
120 #define MONTH_ABBR(d) (get_month_name_abbr (g_date_time_get_month (datetime)))
121 #define MONTH_FULL(d) (get_month_name (g_date_time_get_month (datetime)))
123 /* Translators: this is the preferred format for expressing the date */
124 #define GET_PREFERRED_DATE(d) (g_date_time_printf ((d), C_("GDateTime", "%m/%d/%y")))
126 /* Translators: this is the preferred format for expressing the time */
127 #define GET_PREFERRED_TIME(d) (g_date_time_printf ((d), C_("GDateTime", "%H:%M:%S")))
129 #define SECS_PER_MINUTE (60)
130 #define SECS_PER_HOUR (60 * SECS_PER_MINUTE)
131 #define SECS_PER_DAY (24 * SECS_PER_HOUR)
132 #define SECS_PER_YEAR (365 * SECS_PER_DAY)
133 #define SECS_PER_JULIAN (DAYS_PER_PERIOD * SECS_PER_DAY)
135 typedef struct _GTimeZoneFile GTimeZoneFile;
139 /* 1 is 0001-01-01 in Proleptic Gregorian */
142 /* Microsecond timekeeping within Day */
145 /* TimeZone information, NULL is UTC */
148 volatile gint ref_count;
153 GTimeZoneFile *tz_file;
161 guint is_floating : 1;
164 struct _GTimeZoneFile
170 volatile gint ref_count;
173 G_LOCK_DEFINE_STATIC (time_zone_files);
174 static GHashTable *time_zone_files = NULL;
176 static const guint16 days_in_months[2][13] =
178 { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
179 { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
182 static const guint16 days_in_year[2][13] =
184 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
185 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
189 get_month_name (gint month)
194 return C_("full month name", "January");
196 return C_("full month name", "February");
198 return C_("full month name", "March");
200 return C_("full month name", "April");
202 return C_("full month name", "May");
204 return C_("full month name", "June");
206 return C_("full month name", "July");
208 return C_("full month name", "August");
210 return C_("full month name", "September");
212 return C_("full month name", "October");
214 return C_("full month name", "November");
216 return C_("full month name", "December");
219 g_warning ("Invalid month number %d", month);
226 get_month_name_abbr (gint month)
231 return C_("abbreviated month name", "Jan");
233 return C_("abbreviated month name", "Feb");
235 return C_("abbreviated month name", "Mar");
237 return C_("abbreviated month name", "Apr");
239 return C_("abbreviated month name", "May");
241 return C_("abbreviated month name", "Jun");
243 return C_("abbreviated month name", "Jul");
245 return C_("abbreviated month name", "Aug");
247 return C_("abbreviated month name", "Sep");
249 return C_("abbreviated month name", "Oct");
251 return C_("abbreviated month name", "Nov");
253 return C_("abbreviated month name", "Dec");
256 g_warning ("Invalid month number %d", month);
263 get_weekday_name (gint day)
268 return C_("full weekday name", "Monday");
270 return C_("full weekday name", "Tuesday");
272 return C_("full weekday name", "Wednesday");
274 return C_("full weekday name", "Thursday");
276 return C_("full weekday name", "Friday");
278 return C_("full weekday name", "Saturday");
280 return C_("full weekday name", "Sunday");
283 g_warning ("Invalid week day number %d", day);
290 get_weekday_name_abbr (gint day)
295 return C_("abbreviated weekday name", "Mon");
297 return C_("abbreviated weekday name", "Tue");
299 return C_("abbreviated weekday name", "Wed");
301 return C_("abbreviated weekday name", "Thu");
303 return C_("abbreviated weekday name", "Fri");
305 return C_("abbreviated weekday name", "Sat");
307 return C_("abbreviated weekday name", "Sun");
310 g_warning ("Invalid week day number %d", day);
316 #define ZONEINFO_DIR "zoneinfo"
317 #define TZ_MAGIC "TZif"
318 #define TZ_MAGIC_LEN (strlen (TZ_MAGIC))
319 #define TZ_HEADER_SIZE 44
320 #define TZ_TIMECNT_OFFSET 32
321 #define TZ_TYPECNT_OFFSET 36
322 #define TZ_TRANSITIONS_OFFSET 44
323 #define TZ_TTINFO_SIZE 6
324 #define TZ_TTINFO_GMTOFF_OFFSET 0
325 #define TZ_TTINFO_ISDST_OFFSET 4
326 #define TZ_TTINFO_NAME_OFFSET 5
329 get_tzdata_path (const gchar *tz_name)
331 gchar *retval = NULL;
332 const gchar *tz_dir = g_getenv ("TZDIR");
335 retval = g_build_filename (tz_dir, tz_name, NULL);
338 if (strcmp (tz_name, "localtime") == 0)
339 retval = g_build_filename ("/", "etc", "localtime", NULL);
341 retval = g_build_filename ("/", "usr", "share", ZONEINFO_DIR, tz_name, NULL);
348 parse_tzdata (GTimeZoneFile *tz_file,
357 guint32 timecnt, typecnt;
358 gint transitions_size, ttinfo_map_size;
359 guint8 *ttinfo_map, *ttinfos;
360 gint start_transition = -1;
361 guint32 *transitions;
367 contents = g_mapped_file_get_contents (tz_file->file);
368 length = g_mapped_file_get_length (tz_file->file);
370 if (length < TZ_HEADER_SIZE ||
371 (strncmp (contents, TZ_MAGIC, TZ_MAGIC_LEN) != 0))
376 timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
377 typecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TYPECNT_OFFSET));
379 transitions = (guint32 *)(contents + TZ_TRANSITIONS_OFFSET);
380 transitions_size = timecnt * sizeof (*transitions);
381 ttinfo_map = (void *)(contents + TZ_TRANSITIONS_OFFSET + transitions_size);
382 ttinfo_map_size = timecnt;
383 ttinfos = (void *)(ttinfo_map + ttinfo_map_size);
386 * Find the first transition that contains the 'start' time
388 for (i = 1; i < timecnt && start_transition == -1; i++)
390 gint32 transition_time = GINT32_FROM_BE (transitions[i]);
392 /* if is_utc is not set, we need to add this time offset to compare with
393 * start, because it is already on the timezone time */
398 off = *(gint32 *)(ttinfos + ttinfo_map[i] * TZ_TTINFO_SIZE +
399 TZ_TTINFO_GMTOFF_OFFSET);
400 off = GINT32_FROM_BE (off);
402 transition_time += off;
405 if (transition_time > start)
407 start_transition = ttinfo_map[i - 1];
412 if (start_transition == -1)
415 start_transition = ttinfo_map[timecnt - 1];
417 start_transition = 0;
420 /* Copy the data out of the corresponding ttinfo structs */
421 offset = *(gint32 *)(ttinfos + start_transition * TZ_TTINFO_SIZE +
422 TZ_TTINFO_GMTOFF_OFFSET);
423 offset = GINT32_FROM_BE (offset);
424 isdst = *(ttinfos + start_transition * TZ_TTINFO_SIZE +
425 TZ_TTINFO_ISDST_OFFSET);
426 name_offset = *(ttinfos + start_transition * TZ_TTINFO_SIZE +
427 TZ_TTINFO_NAME_OFFSET);
430 *_name = g_strdup ((gchar*) (ttinfos + TZ_TTINFO_SIZE * typecnt + name_offset));
441 static GTimeZoneFile *
442 g_time_zone_file_new (const gchar *filename)
444 GMappedFile *tz_file;
445 GTimeZoneFile *retval;
447 tz_file = g_mapped_file_new (filename, FALSE, NULL);
451 retval = g_slice_new (GTimeZoneFile);
452 retval->filename = g_strdup (filename);
453 retval->file = tz_file;
454 retval->ref_count = 1;
459 static GTimeZoneFile *
460 g_time_zone_file_ref (GTimeZoneFile *tz_file)
465 g_atomic_int_inc (&tz_file->ref_count);
471 g_time_zone_file_unref (GTimeZoneFile *tz_file)
476 if (g_atomic_int_dec_and_test (&tz_file->ref_count))
478 /* remove the TimeZoneFile from the hash table of known files */
479 G_LOCK (time_zone_files);
480 g_hash_table_remove (time_zone_files, tz_file->filename);
481 G_UNLOCK (time_zone_files);
483 g_mapped_file_unref (tz_file->file);
484 g_free (tz_file->filename);
485 g_slice_free (GTimeZoneFile, tz_file);
490 * g_time_zone_file_get_for_path:
491 * @path: the full path for a time zone file
493 * Retrieves a #GTimeZoneFile for the given path.
495 * If a time zone file for the same path has been already requested,
496 * this function will return the same #GTimeZoneFile with its reference
497 * count increased by one; otherwise, a new #GTimeZoneFile will be created
498 * and added to the known time zone files.
500 * The time zone files are removed from the list of known files when their
501 * reference count reaches 0.
503 * This function holds the lock on the time_zone_files hash table.
505 * Return value: a #GTimeZoneFile or %NULL
507 static GTimeZoneFile *
508 g_time_zone_file_get_for_path (const gchar *path)
510 GTimeZoneFile *retval;
512 G_LOCK (time_zone_files);
514 if (G_LIKELY (time_zone_files != NULL))
516 retval = g_hash_table_lookup (time_zone_files, path);
519 retval = g_time_zone_file_ref (retval);
524 retval = g_time_zone_file_new (path);
527 if (G_UNLIKELY (time_zone_files == NULL))
528 time_zone_files = g_hash_table_new (g_str_hash, g_str_equal);
530 g_hash_table_insert (time_zone_files, retval->filename, retval);
534 G_UNLOCK (time_zone_files);
541 * @offset: the timezone offset from UTC, in seconds
542 * @is_dst: whether the timezone is in Daylight Saving Time or not
544 * Creates a new #GTimeZone for the given @offset, to be used when
545 * creating a #GDateTime.
547 * The #GTimeZone created will not be floating.
549 * Return value: (transfer full): the newly allocated #GTimeZone
554 g_time_zone_new (gint offset,
559 g_return_val_if_fail (offset >= -12 * SECS_PER_HOUR && offset <= 12 * SECS_PER_HOUR, NULL);
561 tz = g_slice_new (GTimeZone);
565 tz->is_floating = FALSE;
568 tz->name = g_strdup_printf ("UTC");
570 tz->name = g_strdup_printf ("UTC%c%02d:%02d",
571 tz->offset > 0 ? '+' : '-',
572 (int) tz->offset / 3600,
573 (int) tz->offset / 60 % 60);
579 * g_time_zone_new_for_name:
580 * @name: an ASCII string containing the Olson's database name of the
581 * timezone, e.g. "America/New_York" or "Europe/London"
583 * Creates a new #GTimeZone for the given @name.
585 * The returned timezone is "floating": if queried, it will return invalid
586 * values. A floating #GTimeZone is "sunk" when it is bound to a #GDateTime
592 * /* the time zone is "floating" */
593 * GTimeZone *tz = g_time_zone_new_for_name ("Europe/London");
595 * /* this will print: "UTC offset: 0 seconds" */
596 * g_print ("UTC offset: %d seconds\n", g_time_zone_get_offset (tz));
598 * /* the GDateTime object copies the time zone */
599 * GDateTime *dt = g_date_time_new_full (2010, 9, 15, 12, 0, 0, tz);
601 * /* this will print: "UTC offset: 3600 seconds", because Europe/London
602 * * on that date is in daylight saving time
604 * g_print ("UTC offset: %d seconds\n",
605 * g_date_time_get_utc_offset (dt) / G_USEC_PER_SEC);
608 * Return value: (transfer full): the newly created, floating #GTimeZone
609 * object for the given name, or %NULL if none was found
614 g_time_zone_new_for_name (const gchar *name)
618 GTimeZoneFile *tz_file;
620 g_return_val_if_fail (name != NULL, NULL);
622 filename = get_tzdata_path (name);
623 if (filename == NULL)
626 tz_file = g_time_zone_file_get_for_path (filename);
632 tz = g_slice_new (GTimeZone);
633 tz->tz_file = tz_file;
637 tz->is_utc = (strcmp (name, "UTC") == 0);
638 tz->is_floating = TRUE;
644 * g_time_zone_new_utc:
646 * Creates a new #GTimeZone for UTC.
648 * Return value: (transfer full): a newly created #GTimeZone for UTC.
649 * Use g_time_zone_free() when done.
654 g_time_zone_new_utc (void)
656 return g_time_zone_new (0, FALSE);
660 * g_time_zone_new_local:
662 * Creates a new #GTimeZone for the local timezone.
664 * The returned #GTimeZone is floating.
666 * Return value: (transfer full): a newly created, floating #GTimeZone.
667 * Use g_time_zone_free() when done.
672 g_time_zone_new_local (void)
674 return g_time_zone_new_for_name ("localtime");
679 * @time_zone: a #GTimeZone
681 * Copies a #GTimeZone. If @time_zone is floating, the returned copy
682 * will be floating as well.
684 * Return value: (transfer full): the newly created #GTimeZone
689 g_time_zone_copy (const GTimeZone *time_zone)
693 g_return_val_if_fail (time_zone != NULL, NULL);
695 retval = g_slice_dup (GTimeZone, time_zone);
697 if (time_zone->tz_file != NULL)
698 retval->tz_file = g_time_zone_file_ref (time_zone->tz_file);
700 if (time_zone->name != NULL)
701 retval->name = g_strdup (time_zone->name);
708 * @time_zone: a #GTimeZone
710 * Frees the resources associated with a #GTimeZone
715 g_time_zone_free (GTimeZone *time_zone)
717 g_return_if_fail (time_zone != NULL);
719 if (time_zone->tz_file != NULL)
720 g_time_zone_file_unref (time_zone->tz_file);
722 g_free (time_zone->name);
723 g_slice_free (GTimeZone, time_zone);
727 * g_time_zone_get_name:
728 * @time_zone: a #GTimeZone
730 * Retrieves the name of the @time_zone, or %NULL if the #GTimeZone is
733 * Return value: (transfer none): the name of the #GTimeZone. The returned
734 * string is owned by the #GTimeZone and it should never be modified or
739 G_CONST_RETURN gchar *
740 g_time_zone_get_name (const GTimeZone *time_zone)
742 g_return_val_if_fail (time_zone != NULL, NULL);
744 if (!time_zone->is_floating)
745 return time_zone->name;
751 * g_time_zone_get_offset:
752 * @time_zone: a #GTimeZone
754 * Retrieves the offset of the @time_zone, in seconds from UTC, or 0
755 * if the #GTimeZone is floating.
757 * Return value: the offset from UTC, in seconds
762 g_time_zone_get_offset (const GTimeZone *time_zone)
764 g_return_val_if_fail (time_zone != NULL, 0);
766 if (!time_zone->is_floating)
767 return time_zone->offset;
773 * g_time_zone_get_is_dst:
774 * @time_zone: a #GTimeZone
776 * Checks whether the @time_zone is in Daylight Saving Time.
777 * If the #GTimeZone is floating, %FALSE is always returned.
779 * Return value: %TRUE if the #GTimeZone is in DST, or %FALSE.
784 g_time_zone_get_is_dst (const GTimeZone *time_zone)
786 g_return_val_if_fail (time_zone != NULL, FALSE);
788 if (!time_zone->is_floating)
789 return time_zone->is_dst;
795 * g_time_zone_is_floating:
796 * @time_zone: a #GTimeZone
798 * Checks whether @time_zone is floating
800 * Return value: %TRUE if the #GTimeZone is floating, and %FALSE otherwise
805 g_time_zone_is_floating (const GTimeZone *time_zone)
807 g_return_val_if_fail (time_zone != NULL, FALSE);
809 return time_zone->is_floating;
814 * @time_zone: a #GTimeZone
815 * @datetime: a #GDateTime
817 * Sinks the floating state of @time_zone by associating it with the
820 * If @time_zone is not floating, this function does not do anything
823 g_time_zone_sink (GTimeZone *time_zone,
826 gint64 offset, epoch;
827 gboolean is_dst, is_utc;
830 if (!time_zone->is_floating)
833 epoch = g_date_time_to_epoch (datetime);
834 is_utc = time_zone->is_utc;
838 if (parse_tzdata (time_zone->tz_file, epoch, is_utc, &offset, &is_dst, &abbrev))
840 time_zone->offset = offset;
841 time_zone->is_dst = is_dst;
842 time_zone->name = abbrev;
843 time_zone->is_utc = (offset == 0);
844 time_zone->is_floating = FALSE;
849 date_to_proleptic_gregorian (gint year,
855 days = (year - 1) * 365 + ((year - 1) / 4) - ((year - 1) / 100)
856 + ((year - 1) / 400);
858 days += days_in_year[0][month - 1];
859 if (GREGORIAN_LEAP (year) && month > 2)
867 static inline void g_date_time_add_usec (GDateTime *datetime,
871 g_date_time_add_days_internal (GDateTime *datetime,
874 gboolean was_dst = FALSE;
875 gint64 old_offset = 0;
877 if (datetime->tz != NULL && datetime->tz->tz_file != NULL)
879 was_dst = g_time_zone_get_is_dst (datetime->tz);
880 old_offset = g_time_zone_get_offset (datetime->tz);
882 datetime->tz->is_floating = TRUE;
885 datetime->days += days;
887 if (datetime->tz != NULL && datetime->tz->tz_file != NULL)
891 g_time_zone_sink (datetime->tz, datetime);
893 if (was_dst == g_time_zone_get_is_dst (datetime->tz))
896 offset = old_offset - g_time_zone_get_offset (datetime->tz);
897 g_date_time_add_usec (datetime, offset * USEC_PER_SECOND * -1);
902 g_date_time_add_usec (GDateTime *datetime,
905 gint64 u = datetime->usec + usecs;
906 gint d = u / USEC_PER_DAY;
907 gboolean was_dst = FALSE;
908 gint64 old_offset = 0;
910 /* if we are using a time zone from a zoneinfo we want to
911 * check for changes in the DST and update the DateTime
912 * accordingly in case we change for standard time to DST
915 if (datetime->tz != NULL && datetime->tz->tz_file != NULL)
917 was_dst = g_time_zone_get_is_dst (datetime->tz);
918 old_offset = g_time_zone_get_offset (datetime->tz);
920 /* force the floating state */
921 datetime->tz->is_floating = TRUE;
928 g_date_time_add_days_internal (datetime, d);
931 datetime->usec = USEC_PER_DAY + (u % USEC_PER_DAY);
933 datetime->usec = u % USEC_PER_DAY;
935 if (datetime->tz != NULL && datetime->tz->tz_file != NULL)
939 /* sink the timezone; if there were no changes in the
940 * DST state then bail out; otherwise, apply the change
941 * in the offset to the DateTime
943 g_time_zone_sink (datetime->tz, datetime);
945 if (was_dst == g_time_zone_get_is_dst (datetime->tz))
948 offset = old_offset - g_time_zone_get_offset (datetime->tz);
949 g_date_time_add_usec (datetime, offset * USEC_PER_SECOND * -1);
954 * g_date_time_add_ymd:
955 * @datetime: a #GDateTime
956 * @years: years to add, in the Gregorian calendar
957 * @months: months to add, in the Gregorian calendar
958 * @days: days to add, in the Gregorian calendar
960 * Updates @datetime by adding @years, @months and @days to it
962 * This function modifies the passed #GDateTime so public accessors
963 * should make always pass a copy
966 g_date_time_add_ymd (GDateTime *datetime,
971 gint y = g_date_time_get_year (datetime);
972 gint m = g_date_time_get_month (datetime);
973 gint d = g_date_time_get_day_of_month (datetime);
975 const guint16 *max_days;
979 /* subtract one day for leap years */
980 if (GREGORIAN_LEAP (y) && m == 2)
987 step = months > 0 ? 1 : -1;
988 for (i = 0; i < ABS (months); i++)
1004 /* clamp the days */
1005 max_days = days_in_months[GREGORIAN_LEAP (y) ? 1 : 0];
1006 if (max_days[m] < d)
1009 datetime->days = date_to_proleptic_gregorian (y, m, d);
1010 g_date_time_add_days_internal (datetime, days);
1014 g_date_time_new (void)
1016 GDateTime *datetime;
1018 datetime = g_slice_new0 (GDateTime);
1019 datetime->ref_count = 1;
1026 * @datetime: a #GDateTime
1028 * Creates a copy of @datetime.
1030 * Return value: the newly created #GDateTime which should be freed with
1031 * g_date_time_unref().
1034 g_date_time_copy (const GDateTime *datetime)
1038 g_return_val_if_fail (datetime != NULL, NULL);
1040 copied = g_date_time_new ();
1041 copied->days = datetime->days;
1042 copied->usec = datetime->usec;
1044 if (datetime->tz != NULL)
1045 copied->tz = g_time_zone_copy (datetime->tz);
1051 g_date_time_free (GDateTime *datetime)
1053 if (G_UNLIKELY (datetime == NULL))
1056 if (datetime->tz != NULL)
1057 g_time_zone_free (datetime->tz);
1059 g_slice_free (GDateTime, datetime);
1064 * @datetime: a #GDateTime
1066 * Atomically increments the reference count of @datetime by one.
1068 * Return value: the #GDateTime with the reference count increased
1073 g_date_time_ref (GDateTime *datetime)
1075 g_return_val_if_fail (datetime != NULL, NULL);
1076 g_return_val_if_fail (datetime->ref_count > 0, NULL);
1078 g_atomic_int_inc (&datetime->ref_count);
1084 * g_date_time_unref:
1085 * @datetime: a #GDateTime
1087 * Atomically decrements the reference count of @datetime by one.
1089 * When the reference count reaches zero, the resources allocated by
1090 * @datetime are freed
1095 g_date_time_unref (GDateTime *datetime)
1097 g_return_if_fail (datetime != NULL);
1098 g_return_if_fail (datetime->ref_count > 0);
1100 if (g_atomic_int_dec_and_test (&datetime->ref_count))
1101 g_date_time_free (datetime);
1105 g_date_time_get_week_number (const GDateTime *datetime,
1110 gint a, b, c, d, e, f, g, n, s, month, day, year;
1112 g_date_time_get_dmy (datetime, &day, &month, &year);
1116 a = g_date_time_get_year (datetime) - 1;
1117 b = (a / 4) - (a / 100) + (a / 400);
1118 c = ((a - 1) / 4) - ((a - 1) / 100) + ((a - 1) / 400);
1121 f = day - 1 + (31 * (month - 1));
1126 b = (a / 4) - (a / 100) + (a / 400);
1127 c = ((a - 1) / 4) - ((a - 1) / 100) + ((a - 1) / 400);
1130 f = day + (((153 * (month - 3)) + 2) / 5) + 58 + s;
1134 d = (f + g - e) % 7;
1140 *week_number = 53 - ((g - s) / 5);
1141 else if (n > 364 + s)
1144 *week_number = (n / 7) + 1;
1148 *day_of_week = d + 1;
1151 *day_of_year = f + 1;
1156 * @datetime: a #GDateTime
1157 * @timespan: a #GTimeSpan
1159 * Creates a copy of @datetime and adds the specified timespan to the copy.
1161 * Return value: the newly created #GDateTime which should be freed with
1162 * g_date_time_unref().
1167 g_date_time_add (const GDateTime *datetime,
1172 g_return_val_if_fail (datetime != NULL, NULL);
1174 dt = g_date_time_copy (datetime);
1175 g_date_time_add_usec (dt, timespan);
1181 * g_date_time_add_years:
1182 * @datetime: a #GDateTime
1183 * @years: the number of years
1185 * Creates a copy of @datetime and adds the specified number of years to the
1188 * Return value: the newly created #GDateTime which should be freed with
1189 * g_date_time_unref().
1194 g_date_time_add_years (const GDateTime *datetime,
1199 g_return_val_if_fail (datetime != NULL, NULL);
1201 dt = g_date_time_copy (datetime);
1202 g_date_time_add_ymd (dt, years, 0, 0);
1208 * g_date_time_add_months:
1209 * @datetime: a #GDateTime
1210 * @months: the number of months
1212 * Creates a copy of @datetime and adds the specified number of months to the
1215 * Return value: the newly created #GDateTime which should be freed with
1216 * g_date_time_unref().
1221 g_date_time_add_months (const GDateTime *datetime,
1226 g_return_val_if_fail (datetime != NULL, NULL);
1228 dt = g_date_time_copy (datetime);
1229 g_date_time_add_ymd (dt, 0, months, 0);
1235 * g_date_time_add_weeks:
1236 * @datetime: a #GDateTime
1237 * @weeks: the number of weeks
1239 * Creates a copy of @datetime and adds the specified number of weeks to the
1242 * Return value: the newly created #GDateTime which should be freed with
1243 * g_date_time_unref().
1248 g_date_time_add_weeks (const GDateTime *datetime,
1251 g_return_val_if_fail (datetime != NULL, NULL);
1253 return g_date_time_add_days (datetime, weeks * 7);
1257 * g_date_time_add_days:
1258 * @datetime: a #GDateTime
1259 * @days: the number of days
1261 * Creates a copy of @datetime and adds the specified number of days to the
1264 * Return value: the newly created #GDateTime which should be freed with
1265 * g_date_time_unref().
1270 g_date_time_add_days (const GDateTime *datetime,
1275 g_return_val_if_fail (datetime != NULL, NULL);
1277 dt = g_date_time_copy (datetime);
1278 g_date_time_add_ymd (dt, 0, 0, days);
1284 * g_date_time_add_hours:
1285 * @datetime: a #GDateTime
1286 * @hours: the number of hours to add
1288 * Creates a copy of @datetime and adds the specified number of hours
1290 * Return value: the newly created #GDateTime which should be freed with
1291 * g_date_time_unref().
1296 g_date_time_add_hours (const GDateTime *datetime,
1301 g_return_val_if_fail (datetime != NULL, NULL);
1303 dt = g_date_time_copy (datetime);
1304 g_date_time_add_usec (dt, (gint64) hours * USEC_PER_HOUR);
1310 * g_date_time_add_seconds:
1311 * @datetime: a #GDateTime
1312 * @seconds: the number of seconds to add
1314 * Creates a copy of @datetime and adds the specified number of seconds.
1316 * Return value: the newly created #GDateTime which should be freed with
1317 * g_date_time_unref().
1322 g_date_time_add_seconds (const GDateTime *datetime,
1327 g_return_val_if_fail (datetime != NULL, NULL);
1329 dt = g_date_time_copy (datetime);
1330 g_date_time_add_usec (dt, (gint64) seconds * USEC_PER_SECOND);
1336 * g_date_time_add_milliseconds:
1337 * @datetime: a #GDateTime
1338 * @milliseconds: the number of milliseconds to add
1340 * Creates a copy of @datetime adding the specified number of milliseconds.
1342 * Return value: the newly created #GDateTime which should be freed with
1343 * g_date_time_unref().
1348 g_date_time_add_milliseconds (const GDateTime *datetime,
1353 g_return_val_if_fail (datetime != NULL, NULL);
1355 dt = g_date_time_copy (datetime);
1356 g_date_time_add_usec (dt, (gint64) milliseconds * USEC_PER_MILLISECOND);
1362 * g_date_time_add_minutes:
1363 * @datetime: a #GDateTime
1364 * @minutes: the number of minutes to add
1366 * Creates a copy of @datetime adding the specified number of minutes.
1368 * Return value: the newly created #GDateTime which should be freed with
1369 * g_date_time_unref().
1374 g_date_time_add_minutes (const GDateTime *datetime,
1379 g_return_val_if_fail (datetime != NULL, NULL);
1381 dt = g_date_time_copy (datetime);
1382 g_date_time_add_usec (dt, (gint64) minutes * USEC_PER_MINUTE);
1388 * g_date_time_add_full:
1389 * @datetime: a #GDateTime
1390 * @years: the number of years to add
1391 * @months: the number of months to add
1392 * @days: the number of days to add
1393 * @hours: the number of hours to add
1394 * @minutes: the number of minutes to add
1395 * @seconds: the number of seconds to add
1397 * Creates a new #GDateTime adding the specified values to the current date and
1398 * time in @datetime.
1400 * Return value: the newly created #GDateTime that should be freed with
1401 * g_date_time_unref().
1406 g_date_time_add_full (const GDateTime *datetime,
1417 g_return_val_if_fail (datetime != NULL, NULL);
1419 dt = g_date_time_copy (datetime);
1422 g_date_time_add_ymd (dt, years, months, days);
1425 usecs = (hours * USEC_PER_HOUR)
1426 + (minutes * USEC_PER_MINUTE)
1427 + (seconds * USEC_PER_SECOND);
1428 g_date_time_add_usec (dt, usecs);
1434 * g_date_time_compare:
1435 * @dt1: first #GDateTime to compare
1436 * @dt2: second #GDateTime to compare
1438 * qsort()-style comparison for #GDateTime<!-- -->'s. Both #GDateTime<-- -->'s
1439 * must be non-%NULL.
1441 * Return value: 0 for equal, less than zero if dt1 is less than dt2, greater
1442 * than zero if dt2 is greator than dt1.
1447 g_date_time_compare (gconstpointer dt1,
1450 const GDateTime *a, *b;
1455 if ((a->days == b->days )&&
1456 (a->usec == b->usec))
1460 else if ((a->days > b->days) ||
1461 ((a->days == b->days) && a->usec > b->usec))
1471 * @datetime: a #GDateTime
1473 * Creates a new #GDateTime at Midnight on the date represented by @datetime.
1475 * Return value: the newly created #GDateTime which should be freed with
1476 * g_date_time_unref().
1481 g_date_time_day (const GDateTime *datetime)
1485 g_return_val_if_fail (datetime != NULL, NULL);
1487 date = g_date_time_copy (datetime);
1494 * g_date_time_difference:
1495 * @begin: a #GDateTime
1496 * @end: a #GDateTime
1498 * Calculates the known difference in time between @begin and @end.
1500 * Since the exact precision cannot always be known due to incomplete
1501 * historic information, an attempt is made to calculate the difference.
1503 * Return value: the difference between the two #GDateTime, as a time
1504 * span expressed in microseconds.
1509 g_date_time_difference (const GDateTime *begin,
1510 const GDateTime *end)
1512 g_return_val_if_fail (begin != NULL, 0);
1513 g_return_val_if_fail (end != NULL, 0);
1515 return (GTimeSpan) (((gint64) end->days - (gint64) begin->days)
1516 * USEC_PER_DAY) + ((gint64) end->usec - (gint64) begin->usec);
1520 * g_date_time_equal:
1521 * @dt1: a #GDateTime
1522 * @dt2: a #GDateTime
1524 * Checks to see if @dt1 and @dt2 are equal.
1526 * Equal here means that they represent the same moment after converting
1527 * them to the same timezone.
1529 * Return value: %TRUE if @dt1 and @dt2 are equal
1534 g_date_time_equal (gconstpointer dt1,
1537 const GDateTime *a, *b;
1538 GDateTime *a_utc, *b_utc;
1539 gint64 a_epoch, b_epoch;
1544 a_utc = g_date_time_to_utc (a);
1545 b_utc = g_date_time_to_utc (b);
1547 a_epoch = g_date_time_to_epoch (a_utc);
1548 b_epoch = g_date_time_to_epoch (b_utc);
1550 g_date_time_unref (a_utc);
1551 g_date_time_unref (b_utc);
1553 return a_epoch == b_epoch;
1557 * g_date_time_get_day_of_week:
1558 * @datetime: a #GDateTime
1560 * Retrieves the day of the week represented by @datetime within the gregorian
1561 * calendar. 1 is Sunday, 2 is Monday, etc.
1563 * Return value: the day of the week
1568 g_date_time_get_day_of_week (const GDateTime *datetime)
1576 g_return_val_if_fail (datetime != NULL, 0);
1579 * See Calendar FAQ Section 2.6 for algorithm information
1580 * http://www.tondering.dk/claus/cal/calendar29.txt
1583 g_date_time_get_dmy (datetime, &day, &month, &year);
1584 a = (14 - month) / 12;
1586 m = month + (12 * a) - 2;
1587 dow = ((day + y + (y / 4) - (y / 100) + (y / 400) + (31 * m) / 12) % 7);
1589 /* 1 is Monday and 7 is Sunday */
1590 return (dow == 0) ? 7 : dow;
1594 * g_date_time_get_day_of_month:
1595 * @datetime: a #GDateTime
1597 * Retrieves the day of the month represented by @datetime in the gregorian
1600 * Return value: the day of the month
1605 g_date_time_get_day_of_month (const GDateTime *datetime)
1609 const guint16 *days;
1612 g_return_val_if_fail (datetime != NULL, 0);
1614 days = days_in_year[g_date_time_is_leap_year (datetime) ? 1 : 0];
1615 g_date_time_get_week_number (datetime, NULL, NULL, &day_of_year);
1617 for (i = 1; i <= 12; i++)
1619 if (days [i] >= day_of_year)
1620 return day_of_year - last;
1624 g_warn_if_reached ();
1629 * g_date_time_get_day_of_year:
1630 * @datetime: a #GDateTime
1632 * Retrieves the day of the year represented by @datetime in the Gregorian
1635 * Return value: the day of the year
1640 g_date_time_get_day_of_year (const GDateTime *datetime)
1644 g_return_val_if_fail (datetime != NULL, 0);
1646 g_date_time_get_week_number (datetime, NULL, NULL, &doy);
1651 * g_date_time_get_dmy:
1652 * @datetime: a #GDateTime.
1653 * @day: (out): the return location for the day of the month, or %NULL.
1654 * @month: (out): the return location for the monty of the year, or %NULL.
1655 * @year: (out): the return location for the gregorian year, or %NULL.
1657 * Retrieves the Gregorian day, month, and year of a given #GDateTime.
1662 g_date_time_get_dmy (const GDateTime *datetime,
1670 gint remaining_days;
1677 g_return_if_fail (datetime != NULL);
1679 remaining_days = datetime->days;
1682 * We need to convert an offset in days to its year/month/day representation.
1683 * Leap years makes this a little trickier than it should be, so we use
1684 * 400, 100 and 4 years cycles here to get to the correct year.
1687 /* Our days offset starts sets 0001-01-01 as day 1, if it was day 0 our
1688 * math would be simpler, so let's do it */
1691 the_year = (remaining_days / DAYS_IN_400YEARS) * 400 + 1;
1692 remaining_days = remaining_days % DAYS_IN_400YEARS;
1694 y100_cycles = remaining_days / DAYS_IN_100YEARS;
1695 remaining_days = remaining_days % DAYS_IN_100YEARS;
1696 the_year += y100_cycles * 100;
1698 y4_cycles = remaining_days / DAYS_IN_4YEARS;
1699 remaining_days = remaining_days % DAYS_IN_4YEARS;
1700 the_year += y4_cycles * 4;
1702 y1_cycles = remaining_days / 365;
1703 the_year += y1_cycles;
1704 remaining_days = remaining_days % 365;
1706 if (y1_cycles == 4 || y100_cycles == 4) {
1707 g_assert (remaining_days == 0);
1709 /* special case that indicates that the date is actually one year before,
1710 * in the 31th of December */
1717 /* now get the month and the day */
1718 leap = y1_cycles == 3 && (y4_cycles != 24 || y100_cycles == 3);
1720 g_assert (leap == GREGORIAN_LEAP(the_year));
1722 the_month = (remaining_days + 50) >> 5;
1723 preceding = (days_in_year[0][the_month - 1] + (the_month > 2 && leap));
1724 if (preceding > remaining_days)
1726 /* estimate is too large */
1728 preceding -= leap ? days_in_months[1][the_month]
1729 : days_in_months[0][the_month];
1732 remaining_days -= preceding;
1733 g_assert(0 <= remaining_days);
1735 the_day = remaining_days + 1;
1747 * g_date_time_get_hour:
1748 * @datetime: a #GDateTime
1750 * Retrieves the hour of the day represented by @datetime
1752 * Return value: the hour of the day
1757 g_date_time_get_hour (const GDateTime *datetime)
1759 g_return_val_if_fail (datetime != NULL, 0);
1761 return (datetime->usec / USEC_PER_HOUR);
1765 * g_date_time_get_julian:
1766 * @datetime: a #GDateTime
1767 * @period: (out): a location for the Julian period
1768 * @julian: (out): a location for the day in the Julian period
1769 * @hour: (out): a location for the hour of the day
1770 * @minute: (out): a location for the minute of the hour
1771 * @second: (out): a location for hte second of the minute
1773 * Retrieves the Julian period, day, hour, minute, and second which @datetime
1774 * represents in the Julian calendar.
1779 g_date_time_get_julian (const GDateTime *datetime,
1786 gint y, m, d, a, b, c, e, f, j;
1787 g_return_if_fail (datetime != NULL);
1789 g_date_time_get_dmy (datetime, &d, &m, &y);
1791 /* FIXME: This is probably not optimal and doesn't handle the fact that the
1792 * julian calendar has its 0 hour on midday */
1797 e = 365.25 * (y + 4716);
1798 f = 30.6001 * (m + 1);
1799 j = c + d + e + f - 1524;
1808 *hour = (datetime->usec / USEC_PER_HOUR);
1811 *minute = (datetime->usec % USEC_PER_HOUR) / USEC_PER_MINUTE;
1814 *second = (datetime->usec % USEC_PER_MINUTE) / USEC_PER_SECOND;
1818 * g_date_time_get_microsecond:
1819 * @datetime: a #GDateTime
1821 * Retrieves the microsecond of the date represented by @datetime
1823 * Return value: the microsecond of the second
1828 g_date_time_get_microsecond (const GDateTime *datetime)
1830 g_return_val_if_fail (datetime != NULL, 0);
1832 return (datetime->usec % USEC_PER_SECOND);
1836 * g_date_time_get_millisecond:
1837 * @datetime: a #GDateTime
1839 * Retrieves the millisecond of the date represented by @datetime
1841 * Return value: the millisecond of the second
1846 g_date_time_get_millisecond (const GDateTime *datetime)
1848 g_return_val_if_fail (datetime != NULL, 0);
1850 return (datetime->usec % USEC_PER_SECOND) / USEC_PER_MILLISECOND;
1854 * g_date_time_get_minute:
1855 * @datetime: a #GDateTime
1857 * Retrieves the minute of the hour represented by @datetime
1859 * Return value: the minute of the hour
1864 g_date_time_get_minute (const GDateTime *datetime)
1866 g_return_val_if_fail (datetime != NULL, 0);
1868 return (datetime->usec % USEC_PER_HOUR) / USEC_PER_MINUTE;
1872 * g_date_time_get_month:
1873 * @datetime: a #GDateTime
1875 * Retrieves the month of the year represented by @datetime in the Gregorian
1878 * Return value: the month represented by @datetime
1883 g_date_time_get_month (const GDateTime *datetime)
1887 g_return_val_if_fail (datetime != NULL, 0);
1889 g_date_time_get_dmy (datetime, NULL, &month, NULL);
1895 * g_date_time_get_second:
1896 * @datetime: a #GDateTime
1898 * Retrieves the second of the minute represented by @datetime
1900 * Return value: the second represented by @datetime
1905 g_date_time_get_second (const GDateTime *datetime)
1907 g_return_val_if_fail (datetime != NULL, 0);
1909 return (datetime->usec % USEC_PER_MINUTE) / USEC_PER_SECOND;
1913 * g_date_time_get_utc_offset:
1914 * @datetime: a #GDateTime
1916 * Retrieves the offset from UTC that the local timezone specified by
1917 * @datetime represents.
1919 * If @datetime represents UTC time, then the offset is zero.
1921 * Return value: the offset, expressed as a time span expressed in
1927 g_date_time_get_utc_offset (const GDateTime *datetime)
1931 g_return_val_if_fail (datetime != NULL, 0);
1933 if (datetime->tz != NULL)
1934 offset = g_time_zone_get_offset (datetime->tz);
1936 return (gint64) offset * USEC_PER_SECOND;
1940 * g_date_time_get_timezone_name:
1941 * @datetime: a #GDateTime
1943 * Retrieves the name of the timezone specified by @datetime, if any.
1945 * Return value: (transfer none): the name of the timezone. The returned
1946 * string is owned by the #GDateTime and it should not be modified or
1951 G_CONST_RETURN gchar *
1952 g_date_time_get_timezone_name (const GDateTime *datetime)
1954 g_return_val_if_fail (datetime != NULL, NULL);
1956 if (datetime->tz != NULL)
1957 return g_time_zone_get_name (datetime->tz);
1963 * g_date_time_get_year:
1964 * @datetime: A #GDateTime
1966 * Retrieves the year represented by @datetime in the Gregorian calendar.
1968 * Return value: the year represented by @datetime
1973 g_date_time_get_year (const GDateTime *datetime)
1977 g_return_val_if_fail (datetime != NULL, 0);
1979 g_date_time_get_dmy (datetime, NULL, NULL, &year);
1986 * @datetime: a #GDateTime
1988 * Hashes @datetime into a #guint, suitable for use within #GHashTable.
1990 * Return value: a #guint containing the hash
1995 g_date_time_hash (gconstpointer datetime)
1997 return (guint) (*((guint64 *) datetime));
2001 * g_date_time_is_leap_year:
2002 * @datetime: a #GDateTime
2004 * Determines if @datetime represents a date known to fall within
2005 * a leap year in the Gregorian calendar.
2007 * Return value: %TRUE if @datetime is a leap year.
2012 g_date_time_is_leap_year (const GDateTime *datetime)
2016 g_return_val_if_fail (datetime != NULL, FALSE);
2018 year = g_date_time_get_year (datetime);
2020 return GREGORIAN_LEAP (year);
2024 * g_date_time_is_daylight_savings:
2025 * @datetime: a #GDateTime
2027 * Determines if @datetime represents a date known to fall within daylight
2028 * savings time in the gregorian calendar.
2030 * Return value: %TRUE if @datetime falls within daylight savings time.
2035 g_date_time_is_daylight_savings (const GDateTime *datetime)
2037 g_return_val_if_fail (datetime != NULL, FALSE);
2039 if (datetime->tz == NULL)
2042 return datetime->tz->is_dst;
2046 * g_date_time_new_from_date:
2047 * @year: the Gregorian year
2048 * @month: the Gregorian month
2049 * @day: the day in the Gregorian month
2051 * Creates a new #GDateTime using the specified date within the Gregorian
2054 * Return value: the newly created #GDateTime or %NULL if it is outside of
2055 * the representable range.
2060 g_date_time_new_from_date (gint year,
2066 g_return_val_if_fail (year > -4712 && year <= 3268, NULL);
2067 g_return_val_if_fail (month > 0 && month <= 12, NULL);
2068 g_return_val_if_fail (day > 0 && day <= 31, NULL);
2070 dt = g_date_time_new ();
2072 dt->days = date_to_proleptic_gregorian (year, month, day);
2073 dt->tz = g_time_zone_new_local ();
2074 g_time_zone_sink (dt->tz, dt);
2080 * g_date_time_new_from_epoch:
2081 * @t: seconds from the Unix epoch
2083 * Creates a new #GDateTime using the time since Jan 1, 1970 specified by @t.
2085 * The timezone of the returned #GDateTime is the local time.
2087 * Return value: the newly created #GDateTime
2092 g_date_time_new_from_epoch (gint64 t)
2094 GDateTime *datetime;
2100 memset (&tm, 0, sizeof (tm));
2102 /* XXX: GLib should probably have a wrapper for this */
2103 #ifdef HAVE_LOCALTIME_R
2104 localtime_r (&tt, &tm);
2107 struct tm *ptm = localtime (&tt);
2111 /* Happens at least in Microsoft's C library if you pass a
2112 * negative time_t. Use 2000-01-01 as default date.
2114 #ifndef G_DISABLE_CHECKS
2115 g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, "ptm != NULL");
2123 memcpy ((void *) &tm, (void *) ptm, sizeof (struct tm));
2125 #endif /* HAVE_LOCALTIME_R */
2127 tz = g_time_zone_new_local ();
2128 datetime = g_date_time_new_full (tm.tm_year + 1900,
2135 g_time_zone_free (tz);
2141 * g_date_time_new_from_timeval:
2144 * Creates a new #GDateTime using the date and time specified by #GTimeVal.
2146 * The timezone of the returned #GDateTime is UTC.
2148 * Return value: the newly created #GDateTime
2153 g_date_time_new_from_timeval (GTimeVal *tv)
2155 GDateTime *datetime;
2157 g_return_val_if_fail (tv != NULL, NULL);
2159 datetime = g_date_time_new_from_epoch (tv->tv_sec);
2160 datetime->usec += tv->tv_usec;
2161 datetime->tz = g_time_zone_new_local ();
2162 g_time_zone_sink (datetime->tz, datetime);
2168 * g_date_time_new_full:
2169 * @year: the Gregorian year
2170 * @month: the Gregorian month
2171 * @day: the day of the Gregorian month
2172 * @hour: the hour of the day
2173 * @minute: the minute of the hour
2174 * @second: the second of the minute, with eventual fractionary parts
2175 * @time_zone: (allow-none): a #GTimeZone, or %NULL for UTC
2177 * Creates a new #GDateTime using the date and times in the Gregorian
2180 * If @time_zone is not %NULL, the #GDateTime will copy the #GTimeZone
2181 * and sink it, if floating.
2183 * Return value: the newly created #GDateTime
2188 g_date_time_new_full (gint year,
2194 const GTimeZone *time_zone)
2198 g_return_val_if_fail (hour >= 0 && hour < 24, NULL);
2199 g_return_val_if_fail (minute >= 0 && minute < 60, NULL);
2200 g_return_val_if_fail (second >= 0.0 && second <= 60.0, NULL);
2202 dt = g_date_time_new ();
2203 dt->days = date_to_proleptic_gregorian (year, month, day);
2204 dt->usec = (hour * USEC_PER_HOUR)
2205 + (minute * USEC_PER_MINUTE)
2206 + (second * USEC_PER_SECOND);
2208 if (time_zone != NULL)
2210 dt->tz = g_time_zone_copy (time_zone);
2211 g_time_zone_sink (dt->tz, dt);
2220 * g_date_time_new_now:
2222 * Creates a new #GDateTime representing the current date and time.
2224 * Return value: the newly created #GDateTime which should be freed with
2225 * g_date_time_unref().
2230 g_date_time_new_now (void)
2234 g_get_current_time (&tv);
2236 return g_date_time_new_from_timeval (&tv);
2240 * g_date_time_printf:
2241 * @datetime: A #GDateTime
2242 * @format: a valid UTF-8 string, containing the format for the #GDateTime
2244 * Creates a newly allocated string representing the requested @format.
2246 * The following format specifiers are supported:
2248 * %%a The abbreviated weekday name according to the current locale.
2249 * %%A The full weekday name according to the current locale.
2250 * %%b The abbreviated month name according to the current locale.
2251 * %%B The full month name according to the current locale.
2252 * %%d The day of the month as a decimal number (range 01 to 31).
2253 * %%e The day of the month as a decimal number (range 1 to 31).
2254 * %%F Equivalent to %Y-%m-%d (the ISO 8601 date format).
2255 * %%h Equivalent to %b.
2256 * %%H The hour as a decimal number using a 24-hour clock (range 00 to 23).
2257 * %%I The hour as a decimal number using a 12-hour clock (range 01 to 12).
2258 * %%j The day of the year as a decimal number (range 001 to 366).
2259 * %%k The hour (24-hour clock) as a decimal number (range 0 to 23);
2260 * single digits are preceded by a blank.
2261 * %%l The hour (12-hour clock) as a decimal number (range 1 to 12);
2262 * single digits are preceded by a blank.
2263 * %%m The month as a decimal number (range 01 to 12).
2264 * %%M The minute as a decimal number (range 00 to 59).
2265 * %%N The micro-seconds as a decimal number.
2266 * %%p Either "AM" or "PM" according to the given time value, or the
2267 * corresponding strings for the current locale. Noon is treated
2268 * as "PM" and midnight as "AM".
2269 * %%P Like %%p but lowercase: "am" or "pm" or a corresponding string for
2270 * the current locale.
2271 * %%r The time in a.m. or p.m. notation.
2272 * %%R The time in 24-hour notation (%H:%M).
2273 * %%s The number of seconds since the Epoch, that is, since 1970-01-01
2275 * %%S The second as a decimal number (range 00 to 60).
2276 * %%t A tab character.
2277 * %%u The day of the week as a decimal, range 1 to 7, Monday being 1.
2278 * %%W The week number of the current year as a decimal number.
2279 * %%x The preferred date representation for the current locale without
2281 * %%X The preferred date representation for the current locale without
2283 * %%y The year as a decimal number without the century.
2284 * %%Y The year as a decimal number including the century.
2285 * %%z The time-zone as hour offset from UTC
2286 * %%Z The timezone or name or abbreviation
2287 * %%% A literal %% character.
2289 * Return value: a newly allocated string formatted to the requested format or
2290 * %NULL in the case that there was an error. The string should be freed
2296 g_date_time_printf (const GDateTime *datetime,
2297 const gchar *format)
2305 g_return_val_if_fail (datetime != NULL, NULL);
2306 g_return_val_if_fail (format != NULL, NULL);
2307 g_return_val_if_fail (g_utf8_validate (format, -1, NULL), NULL);
2309 outstr = g_string_sized_new (strlen (format) * 2);
2310 utf8len = g_utf8_strlen (format, -1);
2313 for (; *format; format = g_utf8_next_char(format))
2315 c = g_utf8_get_char (format);
2332 g_string_append (outstr, WEEKDAY_ABBR (datetime));
2335 g_string_append (outstr, WEEKDAY_FULL (datetime));
2338 g_string_append (outstr, MONTH_ABBR (datetime));
2341 g_string_append (outstr, MONTH_FULL (datetime));
2344 g_string_append_printf (outstr, "%02d", g_date_time_get_day_of_month (datetime));
2347 g_string_append_printf (outstr, "%2d", g_date_time_get_day_of_month (datetime));
2350 g_string_append_printf (outstr, "%d-%02d-%02d",
2351 g_date_time_get_year (datetime),
2352 g_date_time_get_month (datetime),
2353 g_date_time_get_day_of_month (datetime));
2356 g_string_append (outstr, MONTH_ABBR (datetime));
2359 g_string_append_printf (outstr, "%02d", g_date_time_get_hour (datetime));
2362 if (g_date_time_get_hour (datetime) == 0)
2363 g_string_append (outstr, "12");
2365 g_string_append_printf (outstr, "%02d", g_date_time_get_hour (datetime) % 12);
2368 g_string_append_printf (outstr, "%03d", g_date_time_get_day_of_year (datetime));
2371 g_string_append_printf (outstr, "%2d", g_date_time_get_hour (datetime));
2374 if (g_date_time_get_hour (datetime) == 0)
2375 g_string_append (outstr, "12");
2377 g_string_append_printf (outstr, "%2d", g_date_time_get_hour (datetime) % 12);
2380 g_string_append_printf (outstr, "%02d", g_date_time_get_month (datetime));
2383 g_string_append_printf (outstr, "%02d", g_date_time_get_minute (datetime));
2386 g_string_append_printf (outstr, "%"G_GUINT64_FORMAT, datetime->usec % USEC_PER_SECOND);
2389 g_string_append (outstr, GET_AMPM (datetime, FALSE));
2392 g_string_append (outstr, GET_AMPM (datetime, TRUE));
2396 gint hour = g_date_time_get_hour (datetime) % 12;
2399 g_string_append_printf (outstr, "%02d:%02d:%02d %s",
2401 g_date_time_get_minute (datetime),
2402 g_date_time_get_second (datetime),
2403 GET_AMPM (datetime, FALSE));
2407 g_string_append_printf (outstr, "%02d:%02d",
2408 g_date_time_get_hour (datetime),
2409 g_date_time_get_minute (datetime));
2412 g_string_append_printf (outstr, "%" G_GINT64_FORMAT, g_date_time_to_epoch (datetime));
2415 g_string_append_printf (outstr, "%02d", g_date_time_get_second (datetime));
2418 g_string_append_c (outstr, '\t');
2421 g_string_append_printf (outstr, "%d", g_date_time_get_day_of_week (datetime));
2424 g_string_append_printf (outstr, "%d", g_date_time_get_day_of_year (datetime) / 7);
2428 tmp = GET_PREFERRED_DATE (datetime);
2429 g_string_append (outstr, tmp);
2435 tmp = GET_PREFERRED_TIME (datetime);
2436 g_string_append (outstr, tmp);
2441 g_string_append_printf (outstr, "%02d", g_date_time_get_year (datetime) % 100);
2444 g_string_append_printf (outstr, "%d", g_date_time_get_year (datetime));
2447 if (datetime->tz != NULL)
2449 gint64 offset = g_date_time_get_utc_offset (datetime)
2452 g_string_append_printf (outstr, "%c%02d%02d",
2453 offset >= 0 ? '+' : '-',
2454 (int) offset / 3600,
2455 (int) offset / 60 % 60);
2458 g_string_append (outstr, "+0000");
2461 if (datetime->tz != NULL)
2462 g_string_append (outstr, g_date_time_get_timezone_name (datetime));
2464 g_string_append (outstr, "UTC");
2467 g_string_append_c (outstr, '%');
2470 g_string_append_c (outstr, '\n');
2478 g_string_append_unichar (outstr, c);
2482 return g_string_free (outstr, FALSE);
2485 g_string_free (outstr, TRUE);
2490 * g_date_time_to_local:
2491 * @datetime: a #GDateTime
2493 * Creates a new #GDateTime with @datetime converted to local time.
2495 * Return value: the newly created #GDateTime
2500 g_date_time_to_local (const GDateTime *datetime)
2504 g_return_val_if_fail (datetime != NULL, NULL);
2506 dt = g_date_time_copy (datetime);
2509 dt->tz = g_time_zone_new_local ();
2513 g_time_zone_sink (dt->tz, dt);
2514 g_date_time_add_usec (dt, dt->tz->offset * USEC_PER_SECOND);
2521 * g_date_time_to_epoch:
2522 * @datetime: a #GDateTime
2524 * Converts @datetime into an integer representing seconds since the
2527 * Return value: @datetime as seconds since the Unix epoch
2532 g_date_time_to_epoch (const GDateTime *datetime)
2536 g_return_val_if_fail (datetime != NULL, 0);
2538 if (datetime->days <= 0)
2541 result = (datetime->days - UNIX_EPOCH_START) * SEC_PER_DAY
2542 + datetime->usec / USEC_PER_SECOND
2543 - g_date_time_get_utc_offset (datetime) / USEC_PER_SECOND;
2549 * g_date_time_to_timeval:
2550 * @datetime: a #GDateTime
2553 * Converts @datetime into a #GTimeVal and stores the result into @timeval.
2558 g_date_time_to_timeval (const GDateTime *datetime,
2561 g_return_if_fail (datetime != NULL);
2562 g_return_if_fail (tv != NULL);
2564 tv->tv_sec = g_date_time_to_epoch (datetime);
2565 tv->tv_usec = datetime->usec % USEC_PER_SECOND;
2569 * g_date_time_to_utc:
2570 * @datetime: a #GDateTime
2572 * Creates a new #GDateTime that reprents @datetime in Universal coordinated
2575 * Return value: the newly created #GDateTime which should be freed with
2576 * g_date_time_unref().
2581 g_date_time_to_utc (const GDateTime *datetime)
2586 g_return_val_if_fail (datetime != NULL, NULL);
2588 ts = g_date_time_get_utc_offset (datetime) * -1;
2589 dt = g_date_time_add (datetime, ts);
2592 g_time_zone_free (dt->tz);
2600 * g_date_time_new_today:
2602 * Createsa new #GDateTime that represents Midnight on the current day.
2604 * Return value: the newly created #GDateTime which should be freed with
2605 * g_date_time_unref().
2610 g_date_time_new_today (void)
2614 dt = g_date_time_new_now ();
2621 * g_date_time_new_utc_now:
2623 * Creates a new #GDateTime that represents the current instant in Universal
2624 * Coordinated Time (UTC).
2626 * Return value: the newly created #GDateTime which should be freed with
2627 * g_date_time_unref().
2632 g_date_time_new_utc_now (void)
2634 GDateTime *utc, *now;
2636 now = g_date_time_new_now ();
2637 utc = g_date_time_to_utc (now);
2638 g_date_time_unref (now);
2644 * g_date_time_get_week_of_year:
2646 * Returns the numeric week of the respective year.
2648 * Return value: the week of the year
2653 g_date_time_get_week_of_year (const GDateTime *datetime)
2657 g_return_val_if_fail (datetime != NULL, 0);
2659 g_date_time_get_week_number (datetime, &weeknum, NULL, NULL);