[glib] Clean-up/tweaking of GDateTime and GTimeZone
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] Clean-up/tweaking of GDateTime and GTimeZone
- Date: Fri, 17 Sep 2010 15:40:52 +0000 (UTC)
commit 6b0e31ce4891883b3923c40c68347dcf5fe54165
Author: Ryan Lortie <desrt desrt ca>
Date: Thu Sep 16 04:44:59 2010 -0400
Clean-up/tweaking of GDateTime and GTimeZone
docs/reference/glib/glib-docs.sgml | 1 +
docs/reference/glib/glib-sections.txt | 99 +-
glib/Makefile.am | 2 +
glib/gdatetime.c | 2681 +++++++++++++++------------------
glib/gdatetime.h | 247 ++--
glib/glib.h | 1 +
glib/glib.symbols | 49 +-
glib/gtimezone.c | 790 ++++++++++
glib/gtimezone.h | 81 +
glib/tests/gdatetime.c | 314 ++---
10 files changed, 2373 insertions(+), 1892 deletions(-)
---
diff --git a/docs/reference/glib/glib-docs.sgml b/docs/reference/glib/glib-docs.sgml
index 6e9f50f..74cc783 100644
--- a/docs/reference/glib/glib-docs.sgml
+++ b/docs/reference/glib/glib-docs.sgml
@@ -76,6 +76,7 @@ synchronize their operation.
<xi:include href="xml/checksum.xml" />
<xi:include href="xml/i18n.xml" />
<xi:include href="xml/date.xml" />
+ <xi:include href="xml/timezone.xml" />
<xi:include href="xml/date-time.xml" />
<xi:include href="xml/random_numbers.xml" />
<xi:include href="xml/hooks.xml" />
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 1568c48..344e2d4 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -1408,65 +1408,118 @@ g_date_sunday_weeks_in_year
</SECTION>
<SECTION>
+<FILE>timezone</FILE>
+<SUBSECTION>
+GTimeZone
+g_time_zone_unref
+g_time_zone_ref
+<SUBSECTION>
+g_time_zone_new
+g_time_zone_new_local
+g_time_zone_new_utc
+<SUBSECTION>
+GTimeType
+g_time_zone_find_interval
+g_time_zone_adjust_time
+<SUBSECTION>
+g_time_zone_get_abbreviation
+g_time_zone_get_offset
+g_time_zone_is_dst
+</SECTION>
+
+<SECTION>
<FILE>date-time</FILE>
+GTimeSpan
G_TIME_SPAN_DAY
G_TIME_SPAN_HOUR
G_TIME_SPAN_MINUTE
G_TIME_SPAN_SECOND
-G_TIME_SPAN_MILLISECONT
-GTimeSpan
+G_TIME_SPAN_MILLISECOND
+
<SUBSECTION>
GDateTime
-g_date_time_new_full
-g_date_time_new_from_date
-g_date_time_new_from_epoch
-g_date_time_new_from_timeval
-g_date_time_new_now
-g_date_time_new_utc_now
-g_date_time_new_today
-g_date_time_ref
g_date_time_unref
+g_date_time_ref
+
+<SUBSECTION>
+g_date_time_new_now
+g_date_time_new_now_local
+g_date_time_new_now_utc
+
+<SUBSECTION>
+g_date_time_new_from_unix_local
+g_date_time_new_from_unix_utc
+
+<SUBSECTION>
+g_date_time_new_from_timeval_local
+g_date_time_new_from_timeval_utc
+
+<SUBSECTION>
+g_date_time_new
+g_date_time_new_local
+g_date_time_new_utc
+
<SUBSECTION>
g_date_time_add
+
+<SUBSECTION>
g_date_time_add_years
g_date_time_add_months
g_date_time_add_weeks
g_date_time_add_days
+
+<SUBSECTION>
g_date_time_add_hours
g_date_time_add_minutes
g_date_time_add_seconds
-g_date_time_add_milliseconds
+
+<SUBSECTION>
g_date_time_add_full
+
<SUBSECTION>
-g_date_time_difference
g_date_time_compare
-g_date_time_equal
+g_date_time_difference
g_date_time_hash
+g_date_time_equal
+
+<SUBSECTION>
+g_date_time_get_ymd
+
<SUBSECTION>
-g_date_time_get_dmy
g_date_time_get_year
g_date_time_get_month
-g_date_time_get_week_of_year
g_date_time_get_day_of_month
+
+<SUBSECTION>
+g_date_time_get_week_of_year
g_date_time_get_day_of_week
+
+<SUBSECTION>
g_date_time_get_day_of_year
+
+<SUBSECTION>
g_date_time_get_hour
g_date_time_get_minute
g_date_time_get_second
-g_date_time_get_millisecond
g_date_time_get_microsecond
-g_date_time_get_julian
+g_date_time_get_seconds
+
+<SUBSECTION>
+g_date_time_to_unix
+g_date_time_to_timeval
+
+<SUBSECTION>
g_date_time_get_utc_offset
-g_date_time_get_timezone_name
+g_date_time_get_timezone_abbreviation
g_date_time_is_daylight_savings
-g_date_time_is_leap_year
+
<SUBSECTION>
-g_date_time_day
-g_date_time_to_epoch
+g_date_time_to_timezone
g_date_time_to_local
-g_date_time_to_timeval
g_date_time_to_utc
-g_date_time_printf
+
+<SUBSECTION>
+g_date_time_format
</SECTION>
<SECTION>
diff --git a/glib/Makefile.am b/glib/Makefile.am
index b8ce522..6f3d526 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -177,6 +177,7 @@ libglib_2_0_la_SOURCES = \
gthreadprivate.h \
gthreadpool.c \
gtimer.c \
+ gtimezone.c \
gtree.c \
guniprop.c \
gutf8.c \
@@ -276,6 +277,7 @@ glibsubinclude_HEADERS = \
gthread.h \
gthreadpool.h \
gtimer.h \
+ gtimezone.h \
gtree.h \
gtypes.h \
gunicode.h \
diff --git a/glib/gdatetime.c b/glib/gdatetime.c
index b014f11..c2e3407 100644
--- a/glib/gdatetime.c
+++ b/glib/gdatetime.c
@@ -3,20 +3,27 @@
* Copyright (C) 2009-2010 Christian Hergert <chris dronelabs com>
* Copyright (C) 2010 Thiago Santos <thiago sousa santos collabora co uk>
* Copyright (C) 2010 Emmanuele Bassi <ebassi linux intel com>
+ * Copyright © 2010 Codethink Limited
*
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * licence, or (at your option) any later version.
*
- * This is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
+ * This is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ *
+ * Authors: Christian Hergert <chris dronelabs com>
+ * Thiago Santos <thiago sousa santos collabora co uk>
+ * Emmanuele Bassi <ebassi linux intel com>
+ * Ryan Lortie <desrt desrt ca>
*/
/* Algorithms within this file are based on the Calendar FAQ by
@@ -36,6 +43,8 @@
* to its correctness.
*/
+/* Prologue {{{1 */
+
#include "config.h"
#include <stdlib.h>
@@ -60,6 +69,7 @@
#include "gstrfuncs.h"
#include "gtestutils.h"
#include "gthread.h"
+#include "gtimezone.h"
#include "glibintl.h"
@@ -67,27 +77,57 @@
* SECTION:date-time
* @title: GDateTime
* @short_description: A structure representing Date and Time
+ * @see_also: #GTimeZone
*
- * #GDateTime is a structure that combines a date and time into a single
- * structure. It provides many conversion and methods to manipulate dates
- * and times. Time precision is provided down to microseconds.
+ * #GDateTime is a structure that combines a Gregorian date and time
+ * into a single structure. It provides many conversion and methods to
+ * manipulate dates and times. Time precision is provided down to
+ * microseconds and the time can range (proleptically) from 0001-01-01
+ * 00:00:00 to 9999-12-31 23:59:59.999999. #GDateTime follows POSIX
+ * time in the sense that it is oblivious to leap seconds.
*
- * #GDateTime is an immutable object: once it has been created it cannot be
- * modified further. All modifiers will create a new #GDateTime.
+ * #GDateTime is an immutable object; once it has been created it cannot
+ * be modified further. All modifiers will create a new #GDateTime.
+ * Nearly all such functions can fail due to the date or time going out
+ * of range, in which case %NULL will be returned.
*
* #GDateTime is reference counted: the reference count is increased by calling
* g_date_time_ref() and decreased by calling g_date_time_unref(). When the
* reference count drops to 0, the resources allocated by the #GDateTime
* structure are released.
*
- * Internally, #GDateTime uses the Proleptic Gregorian Calendar, the first
- * representable date is 0001-01-01. However, the public API uses the
- * internationally accepted Gregorian Calendar.
+ * Many parts of the API may produce non-obvious results. As an
+ * example, adding two months to January 31st will yield March 31st
+ * whereas adding one month and then one month again will yield either
+ * March 28th or March 29th. Also note that adding 24 hours is not
+ * always the same as adding one day (since days containing daylight
+ * savings time transitions are either 23 or 25 hours in length).
*
* #GDateTime is available since GLib 2.26.
*/
+struct _GDateTime
+{
+ /* 1 is 0001-01-01 in Proleptic Gregorian */
+ gint32 days;
+
+ /* Microsecond timekeeping within Day */
+ guint64 usec;
+
+ /* TimeZone information */
+ GTimeZone *tz;
+ gint interval;
+
+ volatile gint ref_count;
+};
+
+/* Time conversion {{{1 */
+
#define UNIX_EPOCH_START 719163
+#define INSTANT_TO_UNIX(instant) \
+ ((instant)/USEC_PER_SECOND - UNIX_EPOCH_START * SEC_PER_DAY)
+#define UNIX_TO_INSTANT(unix) \
+ (((unix) + UNIX_EPOCH_START * SEC_PER_DAY) * USEC_PER_SECOND)
#define DAYS_IN_4YEARS 1461 /* days in 4 years */
#define DAYS_IN_100YEARS 36524 /* days in 100 years */
@@ -132,47 +172,6 @@
#define SECS_PER_YEAR (365 * SECS_PER_DAY)
#define SECS_PER_JULIAN (DAYS_PER_PERIOD * SECS_PER_DAY)
-typedef struct _GTimeZoneFile GTimeZoneFile;
-
-struct _GDateTime
-{
- /* 1 is 0001-01-01 in Proleptic Gregorian */
- guint32 days;
-
- /* Microsecond timekeeping within Day */
- guint64 usec;
-
- /* TimeZone information, NULL is UTC */
- GTimeZone *tz;
-
- volatile gint ref_count;
-};
-
-struct _GTimeZone
-{
- GTimeZoneFile *tz_file;
-
- gchar *name;
-
- gint64 offset;
-
- guint is_dst : 1;
- guint is_utc : 1;
- guint is_floating : 1;
-};
-
-struct _GTimeZoneFile
-{
- GMappedFile *file;
-
- gchar *filename;
-
- volatile gint ref_count;
-};
-
-G_LOCK_DEFINE_STATIC (time_zone_files);
-static GHashTable *time_zone_files = NULL;
-
static const guint16 days_in_months[2][13] =
{
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
@@ -313,844 +312,701 @@ get_weekday_name_abbr (gint day)
return NULL;
}
-#define ZONEINFO_DIR "zoneinfo"
-#define TZ_MAGIC "TZif"
-#define TZ_MAGIC_LEN (strlen (TZ_MAGIC))
-#define TZ_HEADER_SIZE 44
-#define TZ_TIMECNT_OFFSET 32
-#define TZ_TYPECNT_OFFSET 36
-#define TZ_TRANSITIONS_OFFSET 44
-#define TZ_TTINFO_SIZE 6
-#define TZ_TTINFO_GMTOFF_OFFSET 0
-#define TZ_TTINFO_ISDST_OFFSET 4
-#define TZ_TTINFO_NAME_OFFSET 5
-
-static gchar *
-get_tzdata_path (const gchar *tz_name)
+static inline gint
+ymd_to_days (gint year,
+ gint month,
+ gint day)
{
- gchar *retval = NULL;
- const gchar *tz_dir = g_getenv ("TZDIR");
+ gint64 days;
- if (tz_dir != NULL)
- retval = g_build_filename (tz_dir, tz_name, NULL);
- else
- {
- if (strcmp (tz_name, "localtime") == 0)
- retval = g_build_filename ("/", "etc", "localtime", NULL);
- else
- retval = g_build_filename ("/", "usr", "share", ZONEINFO_DIR, tz_name, NULL);
- }
+ days = (year - 1) * 365 + ((year - 1) / 4) - ((year - 1) / 100)
+ + ((year - 1) / 400);
+
+ days += days_in_year[0][month - 1];
+ if (GREGORIAN_LEAP (year) && month > 2)
+ day++;
+
+ days += day;
- return retval;
+ return days;
}
-static gboolean
-parse_tzdata (GTimeZoneFile *tz_file,
- gint64 start,
- gboolean is_utc,
- gint64 *_offset,
- gboolean *_is_dst,
- gchar **_name)
+static void
+g_date_time_get_week_number (GDateTime *datetime,
+ gint *week_number,
+ gint *day_of_week,
+ gint *day_of_year)
{
- gchar *contents;
- gsize length;
- guint32 timecnt, typecnt;
- gint transitions_size, ttinfo_map_size;
- guint8 *ttinfo_map, *ttinfos;
- gint start_transition = -1;
- guint32 *transitions;
- gint32 offset;
- guint8 isdst;
- guint8 name_offset;
- gint i;
-
- contents = g_mapped_file_get_contents (tz_file->file);
- length = g_mapped_file_get_length (tz_file->file);
-
- if (length < TZ_HEADER_SIZE ||
- (strncmp (contents, TZ_MAGIC, TZ_MAGIC_LEN) != 0))
- {
- return FALSE;
- }
-
- timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
- typecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TYPECNT_OFFSET));
+ gint a, b, c, d, e, f, g, n, s, month, day, year;
- transitions = (guint32 *)(contents + TZ_TRANSITIONS_OFFSET);
- transitions_size = timecnt * sizeof (*transitions);
- ttinfo_map = (void *)(contents + TZ_TRANSITIONS_OFFSET + transitions_size);
- ttinfo_map_size = timecnt;
- ttinfos = (void *)(ttinfo_map + ttinfo_map_size);
+ g_date_time_get_ymd (datetime, &year, &month, &day);
- /*
- * Find the first transition that contains the 'start' time
- */
- for (i = 1; i < timecnt && start_transition == -1; i++)
+ if (month <= 2)
{
- gint32 transition_time = GINT32_FROM_BE (transitions[i]);
-
- /* if is_utc is not set, we need to add this time offset to compare with
- * start, because it is already on the timezone time */
- if (!is_utc)
- {
- gint32 off;
-
- off = *(gint32 *)(ttinfos + ttinfo_map[i] * TZ_TTINFO_SIZE +
- TZ_TTINFO_GMTOFF_OFFSET);
- off = GINT32_FROM_BE (off);
-
- transition_time += off;
- }
-
- if (transition_time > start)
- {
- start_transition = ttinfo_map[i - 1];
- break;
- }
+ a = g_date_time_get_year (datetime) - 1;
+ b = (a / 4) - (a / 100) + (a / 400);
+ c = ((a - 1) / 4) - ((a - 1) / 100) + ((a - 1) / 400);
+ s = b - c;
+ e = 0;
+ f = day - 1 + (31 * (month - 1));
}
-
- if (start_transition == -1)
+ else
{
- if (timecnt)
- start_transition = ttinfo_map[timecnt - 1];
- else
- start_transition = 0;
+ a = year;
+ b = (a / 4) - (a / 100) + (a / 400);
+ c = ((a - 1) / 4) - ((a - 1) / 100) + ((a - 1) / 400);
+ s = b - c;
+ e = s + 1;
+ f = day + (((153 * (month - 3)) + 2) / 5) + 58 + s;
}
- /* Copy the data out of the corresponding ttinfo structs */
- offset = *(gint32 *)(ttinfos + start_transition * TZ_TTINFO_SIZE +
- TZ_TTINFO_GMTOFF_OFFSET);
- offset = GINT32_FROM_BE (offset);
- isdst = *(ttinfos + start_transition * TZ_TTINFO_SIZE +
- TZ_TTINFO_ISDST_OFFSET);
- name_offset = *(ttinfos + start_transition * TZ_TTINFO_SIZE +
- TZ_TTINFO_NAME_OFFSET);
-
- if (_name != NULL)
- *_name = g_strdup ((gchar*) (ttinfos + TZ_TTINFO_SIZE * typecnt + name_offset));
+ g = (a + b) % 7;
+ d = (f + g - e) % 7;
+ n = f + 3 - d;
- if (_offset)
- *_offset = offset;
+ if (week_number)
+ {
+ if (n < 0)
+ *week_number = 53 - ((g - s) / 5);
+ else if (n > 364 + s)
+ *week_number = 1;
+ else
+ *week_number = (n / 7) + 1;
+ }
- if (_is_dst)
- *_is_dst = isdst;
+ if (day_of_week)
+ *day_of_week = d + 1;
- return TRUE;
+ if (day_of_year)
+ *day_of_year = f + 1;
}
-static GTimeZoneFile *
-g_time_zone_file_new (const gchar *filename)
-{
- GMappedFile *tz_file;
- GTimeZoneFile *retval;
+/* Lifecycle {{{1 */
- tz_file = g_mapped_file_new (filename, FALSE, NULL);
- if (tz_file == NULL)
- return NULL;
+static GDateTime *
+g_date_time_alloc (GTimeZone *tz)
+{
+ GDateTime *datetime;
- retval = g_slice_new (GTimeZoneFile);
- retval->filename = g_strdup (filename);
- retval->file = tz_file;
- retval->ref_count = 1;
+ datetime = g_slice_new0 (GDateTime);
+ datetime->tz = g_time_zone_ref (tz);
+ datetime->ref_count = 1;
- return retval;
+ return datetime;
}
-static GTimeZoneFile *
-g_time_zone_file_ref (GTimeZoneFile *tz_file)
+/**
+ * g_date_time_ref:
+ * @datetime: a #GDateTime
+ *
+ * Atomically increments the reference count of @datetime by one.
+ *
+ * Return value: the #GDateTime with the reference count increased
+ *
+ * Since: 2.26
+ */
+GDateTime *
+g_date_time_ref (GDateTime *datetime)
{
- if (tz_file == NULL)
- return NULL;
+ g_return_val_if_fail (datetime != NULL, NULL);
+ g_return_val_if_fail (datetime->ref_count > 0, NULL);
- g_atomic_int_inc (&tz_file->ref_count);
+ g_atomic_int_inc (&datetime->ref_count);
- return tz_file;
+ return datetime;
}
-static void
-g_time_zone_file_unref (GTimeZoneFile *tz_file)
+/**
+ * g_date_time_unref:
+ * @datetime: a #GDateTime
+ *
+ * Atomically decrements the reference count of @datetime by one.
+ *
+ * When the reference count reaches zero, the resources allocated by
+ * @datetime are freed
+ *
+ * Since: 2.26
+ */
+void
+g_date_time_unref (GDateTime *datetime)
{
- if (tz_file == NULL)
- return;
+ g_return_if_fail (datetime != NULL);
+ g_return_if_fail (datetime->ref_count > 0);
- if (g_atomic_int_dec_and_test (&tz_file->ref_count))
+ if (g_atomic_int_dec_and_test (&datetime->ref_count))
{
- /* remove the TimeZoneFile from the hash table of known files */
- G_LOCK (time_zone_files);
- g_hash_table_remove (time_zone_files, tz_file->filename);
- G_UNLOCK (time_zone_files);
-
- g_mapped_file_unref (tz_file->file);
- g_free (tz_file->filename);
- g_slice_free (GTimeZoneFile, tz_file);
+ g_time_zone_unref (datetime->tz);
+ g_slice_free (GDateTime, datetime);
}
}
+/* Internal state transformers {{{1 */
/*< internal >
- * g_time_zone_file_get_for_path:
- * @path: the full path for a time zone file
+ * g_date_time_to_instant:
+ * @datetime: a #GDateTime
*
- * Retrieves a #GTimeZoneFile for the given path.
+ * Convert a @datetime into an instant.
*
- * If a time zone file for the same path has been already requested,
- * this function will return the same #GTimeZoneFile with its reference
- * count increased by one; otherwise, a new #GTimeZoneFile will be created
- * and added to the known time zone files.
+ * An instant is a number that uniquely describes a particular
+ * microsecond in time, taking time zone considerations into account.
+ * (ie: "03:00 -0400" is the same instant as "02:00 -0500").
*
- * The time zone files are removed from the list of known files when their
- * reference count reaches 0.
+ * An instant is always positive but we use a signed return value to
+ * avoid troubles with C.
+ */
+static gint64
+g_date_time_to_instant (GDateTime *datetime)
+{
+ gint64 offset;
+
+ offset = g_time_zone_get_offset (datetime->tz, datetime->interval);
+ offset *= USEC_PER_SECOND;
+
+ return datetime->days * USEC_PER_DAY + datetime->usec - offset;
+}
+
+/*< internal >
+ * g_date_time_from_instant:
+ * @tz: a #GTimeZone
+ * @instant: a instant in time
*
- * This function holds the lock on the time_zone_files hash table.
+ * Creates a #GDateTime from a time zone and an instant.
*
- * Return value: a #GTimeZoneFile or %NULL
+ * This might fail if the time ends up being out of range.
*/
-static GTimeZoneFile *
-g_time_zone_file_get_for_path (const gchar *path)
+static GDateTime *
+g_date_time_from_instant (GTimeZone *tz,
+ gint64 instant)
{
- GTimeZoneFile *retval;
+ GDateTime *datetime;
+ gint64 offset;
- G_LOCK (time_zone_files);
+ if (instant < 0 || instant > 1000000000000000000)
+ return NULL;
- if (G_LIKELY (time_zone_files != NULL))
- {
- retval = g_hash_table_lookup (time_zone_files, path);
- if (retval != NULL)
- {
- retval = g_time_zone_file_ref (retval);
- goto out;
- }
- }
+ datetime = g_date_time_alloc (tz);
+ datetime->interval = g_time_zone_find_interval (tz,
+ G_TIME_TYPE_UNIVERSAL,
+ INSTANT_TO_UNIX (instant));
+ offset = g_time_zone_get_offset (datetime->tz, datetime->interval);
+ offset *= USEC_PER_SECOND;
- retval = g_time_zone_file_new (path);
- if (retval != NULL)
- {
- if (G_UNLIKELY (time_zone_files == NULL))
- time_zone_files = g_hash_table_new (g_str_hash, g_str_equal);
+ instant += offset;
- g_hash_table_insert (time_zone_files, retval->filename, retval);
- }
+ datetime->days = instant / USEC_PER_DAY;
+ datetime->usec = instant % USEC_PER_DAY;
-out:
- G_UNLOCK (time_zone_files);
+ if (datetime->days < 1 || 3652059 < datetime->days)
+ {
+ g_date_time_unref (datetime);
+ datetime = NULL;
+ }
- return retval;
+ return datetime;
}
-/**
- * g_time_zone_new:
- * @offset: the timezone offset from UTC, in seconds
- * @is_dst: whether the timezone is in Daylight Saving Time or not
+
+/*< internal >
+ * g_date_time_deal_with_date_change:
+ * @datetime: a #GDateTime
*
- * Creates a new #GTimeZone for the given @offset, to be used when
- * creating a #GDateTime.
+ * This function should be called whenever the date changes by adding
+ * days, months or years. It does three things.
*
- * The #GTimeZone created will not be floating.
+ * First, we ensure that the date falls between 0001-01-01 and
+ * 9999-12-31 and return %FALSE if it does not.
*
- * Return value: (transfer full): the newly allocated #GTimeZone
+ * Next we update the ->interval field.
*
- * Since: 2.26
+ * Finally, we ensure that the resulting date and time pair exists (by
+ * ensuring that our time zone has an interval containing it) and
+ * adjusting as required. For example, if we have the time 02:30:00 on
+ * March 13 2010 in Toronto and we add 1 day to it, we would end up with
+ * 2:30am on March 14th, which doesn't exist. In that case, we bump the
+ * time up to 3:00am.
*/
-GTimeZone *
-g_time_zone_new (gint offset,
- gboolean is_dst)
+static gboolean
+g_date_time_deal_with_date_change (GDateTime *datetime)
{
- GTimeZone *tz;
+ GTimeType was_dst;
+ gint64 full_time;
+ gint64 usec;
- g_return_val_if_fail (offset >= -12 * SECS_PER_HOUR && offset <= 12 * SECS_PER_HOUR, NULL);
+ if (datetime->days < 1 || datetime->days > 3652059)
+ return FALSE;
- tz = g_slice_new (GTimeZone);
- tz->offset = offset;
- tz->is_dst = is_dst;
- tz->tz_file = NULL;
- tz->is_floating = FALSE;
+ was_dst = g_time_zone_is_dst (datetime->tz, datetime->interval);
- if (tz->offset == 0)
- tz->name = g_strdup_printf ("UTC");
- else
- tz->name = g_strdup_printf ("UTC%c%02d:%02d",
- tz->offset > 0 ? '+' : '-',
- (int) tz->offset / 3600,
- (int) tz->offset / 60 % 60);
+ full_time = datetime->days * USEC_PER_DAY + datetime->usec;
- return tz;
-}
-/**
- * g_time_zone_new_for_name:
- * @name: an ASCII string containing the Olson's database name of the
- * timezone, e.g. "America/New_York" or "Europe/London"
- *
- * Creates a new #GTimeZone for the given @name.
- *
- * The returned timezone is "floating": if queried, it will return invalid
- * values. A floating #GTimeZone is "sunk" when it is bound to a #GDateTime
- * object.
- *
- * For instance:
- *
- * |[
- * /* the time zone is "floating" */
- * GTimeZone *tz = g_time_zone_new_for_name ("Europe/London");
- *
- * /* this will print: "UTC offset: 0 seconds" */
- * g_print ("UTC offset: %d seconds\n", g_time_zone_get_offset (tz));
- *
- * /* the GDateTime object copies the time zone */
- * GDateTime *dt = g_date_time_new_full (2010, 9, 15, 12, 0, 0, tz);
- *
- * /* this will print: "UTC offset: 3600 seconds", because Europe/London
- * * on that date is in daylight saving time
- * */
- * g_print ("UTC offset: %d seconds\n",
- * g_date_time_get_utc_offset (dt) / G_USEC_PER_SEC);
- * ]|
- *
- * Return value: (transfer full): the newly created, floating #GTimeZone
- * object for the given name, or %NULL if none was found
- *
- * Since: 2.26
- */
-GTimeZone *
-g_time_zone_new_for_name (const gchar *name)
-{
- GTimeZone *tz;
- gchar *filename;
- GTimeZoneFile *tz_file;
+ usec = full_time % USEC_PER_SECOND;
+ full_time /= USEC_PER_SECOND;
+ full_time -= UNIX_EPOCH_START * SEC_PER_DAY;
- g_return_val_if_fail (name != NULL, NULL);
+ datetime->interval = g_time_zone_adjust_time (datetime->tz,
+ was_dst,
+ &full_time);
+ full_time += UNIX_EPOCH_START * SEC_PER_DAY;
+ full_time *= USEC_PER_SECOND;
+ full_time += usec;
- filename = get_tzdata_path (name);
- if (filename == NULL)
- return NULL;
+ datetime->days = full_time / USEC_PER_DAY;
+ datetime->usec = full_time % USEC_PER_DAY;
- tz_file = g_time_zone_file_get_for_path (filename);
- g_free (filename);
+ /* maybe daylight time caused us to shift to a different day,
+ * but it definitely didn't push us into a different year */
+ return TRUE;
+}
- if (tz_file == NULL)
- return NULL;
+static GDateTime *
+g_date_time_replace_days (GDateTime *datetime,
+ gint days)
+{
+ GDateTime *new;
+
+ new = g_date_time_alloc (datetime->tz);
+ new->interval = datetime->interval;
+ new->usec = datetime->usec;
+ new->days = days;
- tz = g_slice_new (GTimeZone);
- tz->tz_file = tz_file;
- tz->name = NULL;
- tz->offset = 0;
- tz->is_dst = FALSE;
- tz->is_utc = (strcmp (name, "UTC") == 0);
- tz->is_floating = TRUE;
+ if (!g_date_time_deal_with_date_change (new))
+ {
+ g_date_time_unref (new);
+ new = NULL;
+ }
- return tz;
+ return new;
}
-/**
- * g_time_zone_new_utc:
+/* now/unix/timeval Constructors {{{1 */
+
+/*< internal >
+ * g_date_time_new_from_timeval:
+ * @tz: a #GTimeZone
+ * @tv: a #GTimeVal
*
- * Creates a new #GTimeZone for UTC.
+ * Creates a #GDateTime corresponding to the given #GTimeVal @tv in the
+ * given time zone @tz.
*
- * Return value: (transfer full): a newly created #GTimeZone for UTC.
- * Use g_time_zone_free() when done.
+ * The time contained in a #GTimeVal is always stored in the form of
+ * seconds elapsed since 1970-01-01 00:00:00 UTC, regardless of the
+ * given time zone.
+ *
+ * This call can fail (returning %NULL) if @tv represents a time outside
+ * of the supported range of #GDateTime.
+ *
+ * You should release the return value by calling g_date_time_unref()
+ * when you are done with it.
+ *
+ * Returns: a new #GDateTime, or %NULL
*
* Since: 2.26
- */
-GTimeZone *
-g_time_zone_new_utc (void)
+ **/
+static GDateTime *
+g_date_time_new_from_timeval (GTimeZone *tz,
+ const GTimeVal *tv)
{
- return g_time_zone_new (0, FALSE);
+ return g_date_time_from_instant (tz, tv->tv_usec +
+ UNIX_TO_INSTANT (tv->tv_sec));
}
-/**
- * g_time_zone_new_local:
+/*< internal >
+ * g_date_time_new_from_unix:
+ * @tz: a #GTimeZone
+ * @t: the Unix time
+ *
+ * Creates a #GDateTime corresponding to the given Unix time @t in the
+ * given time zone @tz.
*
- * Creates a new #GTimeZone for the local timezone.
+ * Unix time is the number of seconds that have elapsed since 1970-01-01
+ * 00:00:00 UTC, regardless of the time zone given.
*
- * The returned #GTimeZone is floating.
+ * This call can fail (returning %NULL) if @t represents a time outside
+ * of the supported range of #GDateTime.
*
- * Return value: (transfer full): a newly created, floating #GTimeZone.
- * Use g_time_zone_free() when done.
+ * You should release the return value by calling g_date_time_unref()
+ * when you are done with it.
+ *
+ * Returns: a new #GDateTime, or %NULL
*
* Since: 2.26
- */
-GTimeZone *
-g_time_zone_new_local (void)
+ **/
+static GDateTime *
+g_date_time_new_from_unix (GTimeZone *tz,
+ gint64 secs)
{
- return g_time_zone_new_for_name ("localtime");
+ return g_date_time_from_instant (tz, UNIX_TO_INSTANT (secs));
}
/**
- * g_time_zone_copy:
- * @time_zone: a #GTimeZone
+ * g_date_time_new_now:
+ * @tz: a #GTimeZone
+ *
+ * Creates a #GDateTime corresponding to this exact instant in the given
+ * time zone @tz. The time is as accurate as the system allows, to a
+ * maximum accuracy of 1 microsecond.
*
- * Copies a #GTimeZone. If @time_zone is floating, the returned copy
- * will be floating as well.
+ * This function will always succeed unless the system clock is set to
+ * truly insane values (or unless GLib is still being used after the
+ * year 9999).
*
- * Return value: (transfer full): the newly created #GTimeZone
+ * You should release the return value by calling g_date_time_unref()
+ * when you are done with it.
+ *
+ * Returns: a new #GDateTime, or %NULL
*
* Since: 2.26
- */
-GTimeZone *
-g_time_zone_copy (const GTimeZone *time_zone)
+ **/
+GDateTime *
+g_date_time_new_now (GTimeZone *tz)
{
- GTimeZone *retval;
-
- g_return_val_if_fail (time_zone != NULL, NULL);
-
- retval = g_slice_dup (GTimeZone, time_zone);
-
- if (time_zone->tz_file != NULL)
- retval->tz_file = g_time_zone_file_ref (time_zone->tz_file);
+ GTimeVal tv;
- if (time_zone->name != NULL)
- retval->name = g_strdup (time_zone->name);
+ g_get_current_time (&tv);
- return retval;
+ return g_date_time_new_from_timeval (tz, &tv);
}
/**
- * g_time_zone_free:
- * @time_zone: a #GTimeZone
+ * g_date_time_new_now_local:
+ *
+ * Creates a #GDateTime corresponding to this exact instant in the local
+ * time zone.
+ *
+ * This is equivalent to calling g_date_time_new_now() with the time
+ * zone returned by g_time_zone_new_local().
*
- * Frees the resources associated with a #GTimeZone
+ * Returns: a new #GDateTime, or %NULL
*
* Since: 2.26
- */
-void
-g_time_zone_free (GTimeZone *time_zone)
+ **/
+GDateTime *
+g_date_time_new_now_local (void)
{
- g_return_if_fail (time_zone != NULL);
+ GDateTime *datetime;
+ GTimeZone *local;
- if (time_zone->tz_file != NULL)
- g_time_zone_file_unref (time_zone->tz_file);
+ local = g_time_zone_new_local ();
+ datetime = g_date_time_new_now (local);
+ g_time_zone_unref (local);
- g_free (time_zone->name);
- g_slice_free (GTimeZone, time_zone);
+ return datetime;
}
/**
- * g_time_zone_get_name:
- * @time_zone: a #GTimeZone
+ * g_date_time_new_now_utc:
+ *
+ * Creates a #GDateTime corresponding to this exact instant in UTC.
*
- * Retrieves the name of the @time_zone, or %NULL if the #GTimeZone is
- * floating.
+ * This is equivalent to calling g_date_time_new_now() with the time
+ * zone returned by g_time_zone_new_utc().
*
- * Return value: (transfer none): the name of the #GTimeZone. The returned
- * string is owned by the #GTimeZone and it should never be modified or
- * freed
+ * Returns: a new #GDateTime, or %NULL
*
* Since: 2.26
- */
-G_CONST_RETURN gchar *
-g_time_zone_get_name (const GTimeZone *time_zone)
+ **/
+GDateTime *
+g_date_time_new_now_utc (void)
{
- g_return_val_if_fail (time_zone != NULL, NULL);
+ GDateTime *datetime;
+ GTimeZone *utc;
- if (!time_zone->is_floating)
- return time_zone->name;
+ utc = g_time_zone_new_utc ();
+ datetime = g_date_time_new_now (utc);
+ g_time_zone_unref (utc);
- return NULL;
+ return datetime;
}
/**
- * g_time_zone_get_offset:
- * @time_zone: a #GTimeZone
+ * g_date_time_new_from_unix_local:
+ * @t: the Unix time
+ *
+ * Creates a #GDateTime corresponding to the given Unix time @t in the
+ * local time zone.
*
- * Retrieves the offset of the @time_zone, in seconds from UTC, or 0
- * if the #GTimeZone is floating.
+ * Unix time is the number of seconds that have elapsed since 1970-01-01
+ * 00:00:00 UTC, regardless of the local time offset.
*
- * Return value: the offset from UTC, in seconds
+ * This call can fail (returning %NULL) if @t represents a time outside
+ * of the supported range of #GDateTime.
+ *
+ * You should release the return value by calling g_date_time_unref()
+ * when you are done with it.
+ *
+ * Returns: a new #GDateTime, or %NULL
*
* Since: 2.26
- */
-gint
-g_time_zone_get_offset (const GTimeZone *time_zone)
+ **/
+GDateTime *
+g_date_time_new_from_unix_local (gint64 t)
{
- g_return_val_if_fail (time_zone != NULL, 0);
+ GDateTime *datetime;
+ GTimeZone *local;
- if (!time_zone->is_floating)
- return time_zone->offset;
+ local = g_time_zone_new_local ();
+ datetime = g_date_time_new_from_unix (local, t);
+ g_time_zone_unref (local);
- return 0;
+ return datetime;
}
/**
- * g_time_zone_get_is_dst:
- * @time_zone: a #GTimeZone
+ * g_date_time_new_from_unix_utc:
+ * @t: the Unix time
+ *
+ * Creates a #GDateTime corresponding to the given Unix time @t in UTC.
+ *
+ * Unix time is the number of seconds that have elapsed since 1970-01-01
+ * 00:00:00 UTC.
+ *
+ * This call can fail (returning %NULL) if @t represents a time outside
+ * of the supported range of #GDateTime.
*
- * Checks whether the @time_zone is in Daylight Saving Time.
- * If the #GTimeZone is floating, %FALSE is always returned.
+ * You should release the return value by calling g_date_time_unref()
+ * when you are done with it.
*
- * Return value: %TRUE if the #GTimeZone is in DST, or %FALSE.
+ * Returns: a new #GDateTime, or %NULL
*
* Since: 2.26
- */
-gboolean
-g_time_zone_get_is_dst (const GTimeZone *time_zone)
+ **/
+GDateTime *
+g_date_time_new_from_unix_utc (gint64 t)
{
- g_return_val_if_fail (time_zone != NULL, FALSE);
+ GDateTime *datetime;
+ GTimeZone *utc;
- if (!time_zone->is_floating)
- return time_zone->is_dst;
+ utc = g_time_zone_new_utc ();
+ datetime = g_date_time_new_from_unix (utc, t);
+ g_time_zone_unref (utc);
- return FALSE;
+ return datetime;
}
/**
- * g_time_zone_is_floating:
- * @time_zone: a #GTimeZone
+ * g_date_time_new_from_timeval_local:
+ * @tv: a #GTimeVal
*
- * Checks whether @time_zone is floating
+ * Creates a #GDateTime corresponding to the given #GTimeVal @tv in the
+ * local time zone.
*
- * Return value: %TRUE if the #GTimeZone is floating, and %FALSE otherwise
+ * The time contained in a #GTimeVal is always stored in the form of
+ * seconds elapsed since 1970-01-01 00:00:00 UTC, regardless of the
+ * local time offset.
*
- * Since: 2.26
- */
-gboolean
-g_time_zone_is_floating (const GTimeZone *time_zone)
-{
- g_return_val_if_fail (time_zone != NULL, FALSE);
-
- return time_zone->is_floating;
-}
-
-/*< internal >
- * g_time_zone_sink:
- * @time_zone: a #GTimeZone
- * @datetime: a #GDateTime
+ * This call can fail (returning %NULL) if @tv represents a time outside
+ * of the supported range of #GDateTime.
*
- * Sinks the floating state of @time_zone by associating it with the
- * given #GDateTime.
+ * You should release the return value by calling g_date_time_unref()
+ * when you are done with it.
*
- * If @time_zone is not floating, this function does not do anything
- */
-static void
-g_time_zone_sink (GTimeZone *time_zone,
- GDateTime *datetime)
-{
- gint64 offset, epoch;
- gboolean is_dst, is_utc;
- gchar *abbrev;
-
- if (!time_zone->is_floating)
- return;
-
- epoch = g_date_time_to_epoch (datetime);
- is_utc = time_zone->is_utc;
- offset = 0;
- is_dst = FALSE;
- abbrev = NULL;
- if (parse_tzdata (time_zone->tz_file, epoch, is_utc, &offset, &is_dst, &abbrev))
- {
- time_zone->offset = offset;
- time_zone->is_dst = is_dst;
- time_zone->name = abbrev;
- time_zone->is_utc = (offset == 0);
- time_zone->is_floating = FALSE;
- }
-}
-
-static inline gint
-date_to_proleptic_gregorian (gint year,
- gint month,
- gint day)
-{
- gint64 days;
-
- days = (year - 1) * 365 + ((year - 1) / 4) - ((year - 1) / 100)
- + ((year - 1) / 400);
-
- days += days_in_year[0][month - 1];
- if (GREGORIAN_LEAP (year) && month > 2)
- day++;
-
- days += day;
-
- return days;
-}
-
-static inline void g_date_time_add_usec (GDateTime *datetime,
- gint64 usecs);
-
-static inline void
-g_date_time_add_days_internal (GDateTime *datetime,
- gint64 days)
-{
- gboolean was_dst = FALSE;
- gint64 old_offset = 0;
-
- if (datetime->tz != NULL && datetime->tz->tz_file != NULL)
- {
- was_dst = g_time_zone_get_is_dst (datetime->tz);
- old_offset = g_time_zone_get_offset (datetime->tz);
-
- datetime->tz->is_floating = TRUE;
- }
-
- datetime->days += days;
-
- if (datetime->tz != NULL && datetime->tz->tz_file != NULL)
- {
- gint64 offset;
-
- g_time_zone_sink (datetime->tz, datetime);
-
- if (was_dst == g_time_zone_get_is_dst (datetime->tz))
- return;
-
- offset = old_offset - g_time_zone_get_offset (datetime->tz);
- g_date_time_add_usec (datetime, offset * USEC_PER_SECOND * -1);
- }
-}
-
-static inline void
-g_date_time_add_usec (GDateTime *datetime,
- gint64 usecs)
+ * Returns: a new #GDateTime, or %NULL
+ *
+ * Since: 2.26
+ **/
+GDateTime *
+g_date_time_new_from_timeval_local (const GTimeVal *tv)
{
- gint64 u = datetime->usec + usecs;
- gint d = u / USEC_PER_DAY;
- gboolean was_dst = FALSE;
- gint64 old_offset = 0;
-
- /* if we are using a time zone from a zoneinfo we want to
- * check for changes in the DST and update the DateTime
- * accordingly in case we change for standard time to DST
- * and vice versa
- */
- if (datetime->tz != NULL && datetime->tz->tz_file != NULL)
- {
- was_dst = g_time_zone_get_is_dst (datetime->tz);
- old_offset = g_time_zone_get_offset (datetime->tz);
-
- /* force the floating state */
- datetime->tz->is_floating = TRUE;
- }
-
- if (u < 0)
- d -= 1;
-
- if (d != 0)
- g_date_time_add_days_internal (datetime, d);
-
- if (u < 0)
- datetime->usec = USEC_PER_DAY + (u % USEC_PER_DAY);
- else
- datetime->usec = u % USEC_PER_DAY;
-
- if (datetime->tz != NULL && datetime->tz->tz_file != NULL)
- {
- gint64 offset;
-
- /* sink the timezone; if there were no changes in the
- * DST state then bail out; otherwise, apply the change
- * in the offset to the DateTime
- */
- g_time_zone_sink (datetime->tz, datetime);
+ GDateTime *datetime;
+ GTimeZone *local;
- if (was_dst == g_time_zone_get_is_dst (datetime->tz))
- return;
+ local = g_time_zone_new_local ();
+ datetime = g_date_time_new_from_timeval (local, tv);
+ g_time_zone_unref (local);
- offset = old_offset - g_time_zone_get_offset (datetime->tz);
- g_date_time_add_usec (datetime, offset * USEC_PER_SECOND * -1);
- }
+ return datetime;
}
-/*< internal >
- * g_date_time_add_ymd:
- * @datetime: a #GDateTime
- * @years: years to add, in the Gregorian calendar
- * @months: months to add, in the Gregorian calendar
- * @days: days to add, in the Gregorian calendar
+/**
+ * g_date_time_new_from_timeval_utc:
+ * @tv: a #GTimeVal
*
- * Updates @datetime by adding @years, @months and @days to it
+ * Creates a #GDateTime corresponding to the given #GTimeVal @tv in UTC.
*
- * This function modifies the passed #GDateTime so public accessors
- * should make always pass a copy
- */
-static inline void
-g_date_time_add_ymd (GDateTime *datetime,
- gint years,
- gint months,
- gint days)
-{
- gint y = g_date_time_get_year (datetime);
- gint m = g_date_time_get_month (datetime);
- gint d = g_date_time_get_day_of_month (datetime);
- gint step, i;
- const guint16 *max_days;
-
- y += years;
-
- /* subtract one day for leap years */
- if (GREGORIAN_LEAP (y) && m == 2)
- {
- if (d == 29)
- d -= 1;
- }
-
- /* add months */
- step = months > 0 ? 1 : -1;
- for (i = 0; i < ABS (months); i++)
- {
- m += step;
-
- if (m < 1)
- {
- y -= 1;
- m = 12;
- }
- else if (m > 12)
- {
- y += 1;
- m = 1;
- }
- }
-
- /* clamp the days */
- max_days = days_in_months[GREGORIAN_LEAP (y) ? 1 : 0];
- if (max_days[m] < d)
- d = max_days[m];
-
- datetime->days = date_to_proleptic_gregorian (y, m, d);
- g_date_time_add_days_internal (datetime, days);
-}
-
-static GDateTime *
-g_date_time_new (void)
+ * The time contained in a #GTimeVal is always stored in the form of
+ * seconds elapsed since 1970-01-01 00:00:00 UTC.
+ *
+ * This call can fail (returning %NULL) if @tv represents a time outside
+ * of the supported range of #GDateTime.
+ *
+ * You should release the return value by calling g_date_time_unref()
+ * when you are done with it.
+ *
+ * Returns: a new #GDateTime, or %NULL
+ *
+ * Since: 2.26
+ **/
+GDateTime *
+g_date_time_new_from_timeval_utc (const GTimeVal *tv)
{
GDateTime *datetime;
+ GTimeZone *utc;
- datetime = g_slice_new0 (GDateTime);
- datetime->ref_count = 1;
+ utc = g_time_zone_new_utc ();
+ datetime = g_date_time_new_from_timeval (utc, tv);
+ g_time_zone_unref (utc);
return datetime;
}
-/*< internal >
- * g_date_time_copy:
- * @datetime: a #GDateTime
+/* full new functions {{{1 */
+
+/**
+ * g_date_time_new:
+ * @tz: a #GTimeZone
+ * @year: the year component of the date
+ * @month: the month component of the date
+ * @day: the day component of the date
+ * @hour: the hour component of the date
+ * @minute: the minute component of the date
+ * @seconds: the number of seconds past the minute
*
- * Creates a copy of @datetime.
+ * Creates a new #GDateTime corresponding to the given date and time in
+ * the time zone @tz.
*
- * Return value: the newly created #GDateTime which should be freed with
- * g_date_time_unref().
- */
-static GDateTime *
-g_date_time_copy (const GDateTime *datetime)
+ * The @year must be between 1 and 9999, @month between 1 and 12 and @day
+ * between 1 and 28, 29, 30 or 31 depending on the month and the year.
+ *
+ * @hour must be between 0 and 23 and @minute must be between 0 and 59.
+ *
+ * @seconds must be at least 0.0 and must be strictly less than 60.0.
+ * It will be rounded down to the nearest microsecond.
+ *
+ * If the given time is not representable in the given time zone (for
+ * example, 02:30 on March 14th 2010 in Toronto, due to daylight savings
+ * time) then the time will be rounded up to the nearest existing time
+ * (in this case, 03:00). If this matters to you then you should verify
+ * the return value for containing the same as the numbers you gave.
+ *
+ * In the case that the given time is ambiguous in the given time zone
+ * (for example, 01:30 on November 7th 2010 in Toronto, due to daylight
+ * savings time) then the time falling within standard (ie:
+ * non-daylight) time is taken.
+ *
+ * It not considered a programmer error for the values to this function
+ * to be out of range, but in the case that they are, the function will
+ * return %NULL.
+ *
+ * You should release the return value by calling g_date_time_unref()
+ * when you are done with it.
+ *
+ * Returns: a new #GDateTime, or %NULL
+ *
+ * Since: 2.26
+ **/
+GDateTime *
+g_date_time_new (GTimeZone *tz,
+ gint year,
+ gint month,
+ gint day,
+ gint hour,
+ gint minute,
+ gdouble seconds)
{
- GDateTime *copied;
-
- g_return_val_if_fail (datetime != NULL, NULL);
-
- copied = g_date_time_new ();
- copied->days = datetime->days;
- copied->usec = datetime->usec;
+ GDateTime *datetime;
+ gint64 full_time;
- if (datetime->tz != NULL)
- copied->tz = g_time_zone_copy (datetime->tz);
+ datetime = g_date_time_alloc (tz);
+ datetime->days = ymd_to_days (year, month, day);
+ datetime->usec = (hour * USEC_PER_HOUR)
+ + (minute * USEC_PER_MINUTE)
+ + (gint64) (seconds * USEC_PER_SECOND);
- return copied;
-}
+ full_time = SEC_PER_DAY *
+ (ymd_to_days (year, month, day) - UNIX_EPOCH_START) +
+ SECS_PER_HOUR * hour +
+ SECS_PER_MINUTE * minute +
+ (int) seconds;
-static void
-g_date_time_free (GDateTime *datetime)
-{
- if (G_UNLIKELY (datetime == NULL))
- return;
+ datetime->interval = g_time_zone_adjust_time (datetime->tz,
+ G_TIME_TYPE_STANDARD,
+ &full_time);
- if (datetime->tz != NULL)
- g_time_zone_free (datetime->tz);
+ full_time += UNIX_EPOCH_START * SEC_PER_DAY;
+ datetime->days = full_time / SEC_PER_DAY;
+ datetime->usec = (full_time % SEC_PER_DAY) * USEC_PER_SECOND;
+ datetime->usec += ((int) (seconds * USEC_PER_SECOND)) % USEC_PER_SECOND;
- g_slice_free (GDateTime, datetime);
+ return datetime;
}
/**
- * g_date_time_ref:
- * @datetime: a #GDateTime
+ * g_date_time_new_local:
+ * @year: the year component of the date
+ * @month: the month component of the date
+ * @day: the day component of the date
+ * @hour: the hour component of the date
+ * @minute: the minute component of the date
+ * @seconds: the number of seconds past the minute
*
- * Atomically increments the reference count of @datetime by one.
+ * Creates a new #GDateTime corresponding to the given date and time in
+ * the local time zone.
*
- * Return value: the #GDateTime with the reference count increased
+ * This call is equivalent to calling g_date_time_new() with the time
+ * zone returned by g_time_zone_new_local().
*
- * Since: 2.26
- */
+ * Returns: a #GDateTime, or %NULL
+ *
+ * Since: 2.26.
+ **/
GDateTime *
-g_date_time_ref (GDateTime *datetime)
+g_date_time_new_local (gint year,
+ gint month,
+ gint day,
+ gint hour,
+ gint minute,
+ gdouble seconds)
{
- g_return_val_if_fail (datetime != NULL, NULL);
- g_return_val_if_fail (datetime->ref_count > 0, NULL);
+ GDateTime *datetime;
+ GTimeZone *local;
- g_atomic_int_inc (&datetime->ref_count);
+ local = g_time_zone_new_local ();
+ datetime = g_date_time_new (local, year, month, day, hour, minute, seconds);
+ g_time_zone_unref (local);
return datetime;
}
/**
- * g_date_time_unref:
- * @datetime: a #GDateTime
+ * g_date_time_new_utc:
+ * @year: the year component of the date
+ * @month: the month component of the date
+ * @day: the day component of the date
+ * @hour: the hour component of the date
+ * @minute: the minute component of the date
+ * @seconds: the number of seconds past the minute
*
- * Atomically decrements the reference count of @datetime by one.
+ * Creates a new #GDateTime corresponding to the given date and time in
+ * UTC.
*
- * When the reference count reaches zero, the resources allocated by
- * @datetime are freed
+ * This call is equivalent to calling g_date_time_new() with the time
+ * zone returned by g_time_zone_new_utc().
*
- * Since: 2.26
- */
-void
-g_date_time_unref (GDateTime *datetime)
-{
- g_return_if_fail (datetime != NULL);
- g_return_if_fail (datetime->ref_count > 0);
-
- if (g_atomic_int_dec_and_test (&datetime->ref_count))
- g_date_time_free (datetime);
-}
-
-static void
-g_date_time_get_week_number (const GDateTime *datetime,
- gint *week_number,
- gint *day_of_week,
- gint *day_of_year)
+ * Returns: a #GDateTime, or %NULL
+ *
+ * Since: 2.26.
+ **/
+GDateTime *
+g_date_time_new_utc (gint year,
+ gint month,
+ gint day,
+ gint hour,
+ gint minute,
+ gdouble seconds)
{
- gint a, b, c, d, e, f, g, n, s, month, day, year;
-
- g_date_time_get_dmy (datetime, &day, &month, &year);
-
- if (month <= 2)
- {
- a = g_date_time_get_year (datetime) - 1;
- b = (a / 4) - (a / 100) + (a / 400);
- c = ((a - 1) / 4) - ((a - 1) / 100) + ((a - 1) / 400);
- s = b - c;
- e = 0;
- f = day - 1 + (31 * (month - 1));
- }
- else
- {
- a = year;
- b = (a / 4) - (a / 100) + (a / 400);
- c = ((a - 1) / 4) - ((a - 1) / 100) + ((a - 1) / 400);
- s = b - c;
- e = s + 1;
- f = day + (((153 * (month - 3)) + 2) / 5) + 58 + s;
- }
-
- g = (a + b) % 7;
- d = (f + g - e) % 7;
- n = f + 3 - d;
-
- if (week_number)
- {
- if (n < 0)
- *week_number = 53 - ((g - s) / 5);
- else if (n > 364 + s)
- *week_number = 1;
- else
- *week_number = (n / 7) + 1;
- }
+ GDateTime *datetime;
+ GTimeZone *utc;
- if (day_of_week)
- *day_of_week = d + 1;
+ utc = g_time_zone_new_utc ();
+ datetime = g_date_time_new (utc, year, month, day, hour, minute, seconds);
+ g_time_zone_unref (utc);
- if (day_of_year)
- *day_of_year = f + 1;
+ return datetime;
}
+/* Adders {{{1 */
+
/**
* g_date_time_add:
* @datetime: a #GDateTime
@@ -1164,17 +1020,11 @@ g_date_time_get_week_number (const GDateTime *datetime,
* Since: 2.26
*/
GDateTime*
-g_date_time_add (const GDateTime *datetime,
- GTimeSpan timespan)
+g_date_time_add (GDateTime *datetime,
+ GTimeSpan timespan)
{
- GDateTime *dt;
-
- g_return_val_if_fail (datetime != NULL, NULL);
-
- dt = g_date_time_copy (datetime);
- g_date_time_add_usec (dt, timespan);
-
- return dt;
+ return g_date_time_from_instant (datetime->tz, timespan +
+ g_date_time_to_instant (datetime));
}
/**
@@ -1190,18 +1040,26 @@ g_date_time_add (const GDateTime *datetime,
*
* Since: 2.26
*/
-GDateTime*
-g_date_time_add_years (const GDateTime *datetime,
- gint years)
+GDateTime *
+g_date_time_add_years (GDateTime *datetime,
+ gint years)
{
- GDateTime *dt;
+ gint year, month, day;
g_return_val_if_fail (datetime != NULL, NULL);
- dt = g_date_time_copy (datetime);
- g_date_time_add_ymd (dt, years, 0, 0);
+ if (years < -10000 || years > 10000)
+ return NULL;
+
+ g_date_time_get_ymd (datetime, &year, &month, &day);
+ year += years;
+
+ /* only possible issue is if we've entered a year with no February 29
+ */
+ if (month == 2 && day == 29 && !GREGORIAN_LEAP (year))
+ day = 28;
- return dt;
+ return g_date_time_replace_days (datetime, ymd_to_days (year, month, day));
}
/**
@@ -1218,17 +1076,33 @@ g_date_time_add_years (const GDateTime *datetime,
* Since: 2.26
*/
GDateTime*
-g_date_time_add_months (const GDateTime *datetime,
- gint months)
+g_date_time_add_months (GDateTime *datetime,
+ gint months)
{
- GDateTime *dt;
+ gint year, month, day;
g_return_val_if_fail (datetime != NULL, NULL);
+ g_date_time_get_ymd (datetime, &year, &month, &day);
+
+ if (months < -120000 || months > 120000)
+ return NULL;
+
+ year += months / 12;
+ month += months % 12;
+ if (month < 1)
+ {
+ month += 12;
+ year--;
+ }
+ else if (month > 12)
+ {
+ month -= 12;
+ year++;
+ }
- dt = g_date_time_copy (datetime);
- g_date_time_add_ymd (dt, 0, months, 0);
+ day = MIN (day, days_in_months[GREGORIAN_LEAP (year)][month]);
- return dt;
+ return g_date_time_replace_days (datetime, ymd_to_days (year, month, day));
}
/**
@@ -1245,7 +1119,7 @@ g_date_time_add_months (const GDateTime *datetime,
* Since: 2.26
*/
GDateTime*
-g_date_time_add_weeks (const GDateTime *datetime,
+g_date_time_add_weeks (GDateTime *datetime,
gint weeks)
{
g_return_val_if_fail (datetime != NULL, NULL);
@@ -1267,17 +1141,15 @@ g_date_time_add_weeks (const GDateTime *datetime,
* Since: 2.26
*/
GDateTime*
-g_date_time_add_days (const GDateTime *datetime,
- gint days)
+g_date_time_add_days (GDateTime *datetime,
+ gint days)
{
- GDateTime *dt;
-
g_return_val_if_fail (datetime != NULL, NULL);
- dt = g_date_time_copy (datetime);
- g_date_time_add_ymd (dt, 0, 0, days);
+ if (days < -3660000 || days > 3660000)
+ return NULL;
- return dt;
+ return g_date_time_replace_days (datetime, datetime->days + days);
}
/**
@@ -1293,25 +1165,18 @@ g_date_time_add_days (const GDateTime *datetime,
* Since: 2.26
*/
GDateTime*
-g_date_time_add_hours (const GDateTime *datetime,
- gint hours)
+g_date_time_add_hours (GDateTime *datetime,
+ gint hours)
{
- GDateTime *dt;
-
- g_return_val_if_fail (datetime != NULL, NULL);
-
- dt = g_date_time_copy (datetime);
- g_date_time_add_usec (dt, (gint64) hours * USEC_PER_HOUR);
-
- return dt;
+ return g_date_time_add (datetime, hours * USEC_PER_HOUR);
}
/**
- * g_date_time_add_seconds:
+ * g_date_time_add_minutes:
* @datetime: a #GDateTime
- * @seconds: the number of seconds to add
+ * @minutes: the number of minutes to add
*
- * Creates a copy of @datetime and adds the specified number of seconds.
+ * Creates a copy of @datetime adding the specified number of minutes.
*
* Return value: the newly created #GDateTime which should be freed with
* g_date_time_unref().
@@ -1319,51 +1184,19 @@ g_date_time_add_hours (const GDateTime *datetime,
* Since: 2.26
*/
GDateTime*
-g_date_time_add_seconds (const GDateTime *datetime,
- gint seconds)
+g_date_time_add_minutes (GDateTime *datetime,
+ gint minutes)
{
- GDateTime *dt;
-
- g_return_val_if_fail (datetime != NULL, NULL);
-
- dt = g_date_time_copy (datetime);
- g_date_time_add_usec (dt, (gint64) seconds * USEC_PER_SECOND);
-
- return dt;
+ return g_date_time_add (datetime, minutes * USEC_PER_MINUTE);
}
-/**
- * g_date_time_add_milliseconds:
- * @datetime: a #GDateTime
- * @milliseconds: the number of milliseconds to add
- *
- * Creates a copy of @datetime adding the specified number of milliseconds.
- *
- * Return value: the newly created #GDateTime which should be freed with
- * g_date_time_unref().
- *
- * Since: 2.26
- */
-GDateTime*
-g_date_time_add_milliseconds (const GDateTime *datetime,
- gint milliseconds)
-{
- GDateTime *dt;
-
- g_return_val_if_fail (datetime != NULL, NULL);
-
- dt = g_date_time_copy (datetime);
- g_date_time_add_usec (dt, (gint64) milliseconds * USEC_PER_MILLISECOND);
-
- return dt;
-}
/**
- * g_date_time_add_minutes:
+ * g_date_time_add_seconds:
* @datetime: a #GDateTime
- * @minutes: the number of minutes to add
+ * @seconds: the number of seconds to add
*
- * Creates a copy of @datetime adding the specified number of minutes.
+ * Creates a copy of @datetime and adds the specified number of seconds.
*
* Return value: the newly created #GDateTime which should be freed with
* g_date_time_unref().
@@ -1371,17 +1204,10 @@ g_date_time_add_milliseconds (const GDateTime *datetime,
* Since: 2.26
*/
GDateTime*
-g_date_time_add_minutes (const GDateTime *datetime,
- gint minutes)
+g_date_time_add_seconds (GDateTime *datetime,
+ gdouble seconds)
{
- GDateTime *dt;
-
- g_return_val_if_fail (datetime != NULL, NULL);
-
- dt = g_date_time_copy (datetime);
- g_date_time_add_usec (dt, (gint64) minutes * USEC_PER_MINUTE);
-
- return dt;
+ return g_date_time_add (datetime, seconds * USEC_PER_SECOND);
}
/**
@@ -1403,40 +1229,95 @@ g_date_time_add_minutes (const GDateTime *datetime,
* Since: 2.26
*/
GDateTime *
-g_date_time_add_full (const GDateTime *datetime,
- gint years,
- gint months,
- gint days,
- gint hours,
- gint minutes,
- gint seconds)
-{
- GDateTime *dt;
- gint64 usecs;
+g_date_time_add_full (GDateTime *datetime,
+ gint years,
+ gint months,
+ gint days,
+ gint hours,
+ gint minutes,
+ gdouble seconds)
+{
+ gint year, month, day;
+ gint64 full_time;
+ GDateTime *new;
+ gint interval;
g_return_val_if_fail (datetime != NULL, NULL);
+ g_date_time_get_ymd (datetime, &year, &month, &day);
+
+ months += years * 12;
+
+ if (months < -120000 || months > 120000)
+ return NULL;
+
+ if (days < -3660000 || days > 3660000)
+ return NULL;
+
+ year += months / 12;
+ month += months % 12;
+ if (month < 1)
+ {
+ month += 12;
+ year--;
+ }
+ else if (month > 12)
+ {
+ month -= 12;
+ year++;
+ }
- dt = g_date_time_copy (datetime);
+ day = MIN (day, days_in_months[GREGORIAN_LEAP (year)][month]);
- /* add date */
- g_date_time_add_ymd (dt, years, months, days);
+ /* full_time is now in unix (local) time */
+ full_time = datetime->usec / USEC_PER_SECOND + SEC_PER_DAY *
+ (ymd_to_days (year, month, day) + days - UNIX_EPOCH_START);
- /* add time */
- usecs = (hours * USEC_PER_HOUR)
- + (minutes * USEC_PER_MINUTE)
- + (seconds * USEC_PER_SECOND);
- g_date_time_add_usec (dt, usecs);
+ interval = g_time_zone_adjust_time (datetime->tz,
+ g_time_zone_is_dst (datetime->tz,
+ datetime->interval),
+ &full_time);
- return dt;
+ /* move to UTC unix time */
+ full_time -= g_time_zone_get_offset (datetime->tz, interval);
+
+ /* convert back to an instant, add back fractional seconds */
+ full_time += UNIX_EPOCH_START * SEC_PER_DAY;
+ full_time = full_time * USEC_PER_SECOND +
+ datetime->usec % USEC_PER_SECOND;
+
+ /* do the actual addition now */
+ full_time += (hours * USEC_PER_HOUR) +
+ (minutes * USEC_PER_MINUTE) +
+ (gint64) (seconds * USEC_PER_SECOND);
+
+ /* find the new interval */
+ interval = g_time_zone_find_interval (datetime->tz,
+ G_TIME_TYPE_UNIVERSAL,
+ INSTANT_TO_UNIX (full_time));
+
+ /* convert back into local time */
+ full_time += USEC_PER_SECOND *
+ g_time_zone_get_offset (datetime->tz, interval);
+
+ /* split into days and usec of a new datetime */
+ new = g_date_time_alloc (datetime->tz);
+ new->interval = interval;
+ new->days = full_time / USEC_PER_DAY;
+ new->usec = full_time % USEC_PER_DAY;
+
+ /* XXX validate */
+
+ return new;
}
+/* Compare, difference, hash, equal {{{1 */
/**
* g_date_time_compare:
* @dt1: first #GDateTime to compare
* @dt2: second #GDateTime to compare
*
- * qsort()-style comparison for #GDateTime<!-- -->'s. Both #GDateTime<-- -->'s
- * must be non-%NULL.
+ * #GCompareFunc-compatible comparison for #GDateTime<!-- -->'s. Both
+ * #GDateTime<-- -->'s must be non-%NULL.
*
* Return value: 0 for equal, less than zero if dt1 is less than dt2, greater
* than zero if dt2 is greator than dt1.
@@ -1447,58 +1328,28 @@ gint
g_date_time_compare (gconstpointer dt1,
gconstpointer dt2)
{
- const GDateTime *a, *b;
+ gint64 difference;
- a = dt1;
- b = dt2;
+ difference = g_date_time_difference ((GDateTime *) dt1, (GDateTime *) dt2);
- if ((a->days == b->days )&&
- (a->usec == b->usec))
- {
- return 0;
- }
- else if ((a->days > b->days) ||
- ((a->days == b->days) && a->usec > b->usec))
- {
- return 1;
- }
- else
+ if (difference < 0)
return -1;
-}
-/**
- * g_date_time_day:
- * @datetime: a #GDateTime
- *
- * Creates a new #GDateTime at Midnight on the date represented by @datetime.
- *
- * Return value: the newly created #GDateTime which should be freed with
- * g_date_time_unref().
- *
- * Since: 2.26
- */
-GDateTime*
-g_date_time_day (const GDateTime *datetime)
-{
- GDateTime *date;
+ else if (difference > 0)
+ return 1;
- g_return_val_if_fail (datetime != NULL, NULL);
-
- date = g_date_time_copy (datetime);
- date->usec = 0;
-
- return date;
+ else
+ return 0;
}
/**
* g_date_time_difference:
- * @begin: a #GDateTime
* @end: a #GDateTime
+ * @begin: a #GDateTime
*
- * Calculates the known difference in time between @begin and @end.
- *
- * Since the exact precision cannot always be known due to incomplete
- * historic information, an attempt is made to calculate the difference.
+ * Calculates the difference in time between @end and @begin. The
+ * #GTimeSpan that is returned is effectively @end - @begin (ie:
+ * positive if the first simparameter is larger).
*
* Return value: the difference between the two #GDateTime, as a time
* span expressed in microseconds.
@@ -1506,126 +1357,70 @@ g_date_time_day (const GDateTime *datetime)
* Since: 2.26
*/
GTimeSpan
-g_date_time_difference (const GDateTime *begin,
- const GDateTime *end)
+g_date_time_difference (GDateTime *end,
+ GDateTime *begin)
{
g_return_val_if_fail (begin != NULL, 0);
g_return_val_if_fail (end != NULL, 0);
- return (GTimeSpan) (((gint64) end->days - (gint64) begin->days)
- * USEC_PER_DAY) + ((gint64) end->usec - (gint64) begin->usec);
+ return g_date_time_to_instant (end) -
+ g_date_time_to_instant (begin);
}
/**
- * g_date_time_get_day_of_week:
+ * g_date_time_hash:
* @datetime: a #GDateTime
*
- * Retrieves the day of the week represented by @datetime within the gregorian
- * calendar. 1 is Sunday, 2 is Monday, etc.
+ * Hashes @datetime into a #guint, suitable for use within #GHashTable.
*
- * Return value: the day of the week
+ * Return value: a #guint containing the hash
*
* Since: 2.26
*/
-gint
-g_date_time_get_day_of_week (const GDateTime *datetime)
+guint
+g_date_time_hash (gconstpointer datetime)
{
- gint a, y, m,
- year = 0,
- month = 0,
- day = 0,
- dow;
-
- g_return_val_if_fail (datetime != NULL, 0);
-
- /*
- * See Calendar FAQ Section 2.6 for algorithm information
- * http://www.tondering.dk/claus/cal/calendar29.txt
- */
-
- g_date_time_get_dmy (datetime, &day, &month, &year);
- a = (14 - month) / 12;
- y = year - a;
- m = month + (12 * a) - 2;
- dow = ((day + y + (y / 4) - (y / 100) + (y / 400) + (31 * m) / 12) % 7);
-
- /* 1 is Monday and 7 is Sunday */
- return (dow == 0) ? 7 : dow;
+ return g_date_time_to_instant ((GDateTime *) datetime);
}
/**
- * g_date_time_get_day_of_month:
- * @datetime: a #GDateTime
- *
- * Retrieves the day of the month represented by @datetime in the gregorian
- * calendar.
- *
- * Return value: the day of the month
+ * g_date_time_equal:
+ * @dt1: a #GDateTime
+ * @dt2: a #GDateTime
*
- * Since: 2.26
- */
-gint
-g_date_time_get_day_of_month (const GDateTime *datetime)
-{
- gint day_of_year,
- i;
- const guint16 *days;
- guint16 last = 0;
-
- g_return_val_if_fail (datetime != NULL, 0);
-
- days = days_in_year[g_date_time_is_leap_year (datetime) ? 1 : 0];
- g_date_time_get_week_number (datetime, NULL, NULL, &day_of_year);
-
- for (i = 1; i <= 12; i++)
- {
- if (days [i] >= day_of_year)
- return day_of_year - last;
- last = days [i];
- }
-
- g_warn_if_reached ();
- return 0;
-}
-
-/**
- * g_date_time_get_day_of_year:
- * @datetime: a #GDateTime
+ * Checks to see if @dt1 and @dt2 are equal.
*
- * Retrieves the day of the year represented by @datetime in the Gregorian
- * calendar.
+ * Equal here means that they represent the same moment after converting
+ * them to the same time zone.
*
- * Return value: the day of the year
+ * Return value: %TRUE if @dt1 and @dt2 are equal
*
* Since: 2.26
*/
-gint
-g_date_time_get_day_of_year (const GDateTime *datetime)
+gboolean
+g_date_time_equal (gconstpointer dt1,
+ gconstpointer dt2)
{
- gint doy = 0;
-
- g_return_val_if_fail (datetime != NULL, 0);
-
- g_date_time_get_week_number (datetime, NULL, NULL, &doy);
- return doy;
+ return g_date_time_difference ((GDateTime *) dt1, (GDateTime *) dt2) == 0;
}
+/* Year, Month, Day Getters {{{1 */
/**
- * g_date_time_get_dmy:
+ * g_date_time_get_ymd:
* @datetime: a #GDateTime.
- * @day: (out): the return location for the day of the month, or %NULL.
- * @month: (out): the return location for the monty of the year, or %NULL.
* @year: (out): the return location for the gregorian year, or %NULL.
+ * @month: (out): the return location for the monty of the year, or %NULL.
+ * @day: (out): the return location for the day of the month, or %NULL.
*
* Retrieves the Gregorian day, month, and year of a given #GDateTime.
*
* Since: 2.26
- */
+ **/
void
-g_date_time_get_dmy (const GDateTime *datetime,
- gint *day,
- gint *month,
- gint *year)
+g_date_time_get_ymd (GDateTime *datetime,
+ gint *year,
+ gint *month,
+ gint *day)
{
gint the_year;
gint the_month;
@@ -1707,600 +1502,664 @@ end:
}
/**
- * g_date_time_get_hour:
- * @datetime: a #GDateTime
+ * g_date_time_get_year:
+ * @datetime: A #GDateTime
*
- * Retrieves the hour of the day represented by @datetime
+ * Retrieves the year represented by @datetime in the Gregorian calendar.
*
- * Return value: the hour of the day
+ * Return value: the year represented by @datetime
*
* Since: 2.26
*/
gint
-g_date_time_get_hour (const GDateTime *datetime)
+g_date_time_get_year (GDateTime *datetime)
{
+ gint year;
+
g_return_val_if_fail (datetime != NULL, 0);
- return (datetime->usec / USEC_PER_HOUR);
+ g_date_time_get_ymd (datetime, &year, NULL, NULL);
+
+ return year;
}
/**
- * g_date_time_get_julian:
+ * g_date_time_get_month:
* @datetime: a #GDateTime
- * @period: (out): a location for the Julian period
- * @julian: (out): a location for the day in the Julian period
- * @hour: (out): a location for the hour of the day
- * @minute: (out): a location for the minute of the hour
- * @second: (out): a location for hte second of the minute
*
- * Retrieves the Julian period, day, hour, minute, and second which @datetime
- * represents in the Julian calendar.
+ * Retrieves the month of the year represented by @datetime in the Gregorian
+ * calendar.
+ *
+ * Return value: the month represented by @datetime
*
* Since: 2.26
*/
-void
-g_date_time_get_julian (const GDateTime *datetime,
- gint *period,
- gint *julian,
- gint *hour,
- gint *minute,
- gint *second)
+gint
+g_date_time_get_month (GDateTime *datetime)
{
- gint y, m, d, a, b, c, e, f, j;
- g_return_if_fail (datetime != NULL);
-
- g_date_time_get_dmy (datetime, &d, &m, &y);
-
- /* FIXME: This is probably not optimal and doesn't handle the fact that the
- * julian calendar has its 0 hour on midday */
-
- a = y / 100;
- b = a / 4;
- c = 2 - a + b;
- e = 365.25 * (y + 4716);
- f = 30.6001 * (m + 1);
- j = c + d + e + f - 1524;
-
- if (period)
- *period = 0;
-
- if (julian)
- *julian = j;
+ gint month;
- if (hour)
- *hour = (datetime->usec / USEC_PER_HOUR);
+ g_return_val_if_fail (datetime != NULL, 0);
- if (minute)
- *minute = (datetime->usec % USEC_PER_HOUR) / USEC_PER_MINUTE;
+ g_date_time_get_ymd (datetime, NULL, &month, NULL);
- if (second)
- *second = (datetime->usec % USEC_PER_MINUTE) / USEC_PER_SECOND;
+ return month;
}
/**
- * g_date_time_get_microsecond:
+ * g_date_time_get_day_of_month:
* @datetime: a #GDateTime
*
- * Retrieves the microsecond of the date represented by @datetime
+ * Retrieves the day of the month represented by @datetime in the gregorian
+ * calendar.
*
- * Return value: the microsecond of the second
+ * Return value: the day of the month
*
* Since: 2.26
*/
gint
-g_date_time_get_microsecond (const GDateTime *datetime)
+g_date_time_get_day_of_month (GDateTime *datetime)
{
+ gint day_of_year,
+ i;
+ const guint16 *days;
+ guint16 last = 0;
+
g_return_val_if_fail (datetime != NULL, 0);
- return (datetime->usec % USEC_PER_SECOND);
+ days = days_in_year[GREGORIAN_LEAP (g_date_time_get_year (datetime)) ? 1 : 0];
+ g_date_time_get_week_number (datetime, NULL, NULL, &day_of_year);
+
+ for (i = 1; i <= 12; i++)
+ {
+ if (days [i] >= day_of_year)
+ return day_of_year - last;
+ last = days [i];
+ }
+
+ g_warn_if_reached ();
+ return 0;
}
+/* Week of year / day of week getters {{{1 */
/**
- * g_date_time_get_millisecond:
+ * g_date_time_get_week_of_year:
* @datetime: a #GDateTime
*
- * Retrieves the millisecond of the date represented by @datetime
+ * Returns the numeric week of the respective year.
*
- * Return value: the millisecond of the second
+ * Return value: the week of the year
*
* Since: 2.26
*/
gint
-g_date_time_get_millisecond (const GDateTime *datetime)
+g_date_time_get_week_of_year (GDateTime *datetime)
{
+ gint weeknum;
+
g_return_val_if_fail (datetime != NULL, 0);
- return (datetime->usec % USEC_PER_SECOND) / USEC_PER_MILLISECOND;
+ g_date_time_get_week_number (datetime, &weeknum, NULL, NULL);
+
+ return weeknum;
}
/**
- * g_date_time_get_minute:
+ * g_date_time_get_day_of_week:
* @datetime: a #GDateTime
*
- * Retrieves the minute of the hour represented by @datetime
+ * Retrieves the day of the week represented by @datetime within the gregorian
+ * calendar. 1 is Sunday, 2 is Monday, etc.
*
- * Return value: the minute of the hour
+ * Return value: the day of the week
*
* Since: 2.26
*/
gint
-g_date_time_get_minute (const GDateTime *datetime)
+g_date_time_get_day_of_week (GDateTime *datetime)
{
+ gint a, y, m,
+ year = 0,
+ month = 0,
+ day = 0,
+ dow;
+
g_return_val_if_fail (datetime != NULL, 0);
- return (datetime->usec % USEC_PER_HOUR) / USEC_PER_MINUTE;
+ /*
+ * See Calendar FAQ Section 2.6 for algorithm information
+ * http://www.tondering.dk/claus/cal/calendar29.txt
+ */
+
+ g_date_time_get_ymd (datetime, &year, &month, &day);
+ a = (14 - month) / 12;
+ y = year - a;
+ m = month + (12 * a) - 2;
+ dow = ((day + y + (y / 4) - (y / 100) + (y / 400) + (31 * m) / 12) % 7);
+
+ /* 1 is Monday and 7 is Sunday */
+ return (dow == 0) ? 7 : dow;
}
+/* Day of year getter {{{1 */
/**
- * g_date_time_get_month:
+ * g_date_time_get_day_of_year:
* @datetime: a #GDateTime
*
- * Retrieves the month of the year represented by @datetime in the Gregorian
+ * Retrieves the day of the year represented by @datetime in the Gregorian
* calendar.
*
- * Return value: the month represented by @datetime
+ * Return value: the day of the year
*
* Since: 2.26
*/
gint
-g_date_time_get_month (const GDateTime *datetime)
+g_date_time_get_day_of_year (GDateTime *datetime)
{
- gint month;
+ gint doy = 0;
g_return_val_if_fail (datetime != NULL, 0);
- g_date_time_get_dmy (datetime, NULL, &month, NULL);
-
- return month;
+ g_date_time_get_week_number (datetime, NULL, NULL, &doy);
+ return doy;
}
+/* Time component getters {{{1 */
+
/**
- * g_date_time_get_second:
+ * g_date_time_get_hour:
* @datetime: a #GDateTime
*
- * Retrieves the second of the minute represented by @datetime
+ * Retrieves the hour of the day represented by @datetime
*
- * Return value: the second represented by @datetime
+ * Return value: the hour of the day
*
* Since: 2.26
*/
gint
-g_date_time_get_second (const GDateTime *datetime)
+g_date_time_get_hour (GDateTime *datetime)
{
g_return_val_if_fail (datetime != NULL, 0);
- return (datetime->usec % USEC_PER_MINUTE) / USEC_PER_SECOND;
+ return (datetime->usec / USEC_PER_HOUR);
}
/**
- * g_date_time_get_utc_offset:
+ * g_date_time_get_minute:
* @datetime: a #GDateTime
*
- * Retrieves the offset from UTC that the local timezone specified by
- * @datetime represents.
- *
- * If @datetime represents UTC time, then the offset is zero.
+ * Retrieves the minute of the hour represented by @datetime
*
- * Return value: the offset, expressed as a time span expressed in
- * microseconds.
+ * Return value: the minute of the hour
*
* Since: 2.26
*/
-GTimeSpan
-g_date_time_get_utc_offset (const GDateTime *datetime)
+gint
+g_date_time_get_minute (GDateTime *datetime)
{
- gint offset = 0;
-
g_return_val_if_fail (datetime != NULL, 0);
- if (datetime->tz != NULL)
- offset = g_time_zone_get_offset (datetime->tz);
-
- return (gint64) offset * USEC_PER_SECOND;
+ return (datetime->usec % USEC_PER_HOUR) / USEC_PER_MINUTE;
}
/**
- * g_date_time_get_timezone_name:
+ * g_date_time_get_second:
* @datetime: a #GDateTime
*
- * Retrieves the name of the timezone specified by @datetime, if any.
+ * Retrieves the second of the minute represented by @datetime
*
- * Return value: (transfer none): the name of the timezone. The returned
- * string is owned by the #GDateTime and it should not be modified or
- * freed
+ * Return value: the second represented by @datetime
*
* Since: 2.26
*/
-G_CONST_RETURN gchar *
-g_date_time_get_timezone_name (const GDateTime *datetime)
+gint
+g_date_time_get_second (GDateTime *datetime)
{
- g_return_val_if_fail (datetime != NULL, NULL);
-
- if (datetime->tz != NULL)
- return g_time_zone_get_name (datetime->tz);
+ g_return_val_if_fail (datetime != NULL, 0);
- return "UTC";
+ return (datetime->usec % USEC_PER_MINUTE) / USEC_PER_SECOND;
}
/**
- * g_date_time_get_year:
- * @datetime: A #GDateTime
+ * g_date_time_get_microsecond:
+ * @datetime: a #GDateTime
*
- * Retrieves the year represented by @datetime in the Gregorian calendar.
+ * Retrieves the microsecond of the date represented by @datetime
*
- * Return value: the year represented by @datetime
+ * Return value: the microsecond of the second
*
* Since: 2.26
*/
gint
-g_date_time_get_year (const GDateTime *datetime)
+g_date_time_get_microsecond (GDateTime *datetime)
{
- gint year;
-
g_return_val_if_fail (datetime != NULL, 0);
- g_date_time_get_dmy (datetime, NULL, NULL, &year);
-
- return year;
+ return (datetime->usec % USEC_PER_SECOND);
}
/**
- * g_date_time_hash:
+ * g_date_time_get_seconds:
* @datetime: a #GDateTime
*
- * Hashes @datetime into a #guint, suitable for use within #GHashTable.
+ * Retrieves the number of seconds since the start of the last minute,
+ * including the fractional part.
*
- * Return value: a #guint containing the hash
+ * Returns: the number of seconds
*
* Since: 2.26
- */
-guint
-g_date_time_hash (gconstpointer datetime)
+ **/
+gdouble
+g_date_time_get_seconds (GDateTime *datetime)
{
- GDateTime *dt_utc;
- gint64 epoch;
-
- dt_utc = g_date_time_to_utc (datetime);
- epoch = g_date_time_to_epoch (dt_utc);
- g_date_time_unref (dt_utc);
+ g_return_val_if_fail (datetime != NULL, 0);
- return (guint) epoch;
+ return (datetime->usec % USEC_PER_MINUTE) / 1000000.0;
}
+/* Exporters {{{1 */
/**
- * g_date_time_equal:
- * @dt1: a #GDateTime
- * @dt2: a #GDateTime
+ * g_date_time_to_unix:
+ * @datetime: a #GDateTime
*
- * Checks to see if @dt1 and @dt2 are equal.
+ * Gives the Unix time corresponding to @datetime, rounding down to the
+ * nearest second.
*
- * Equal here means that they represent the same moment after converting
- * them to the same timezone.
+ * Unix time is the number of seconds that have elapsed since 1970-01-01
+ * 00:00:00 UTC, regardless of the time zone associated with @datetime.
*
- * Return value: %TRUE if @dt1 and @dt2 are equal
+ * Returns: the Unix time corresponding to @datetime
*
* Since: 2.26
- */
-gboolean
-g_date_time_equal (gconstpointer dt1,
- gconstpointer dt2)
+ **/
+gint64
+g_date_time_to_unix (GDateTime *datetime)
{
- const GDateTime *a, *b;
- GDateTime *a_utc, *b_utc;
- gint64 a_epoch, b_epoch;
-
- a = dt1;
- b = dt2;
-
- a_utc = g_date_time_to_utc (a);
- b_utc = g_date_time_to_utc (b);
-
- a_epoch = g_date_time_to_epoch (a_utc);
- b_epoch = g_date_time_to_epoch (b_utc);
-
- g_date_time_unref (a_utc);
- g_date_time_unref (b_utc);
-
- return a_epoch == b_epoch;
+ return INSTANT_TO_UNIX (g_date_time_to_instant (datetime));
}
/**
- * g_date_time_is_leap_year:
+ * g_date_time_to_timeval:
* @datetime: a #GDateTime
+ * @tv: a #GTimeVal to modify
+ *
+ * Stores the instant in time that @datetime represents into @tv.
*
- * Determines if @datetime represents a date known to fall within
- * a leap year in the Gregorian calendar.
+ * The time contained in a #GTimeVal is always stored in the form of
+ * seconds elapsed since 1970-01-01 00:00:00 UTC, regardless of the time
+ * zone associated with @datetime.
*
- * Return value: %TRUE if @datetime is a leap year.
+ * On systems where 'long' is 32bit (ie: all 32bit systems and all
+ * Windows systems), a #GTimeVal is incapable of storing the entire
+ * range of values that #GDateTime is capable of expressing. On those
+ * systems, this function returns %FALSE to indicate that the time is
+ * out of range.
+ *
+ * On systems where 'long' is 64bit, this function never fails.
+ *
+ * Returns: %TRUE if successful, else %FALSE
*
* Since: 2.26
- */
+ **/
gboolean
-g_date_time_is_leap_year (const GDateTime *datetime)
+g_date_time_to_timeval (GDateTime *datetime,
+ GTimeVal *tv)
{
- gint year;
-
- g_return_val_if_fail (datetime != NULL, FALSE);
-
- year = g_date_time_get_year (datetime);
+ tv->tv_sec = INSTANT_TO_UNIX (g_date_time_to_instant (datetime));
+ tv->tv_usec = datetime->usec % USEC_PER_SECOND;
- return GREGORIAN_LEAP (year);
+ return TRUE;
}
+/* Timezone queries {{{1 */
/**
- * g_date_time_is_daylight_savings:
+ * g_date_time_get_utc_offset:
* @datetime: a #GDateTime
*
- * Determines if @datetime represents a date known to fall within daylight
- * savings time in the gregorian calendar.
+ * Determines the offset to UTC in effect at the time and in the time
+ * zone of @datetime.
*
- * Return value: %TRUE if @datetime falls within daylight savings time.
+ * The offset is the number of microseconds that you add to UTC time to
+ * arrive at local time for the time zone (ie: negative numbers for time
+ * zones west of GMT, positive numbers for east).
+ *
+ * If @datetime represents UTC time, then the offset is always zero.
+ *
+ * Returns: the number of microseconds that should be added to UTC to
+ * get the local time
*
* Since: 2.26
- */
-gboolean
-g_date_time_is_daylight_savings (const GDateTime *datetime)
+ **/
+GTimeSpan
+g_date_time_get_utc_offset (GDateTime *datetime)
{
- g_return_val_if_fail (datetime != NULL, FALSE);
+ gint offset;
- if (datetime->tz == NULL)
- return FALSE;
+ g_return_val_if_fail (datetime != NULL, 0);
- return datetime->tz->is_dst;
+ offset = g_time_zone_get_offset (datetime->tz, datetime->interval);
+
+ return (gint64) offset * USEC_PER_SECOND;
}
/**
- * g_date_time_new_from_date:
- * @year: the Gregorian year
- * @month: the Gregorian month
- * @day: the day in the Gregorian month
+ * g_date_time_get_timezone_abbreviation:
+ * @datetime: a #GDateTime
*
- * Creates a new #GDateTime using the specified date within the Gregorian
- * calendar.
+ * Determines the time zone abbreviation to be used at the time and in
+ * the time zone of @datetime.
*
- * Return value: the newly created #GDateTime or %NULL if it is outside of
- * the representable range.
+ * For example, in Toronto this is currently "EST" during the winter
+ * months and "EDT" during the summer months when daylight savings
+ * time is in effect.
+ *
+ * Returns: (transfer none): the time zone abbreviation. The returned
+ * string is owned by the #GDateTime and it should not be
+ * modified or freed
*
* Since: 2.26
- */
-GDateTime *
-g_date_time_new_from_date (gint year,
- gint month,
- gint day)
+ **/
+const gchar *
+g_date_time_get_timezone_abbreviation (GDateTime *datetime)
{
- GDateTime *dt;
-
- g_return_val_if_fail (year > -4712 && year <= 3268, NULL);
- g_return_val_if_fail (month > 0 && month <= 12, NULL);
- g_return_val_if_fail (day > 0 && day <= 31, NULL);
-
- dt = g_date_time_new ();
-
- dt->days = date_to_proleptic_gregorian (year, month, day);
- dt->tz = g_time_zone_new_local ();
- g_time_zone_sink (dt->tz, dt);
+ g_return_val_if_fail (datetime != NULL, NULL);
- return dt;
+ return g_time_zone_get_abbreviation (datetime->tz, datetime->interval);
}
/**
- * g_date_time_new_from_epoch:
- * @t: seconds from the Unix epoch
- *
- * Creates a new #GDateTime using the time since Jan 1, 1970 specified by @t.
+ * g_date_time_is_daylight_savings:
+ * @datetime: a #GDateTime
*
- * The timezone of the returned #GDateTime is the local time.
+ * Determines if daylight savings time is in effect at the time and in
+ * the time zone of @datetime.
*
- * Return value: the newly created #GDateTime
+ * Returns: %TRUE if daylight savings time is in effect
*
* Since: 2.26
- */
-GDateTime*
-g_date_time_new_from_epoch (gint64 t)
+ **/
+gboolean
+g_date_time_is_daylight_savings (GDateTime *datetime)
{
- GDateTime *datetime;
- GTimeZone *tz;
- struct tm tm;
- time_t tt;
-
- tt = (time_t) t;
- memset (&tm, 0, sizeof (tm));
-
- /* XXX: GLib should probably have a wrapper for this */
-#ifdef HAVE_LOCALTIME_R
- localtime_r (&tt, &tm);
-#else
- {
- struct tm *ptm = localtime (&tt);
-
- if (ptm == NULL)
- {
- /* Happens at least in Microsoft's C library if you pass a
- * negative time_t. Use 2000-01-01 as default date.
- */
-#ifndef G_DISABLE_CHECKS
- g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, "ptm != NULL");
-#endif
-
- tm.tm_mon = 0;
- tm.tm_mday = 1;
- tm.tm_year = 100;
- }
- else
- memcpy ((void *) &tm, (void *) ptm, sizeof (struct tm));
- }
-#endif /* HAVE_LOCALTIME_R */
-
- tz = g_time_zone_new_local ();
- datetime = g_date_time_new_full (tm.tm_year + 1900,
- tm.tm_mon + 1,
- tm.tm_mday,
- tm.tm_hour,
- tm.tm_min,
- tm.tm_sec,
- tz);
- g_time_zone_free (tz);
+ g_return_val_if_fail (datetime != NULL, FALSE);
- return datetime;
+ return g_time_zone_is_dst (datetime->tz, datetime->interval);
}
+/* Timezone convert {{{1 */
/**
- * g_date_time_new_from_timeval:
- * @tv: #GTimeVal
+ * g_date_time_to_timezone:
+ * @datetime: a #GDateTime
+ * @tz: the new #GTimeZone
+ *
+ * Create a new #GDateTime corresponding to the same instant in time as
+ * @datetime, but in the time zone @tz.
*
- * Creates a new #GDateTime using the date and time specified by #GTimeVal.
+ * This call can fail in the case that the time goes out of bounds. For
+ * example, converting 0001-01-01 00:00:00 UTC to a time zone west of
+ * Greenwich will fail (due to the year 0 being out of range).
*
- * The timezone of the returned #GDateTime is UTC.
+ * You should release the return value by calling g_date_time_unref()
+ * when you are done with it.
*
- * Return value: the newly created #GDateTime
+ * Returns: a new #GDateTime, or %NULL
*
* Since: 2.26
- */
+ **/
GDateTime *
-g_date_time_new_from_timeval (GTimeVal *tv)
+g_date_time_to_timezone (GDateTime *datetime,
+ GTimeZone *tz)
{
- GDateTime *datetime;
-
- g_return_val_if_fail (tv != NULL, NULL);
-
- datetime = g_date_time_new_from_epoch (tv->tv_sec);
- datetime->usec += tv->tv_usec;
- datetime->tz = g_time_zone_new_local ();
- g_time_zone_sink (datetime->tz, datetime);
-
- return datetime;
+ return g_date_time_from_instant (tz, g_date_time_to_instant (datetime));
}
/**
- * g_date_time_new_full:
- * @year: the Gregorian year
- * @month: the Gregorian month
- * @day: the day of the Gregorian month
- * @hour: the hour of the day
- * @minute: the minute of the hour
- * @second: the second of the minute, with eventual fractionary parts
- * @time_zone: (allow-none): a #GTimeZone, or %NULL for UTC
- *
- * Creates a new #GDateTime using the date and times in the Gregorian
- * calendar.
+ * g_date_time_to_local:
+ * @datetime: a #GDateTime
+ *
+ * Creates a new #GDateTime corresponding to the same instant in time as
+ * @datetime, but in the local time zone.
*
- * If @time_zone is not %NULL, the #GDateTime will copy the #GTimeZone
- * and sink it, if floating.
+ * This call is equivalent to calling g_date_time_to_timezone() with the
+ * time zone returned by g_time_zone_new_local().
*
- * Return value: the newly created #GDateTime
+ * Returns: the newly created #GDateTime
*
* Since: 2.26
- */
+ **/
GDateTime *
-g_date_time_new_full (gint year,
- gint month,
- gint day,
- gint hour,
- gint minute,
- gdouble second,
- const GTimeZone *time_zone)
+g_date_time_to_local (GDateTime *datetime)
{
- GDateTime *dt;
-
- g_return_val_if_fail (hour >= 0 && hour < 24, NULL);
- g_return_val_if_fail (minute >= 0 && minute < 60, NULL);
- g_return_val_if_fail (second >= 0.0 && second <= 60.0, NULL);
+ GDateTime *new;
+ GTimeZone *local;
- dt = g_date_time_new ();
- dt->days = date_to_proleptic_gregorian (year, month, day);
- dt->usec = (hour * USEC_PER_HOUR)
- + (minute * USEC_PER_MINUTE)
- + (second * USEC_PER_SECOND);
+ local = g_time_zone_new_local ();
+ new = g_date_time_to_timezone (datetime, local);
+ g_time_zone_unref (local);
- if (time_zone != NULL)
- {
- dt->tz = g_time_zone_copy (time_zone);
- g_time_zone_sink (dt->tz, dt);
- }
- else
- dt->tz = NULL;
-
- return dt;
+ return new;
}
/**
- * g_date_time_new_now:
+ * g_date_time_to_utc:
+ * @datetime: a #GDateTime
*
- * Creates a new #GDateTime representing the current date and time.
+ * Creates a new #GDateTime corresponding to the same instant in time as
+ * @datetime, but in UTC.
*
- * Return value: the newly created #GDateTime which should be freed with
- * g_date_time_unref().
+ * This call is equivalent to calling g_date_time_to_timezone() with the
+ * time zone returned by g_time_zone_new_utc().
+ *
+ * Returns: the newly created #GDateTime
*
* Since: 2.26
- */
-GDateTime*
-g_date_time_new_now (void)
+ **/
+GDateTime *
+g_date_time_to_utc (GDateTime *datetime)
{
- GTimeVal tv;
+ GDateTime *new;
+ GTimeZone *utc;
- g_get_current_time (&tv);
+ utc = g_time_zone_new_utc ();
+ new = g_date_time_to_timezone (datetime, utc);
+ g_time_zone_unref (utc);
- return g_date_time_new_from_timeval (&tv);
+ return new;
}
+/* Format {{{1 */
/**
* g_date_time_format:
* @datetime: A #GDateTime
- * @format: a valid UTF-8 string, containing the format for the #GDateTime
+ * @format: a valid UTF-8 string, containing the format for the
+ * #GDateTime
*
* Creates a newly allocated string representing the requested @format.
*
* The following format specifiers are supported:
*
- * %%a The abbreviated weekday name according to the current locale.
- * %%A The full weekday name according to the current locale.
- * %%b The abbreviated month name according to the current locale.
- * %%B The full month name according to the current locale.
- * %%d The day of the month as a decimal number (range 01 to 31).
- * %%e The day of the month as a decimal number (range 1 to 31).
- * %%F Equivalent to %Y-%m-%d (the ISO 8601 date format).
- * %%h Equivalent to %b.
- * %%H The hour as a decimal number using a 24-hour clock (range 00 to 23).
- * %%I The hour as a decimal number using a 12-hour clock (range 01 to 12).
- * %%j The day of the year as a decimal number (range 001 to 366).
- * %%k The hour (24-hour clock) as a decimal number (range 0 to 23);
- * single digits are preceded by a blank.
- * %%l The hour (12-hour clock) as a decimal number (range 1 to 12);
- * single digits are preceded by a blank.
- * %%m The month as a decimal number (range 01 to 12).
- * %%M The minute as a decimal number (range 00 to 59).
- * %%N The micro-seconds as a decimal number.
- * %%p Either "AM" or "PM" according to the given time value, or the
- * corresponding strings for the current locale. Noon is treated
- * as "PM" and midnight as "AM".
- * %%P Like %%p but lowercase: "am" or "pm" or a corresponding string for
- * the current locale.
- * %%r The time in a.m. or p.m. notation.
- * %%R The time in 24-hour notation (%H:%M).
- * %%s The number of seconds since the Epoch, that is, since 1970-01-01
- * 00:00:00 UTC.
- * %%S The second as a decimal number (range 00 to 60).
- * %%t A tab character.
- * %%u The day of the week as a decimal, range 1 to 7, Monday being 1.
- * %%W The week number of the current year as a decimal number.
- * %%x The preferred date representation for the current locale without
- * the time.
- * %%X The preferred date representation for the current locale without
- * the date.
- * %%y The year as a decimal number without the century.
- * %%Y The year as a decimal number including the century.
- * %%z The time-zone as hour offset from UTC
- * %%Z The timezone or name or abbreviation
- * %%% A literal %% character.
- *
- * Return value: a newly allocated string formatted to the requested format or
- * %NULL in the case that there was an error. The string should be freed
- * with g_free().
+ * <variablelist>
+ * <varlistentry><term>
+ * <literal>%%a</literal>:
+ * </term><listitem><simpara>
+ * the abbreviated weekday name according to the current locale
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%A</literal>:
+ * </term><listitem><simpara>
+ * the full weekday name according to the current locale
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%b</literal>:
+ * </term><listitem><simpara>
+ * the abbreviated month name according to the current locale
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%B</literal>:
+ * </term><listitem><simpara>
+ * the full month name according to the current locale
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%d</literal>:
+ * </term><listitem><simpara>
+ * the day of the month as a decimal number (range 01 to 31)
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%e</literal>:
+ * </term><listitem><simpara>
+ * the day of the month as a decimal number (range 1 to 31)
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%F</literal>:
+ * </term><listitem><simpara>
+ * equivalent to <literal>%%Y-%%m-%%d</literal> (the ISO 8601 date
+ * format)
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%h</literal>:
+ * </term><listitem><simpara>
+ * equivalent to <literal>%%b</literal>
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%H</literal>:
+ * </term><listitem><simpara>
+ * the hour as a decimal number using a 24-hour clock (range 00 to
+ * 23)
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%I</literal>:
+ * </term><listitem><simpara>
+ * the hour as a decimal number using a 12-hour clock (range 01 to
+ * 12)
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%j</literal>:
+ * </term><listitem><simpara>
+ * the day of the year as a decimal number (range 001 to 366)
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%k</literal>:
+ * </term><listitem><simpara>
+ * the hour (24-hour clock) as a decimal number (range 0 to 23);
+ * single digits are preceded by a blank
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%l</literal>:
+ * </term><listitem><simpara>
+ * the hour (12-hour clock) as a decimal number (range 1 to 12);
+ * single digits are preceded by a blank
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%m</literal>:
+ * </term><listitem><simpara>
+ * the month as a decimal number (range 01 to 12)
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%M</literal>:
+ * </term><listitem><simpara>
+ * the minute as a decimal number (range 00 to 59)
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%N</literal>:
+ * </term><listitem><simpara>
+ * the micro-seconds as a decimal number
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%p</literal>:
+ * </term><listitem><simpara>
+ * either "AM" or "PM" according to the given time value, or the
+ * corresponding strings for the current locale. Noon is treated as
+ * "PM" and midnight as "AM".
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%P</literal>:
+ * </term><listitem><simpara>
+ * like %%p but lowercase: "am" or "pm" or a corresponding string for
+ * the current locale
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%r</literal>:
+ * </term><listitem><simpara>
+ * the time in a.m. or p.m. notation
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%R</literal>:
+ * </term><listitem><simpara>
+ * the time in 24-hour notation (<literal>%%H:%%M</literal>)
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%s</literal>:
+ * </term><listitem><simpara>
+ * the number of seconds since the Epoch, that is, since 1970-01-01
+ * 00:00:00 UTC
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%S</literal>:
+ * </term><listitem><simpara>
+ * the second as a decimal number (range 00 to 60)
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%t</literal>:
+ * </term><listitem><simpara>
+ * a tab character
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%u</literal>:
+ * </term><listitem><simpara>
+ * the day of the week as a decimal, range 1 to 7, Monday being 1
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%W</literal>:
+ * </term><listitem><simpara>
+ * the week number of the current year as a decimal number
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%x</literal>:
+ * </term><listitem><simpara>
+ * the preferred date representation for the current locale without
+ * the time
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%X</literal>:
+ * </term><listitem><simpara>
+ * the preferred time representation for the current locale without
+ * the date
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%y</literal>:
+ * </term><listitem><simpara>
+ * the year as a decimal number without the century
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%Y</literal>:
+ * </term><listitem><simpara>
+ * the year as a decimal number including the century
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%z</literal>:
+ * </term><listitem><simpara>
+ * the time-zone as hour offset from UTC
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%Z</literal>:
+ * </term><listitem><simpara>
+ * the time zone or name or abbreviation
+ * </simpara></listitem></varlistentry>
+ * <varlistentry><term>
+ * <literal>%%%</literal>:
+ * </term><listitem><simpara>
+ * a literal <literal>%%</literal> character
+ * </simpara></listitem></varlistentry>
+ * </variablelist>
+ *
+ * Returns: a newly allocated string formatted to the requested format
+ * or %NULL in the case that there was an error. The string
+ * should be freed with g_free().
*
* Since: 2.26
*/
gchar *
-g_date_time_format (const GDateTime *datetime,
+g_date_time_format (GDateTime *datetime,
const gchar *format)
{
GString *outstr;
@@ -2416,7 +2275,7 @@ g_date_time_format (const GDateTime *datetime,
g_date_time_get_minute (datetime));
break;
case 's':
- g_string_append_printf (outstr, "%" G_GINT64_FORMAT, g_date_time_to_epoch (datetime));
+ g_string_append_printf (outstr, "%" G_GINT64_FORMAT, g_date_time_to_unix (datetime));
break;
case 'S':
g_string_append_printf (outstr, "%02d", g_date_time_get_second (datetime));
@@ -2465,10 +2324,7 @@ g_date_time_format (const GDateTime *datetime,
g_string_append (outstr, "+0000");
break;
case 'Z':
- if (datetime->tz != NULL)
- g_string_append (outstr, g_date_time_get_timezone_name (datetime));
- else
- g_string_append (outstr, "UTC");
+ g_string_append (outstr, g_date_time_get_timezone_abbreviation (datetime));
break;
case '%':
g_string_append_c (outstr, '%');
@@ -2493,177 +2349,6 @@ bad_format:
return NULL;
}
-/**
- * g_date_time_to_local:
- * @datetime: a #GDateTime
- *
- * Creates a new #GDateTime with @datetime converted to local time.
- *
- * Return value: the newly created #GDateTime
- *
- * Since: 2.26
- */
-GDateTime *
-g_date_time_to_local (const GDateTime *datetime)
-{
- GDateTime *dt;
-
- g_return_val_if_fail (datetime != NULL, NULL);
-
- dt = g_date_time_copy (datetime);
- if (dt->tz == NULL)
- {
- dt->tz = g_time_zone_new_local ();
- if (dt->tz == NULL)
- return dt;
-
- g_time_zone_sink (dt->tz, dt);
- g_date_time_add_usec (dt, dt->tz->offset * USEC_PER_SECOND);
- }
-
- return dt;
-}
-/**
- * g_date_time_to_epoch:
- * @datetime: a #GDateTime
- *
- * Converts @datetime into an integer representing seconds since the
- * Unix epoch
- *
- * Return value: @datetime as seconds since the Unix epoch
- *
- * Since: 2.26
- */
-gint64
-g_date_time_to_epoch (const GDateTime *datetime)
-{
- gint64 result;
-
- g_return_val_if_fail (datetime != NULL, 0);
-
- if (datetime->days <= 0)
- return G_MININT64;
-
- result = (datetime->days - UNIX_EPOCH_START) * SEC_PER_DAY
- + datetime->usec / USEC_PER_SECOND
- - g_date_time_get_utc_offset (datetime) / USEC_PER_SECOND;
-
- return result;
-}
-
-/**
- * g_date_time_to_timeval:
- * @datetime: a #GDateTime
- * @tv: A #GTimeVal
- *
- * Converts @datetime into a #GTimeVal and stores the result into @timeval.
- *
- * Since: 2.26
- */
-void
-g_date_time_to_timeval (const GDateTime *datetime,
- GTimeVal *tv)
-{
- g_return_if_fail (datetime != NULL);
- g_return_if_fail (tv != NULL);
-
- tv->tv_sec = g_date_time_to_epoch (datetime);
- tv->tv_usec = datetime->usec % USEC_PER_SECOND;
-}
-
-/**
- * g_date_time_to_utc:
- * @datetime: a #GDateTime
- *
- * Creates a new #GDateTime that reprents @datetime in Universal coordinated
- * time.
- *
- * Return value: the newly created #GDateTime which should be freed with
- * g_date_time_unref().
- *
- * Since: 2.26
- */
-GDateTime *
-g_date_time_to_utc (const GDateTime *datetime)
-{
- GDateTime *dt;
- GTimeSpan ts;
-
- g_return_val_if_fail (datetime != NULL, NULL);
-
- ts = g_date_time_get_utc_offset (datetime) * -1;
- dt = g_date_time_add (datetime, ts);
- if (dt->tz != NULL)
- {
- g_time_zone_free (dt->tz);
- dt->tz = NULL;
- }
-
- return dt;
-}
-
-/**
- * g_date_time_new_today:
- *
- * Createsa new #GDateTime that represents Midnight on the current day.
- *
- * Return value: the newly created #GDateTime which should be freed with
- * g_date_time_unref().
- *
- * Since: 2.26
- */
-GDateTime*
-g_date_time_new_today (void)
-{
- GDateTime *dt;
-
- dt = g_date_time_new_now ();
- dt->usec = 0;
-
- return dt;
-}
-
-/**
- * g_date_time_new_utc_now:
- *
- * Creates a new #GDateTime that represents the current instant in Universal
- * Coordinated Time (UTC).
- *
- * Return value: the newly created #GDateTime which should be freed with
- * g_date_time_unref().
- *
- * Since: 2.26
- */
-GDateTime *
-g_date_time_new_utc_now (void)
-{
- GDateTime *utc, *now;
-
- now = g_date_time_new_now ();
- utc = g_date_time_to_utc (now);
- g_date_time_unref (now);
-
- return utc;
-}
-
-/**
- * g_date_time_get_week_of_year:
- *
- * Returns the numeric week of the respective year.
- *
- * Return value: the week of the year
- *
- * Since: 2.26
- */
-gint
-g_date_time_get_week_of_year (const GDateTime *datetime)
-{
- gint weeknum;
-
- g_return_val_if_fail (datetime != NULL, 0);
-
- g_date_time_get_week_number (datetime, &weeknum, NULL, NULL);
-
- return weeknum;
-}
+/* Epilogue {{{1 */
+/* vim:set foldmethod=marker: */
diff --git a/glib/gdatetime.h b/glib/gdatetime.h
index 727a855..8f8533a 100644
--- a/glib/gdatetime.h
+++ b/glib/gdatetime.h
@@ -1,20 +1,26 @@
-/* gdatetime.h
- *
+/*
* Copyright (C) 2009-2010 Christian Hergert <chris dronelabs com>
+ * Copyright © 2010 Codethink Limited
*
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * licence, or (at your option) any later version.
*
- * This is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
+ * This is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ *
+ * Authors: Christian Hergert <chris dronelabs com>
+ * Thiago Santos <thiago sousa santos collabora co uk>
+ * Emmanuele Bassi <ebassi linux intel com>
+ * Ryan Lortie <desrt desrt ca>
*/
#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
@@ -24,8 +30,7 @@
#ifndef __G_DATE_TIME_H__
#define __G_DATE_TIME_H__
-#include <time.h>
-#include <glib/gtypes.h>
+#include <glib/gtimezone.h>
G_BEGIN_DECLS
@@ -84,16 +89,6 @@ G_BEGIN_DECLS
typedef gint64 GTimeSpan;
/**
- * GTimeZone:
- *
- * <structname>GTimeZone</structname> is an opaque structure whose members
- * cannot be accessed directly.
- *
- * Since: 2.26
- */
-typedef struct _GTimeZone GTimeZone;
-
-/**
* GDateTime:
*
* <structname>GDateTime</structname> is an opaque structure whose members
@@ -103,109 +98,109 @@ typedef struct _GTimeZone GTimeZone;
*/
typedef struct _GDateTime GDateTime;
-GDateTime * g_date_time_new_now (void);
-GDateTime * g_date_time_new_today (void);
-GDateTime * g_date_time_new_utc_now (void);
-GDateTime * g_date_time_new_from_date (gint year,
- gint month,
- gint day);
-GDateTime * g_date_time_new_from_epoch (gint64 secs);
-GDateTime * g_date_time_new_from_timeval (GTimeVal *tv);
-GDateTime * g_date_time_new_full (gint year,
- gint month,
- gint day,
- gint hour,
- gint minute,
- gdouble second,
- const GTimeZone *time_zone);
-
-GDateTime * g_date_time_ref (GDateTime *datetime);
-void g_date_time_unref (GDateTime *datetime);
-
-GDateTime * g_date_time_add (const GDateTime *datetime,
- GTimeSpan timespan);
-GDateTime * g_date_time_add_days (const GDateTime *datetime,
- gint days);
-GDateTime * g_date_time_add_hours (const GDateTime *datetime,
- gint hours);
-GDateTime * g_date_time_add_milliseconds (const GDateTime *datetime,
- gint milliseconds);
-GDateTime * g_date_time_add_minutes (const GDateTime *datetime,
- gint minutes);
-GDateTime * g_date_time_add_months (const GDateTime *datetime,
- gint months);
-GDateTime * g_date_time_add_seconds (const GDateTime *datetime,
- gint seconds);
-GDateTime * g_date_time_add_weeks (const GDateTime *datetime,
- gint weeks);
-GDateTime * g_date_time_add_years (const GDateTime *datetime,
- gint years);
-GDateTime * g_date_time_add_full (const GDateTime *datetime,
- gint years,
- gint months,
- gint days,
- gint hours,
- gint minutes,
- gint seconds);
-
-GDateTime * g_date_time_day (const GDateTime *datetime);
-
-gint g_date_time_compare (gconstpointer dt1,
- gconstpointer dt2);
-gboolean g_date_time_equal (gconstpointer dt1,
- gconstpointer dt2);
-guint g_date_time_hash (gconstpointer datetime);
-
-GTimeSpan g_date_time_difference (const GDateTime *begin,
- const GDateTime *end);
-
-void g_date_time_get_julian (const GDateTime *datetime,
- gint *period,
- gint *julian,
- gint *hour,
- gint *minute,
- gint *second);
-gint g_date_time_get_hour (const GDateTime *datetime);
-gint g_date_time_get_minute (const GDateTime *datetime);
-gint g_date_time_get_second (const GDateTime *datetime);
-gint g_date_time_get_millisecond (const GDateTime *datetime);
-gint g_date_time_get_microsecond (const GDateTime *datetime);
-gint g_date_time_get_day_of_week (const GDateTime *datetime);
-gint g_date_time_get_day_of_month (const GDateTime *datetime);
-gint g_date_time_get_week_of_year (const GDateTime *datetime);
-gint g_date_time_get_day_of_year (const GDateTime *datetime);
-gint g_date_time_get_month (const GDateTime *datetime);
-gint g_date_time_get_year (const GDateTime *datetime);
-void g_date_time_get_dmy (const GDateTime *datetime,
- gint *day,
- gint *month,
- gint *year);
-
-GTimeSpan g_date_time_get_utc_offset (const GDateTime *datetime);
-G_CONST_RETURN gchar *g_date_time_get_timezone_name (const GDateTime *datetime);
-gboolean g_date_time_is_daylight_savings (const GDateTime *datetime);
-
-gboolean g_date_time_is_leap_year (const GDateTime *datetime);
-
-GDateTime * g_date_time_to_local (const GDateTime *datetime);
-gint64 g_date_time_to_epoch (const GDateTime *datetime);
-void g_date_time_to_timeval (const GDateTime *datetime,
- GTimeVal *tv);
-GDateTime * g_date_time_to_utc (const GDateTime *datetime);
-gchar * g_date_time_format (const GDateTime *datetime,
- const gchar *format) G_GNUC_MALLOC;
-
-GTimeZone * g_time_zone_new (gint offset,
- gboolean is_dst);
-GTimeZone * g_time_zone_new_for_name (const gchar *name);
-GTimeZone * g_time_zone_new_utc (void);
-GTimeZone * g_time_zone_new_local (void);
-GTimeZone * g_time_zone_copy (const GTimeZone *time_zone);
-void g_time_zone_free (GTimeZone *time_zone);
-G_CONST_RETURN gchar *g_time_zone_get_name (const GTimeZone *time_zone);
-gint g_time_zone_get_offset (const GTimeZone *time_zone);
-gboolean g_time_zone_get_is_dst (const GTimeZone *time_zone);
-gboolean g_time_zone_is_floating (const GTimeZone *time_zone);
+void g_date_time_unref (GDateTime *datetime);
+GDateTime * g_date_time_ref (GDateTime *datetime);
+
+GDateTime * g_date_time_new_now (GTimeZone *tz);
+GDateTime * g_date_time_new_now_local (void);
+GDateTime * g_date_time_new_now_utc (void);
+
+GDateTime * g_date_time_new_from_unix_local (gint64 t);
+GDateTime * g_date_time_new_from_unix_utc (gint64 t);
+
+GDateTime * g_date_time_new_from_timeval_local (const GTimeVal *tv);
+GDateTime * g_date_time_new_from_timeval_utc (const GTimeVal *tv);
+
+GDateTime * g_date_time_new (GTimeZone *tz,
+ gint year,
+ gint month,
+ gint day,
+ gint hour,
+ gint minute,
+ gdouble seconds);
+GDateTime * g_date_time_new_local (gint year,
+ gint month,
+ gint day,
+ gint hour,
+ gint minute,
+ gdouble seconds);
+GDateTime * g_date_time_new_utc (gint year,
+ gint month,
+ gint day,
+ gint hour,
+ gint minute,
+ gdouble seconds);
+
+GDateTime * g_date_time_add (GDateTime *datetime,
+ GTimeSpan timespan);
+
+GDateTime * g_date_time_add_years (GDateTime *datetime,
+ gint years);
+GDateTime * g_date_time_add_months (GDateTime *datetime,
+ gint months);
+GDateTime * g_date_time_add_weeks (GDateTime *datetime,
+ gint weeks);
+GDateTime * g_date_time_add_days (GDateTime *datetime,
+ gint days);
+
+GDateTime * g_date_time_add_hours (GDateTime *datetime,
+ gint hours);
+GDateTime * g_date_time_add_minutes (GDateTime *datetime,
+ gint minutes);
+GDateTime * g_date_time_add_seconds (GDateTime *datetime,
+ gdouble seconds);
+
+GDateTime * g_date_time_add_full (GDateTime *datetime,
+ gint years,
+ gint months,
+ gint days,
+ gint hours,
+ gint minutes,
+ gdouble seconds);
+
+gint g_date_time_compare (gconstpointer dt1,
+ gconstpointer dt2);
+GTimeSpan g_date_time_difference (GDateTime *begin,
+ GDateTime *end);
+guint g_date_time_hash (gconstpointer datetime);
+gboolean g_date_time_equal (gconstpointer dt1,
+ gconstpointer dt2);
+
+void g_date_time_get_ymd (GDateTime *datetime,
+ gint *year,
+ gint *month,
+ gint *day);
+
+gint g_date_time_get_year (GDateTime *datetime);
+gint g_date_time_get_month (GDateTime *datetime);
+gint g_date_time_get_day_of_month (GDateTime *datetime);
+
+gint g_date_time_get_week_of_year (GDateTime *datetime);
+gint g_date_time_get_day_of_week (GDateTime *datetime);
+
+gint g_date_time_get_day_of_year (GDateTime *datetime);
+
+gint g_date_time_get_hour (GDateTime *datetime);
+gint g_date_time_get_minute (GDateTime *datetime);
+gint g_date_time_get_second (GDateTime *datetime);
+gint g_date_time_get_microsecond (GDateTime *datetime);
+gdouble g_date_time_get_seconds (GDateTime *datetime);
+
+gint64 g_date_time_to_unix (GDateTime *datetime);
+gboolean g_date_time_to_timeval (GDateTime *datetime,
+ GTimeVal *tv);
+
+GTimeSpan g_date_time_get_utc_offset (GDateTime *datetime);
+const gchar * g_date_time_get_timezone_abbreviation (GDateTime *datetime);
+gboolean g_date_time_is_daylight_savings (GDateTime *datetime);
+
+GDateTime * g_date_time_to_timezone (GDateTime *datetime,
+ GTimeZone *tz);
+GDateTime * g_date_time_to_local (GDateTime *datetime);
+GDateTime * g_date_time_to_utc (GDateTime *datetime);
+
+gchar * g_date_time_format (GDateTime *datetime,
+ const gchar *format) G_GNUC_MALLOC;
G_END_DECLS
diff --git a/glib/glib.h b/glib/glib.h
index cec8f32..06d0190 100644
--- a/glib/glib.h
+++ b/glib/glib.h
@@ -82,6 +82,7 @@
#include <glib/gthread.h>
#include <glib/gthreadpool.h>
#include <glib/gtimer.h>
+#include <glib/gtimezone.h>
#include <glib/gtree.h>
#include <glib/gtypes.h>
#include <glib/gunicode.h>
diff --git a/glib/glib.symbols b/glib/glib.symbols
index 4f34949..f4b45a0 100644
--- a/glib/glib.symbols
+++ b/glib/glib.symbols
@@ -329,58 +329,63 @@ g_date_time_add
g_date_time_add_days
g_date_time_add_full
g_date_time_add_hours
-g_date_time_add_milliseconds
g_date_time_add_minutes
g_date_time_add_months
g_date_time_add_seconds
g_date_time_add_weeks
g_date_time_add_years
g_date_time_compare
-g_date_time_day
g_date_time_difference
g_date_time_equal
+g_date_time_format G_GNUC_MALLOC
g_date_time_get_day_of_month
g_date_time_get_day_of_week
g_date_time_get_day_of_year
-g_date_time_get_dmy
g_date_time_get_hour
-g_date_time_get_julian
g_date_time_get_microsecond
-g_date_time_get_millisecond
g_date_time_get_minute
g_date_time_get_month
g_date_time_get_second
-g_date_time_get_timezone_name
+g_date_time_get_seconds
+g_date_time_get_timezone_abbreviation
g_date_time_get_utc_offset
g_date_time_get_week_of_year
g_date_time_get_year
+g_date_time_get_ymd
g_date_time_hash
g_date_time_is_daylight_savings
-g_date_time_is_leap_year
-g_date_time_new_from_date
-g_date_time_new_from_epoch
-g_date_time_new_from_timeval
-g_date_time_new_full
+g_date_time_new
+g_date_time_new_from_timeval_local
+g_date_time_new_from_timeval_utc
+g_date_time_new_from_unix_local
+g_date_time_new_from_unix_utc
+g_date_time_new_local
g_date_time_new_now
-g_date_time_new_today
-g_date_time_new_utc_now
-g_date_time_printf G_GNUC_MALLOC
+g_date_time_new_now_local
+g_date_time_new_now_utc
+g_date_time_new_utc
g_date_time_ref
g_date_time_to_local
-g_date_time_to_epoch
g_date_time_to_timeval
+g_date_time_to_timezone
+g_date_time_to_unix
g_date_time_to_utc
g_date_time_unref
-g_time_zone_copy
-g_time_zone_free
-g_time_zone_get_is_dst
-g_time_zone_get_name
-g_time_zone_get_offset
-g_time_zone_is_floating
+#endif
+#endif
+
+#if IN_HEADER(__G_TIME_ZONE_H__)
+#if IN_FILE(__G_TIME_ZONE_C__)
g_time_zone_new
-g_time_zone_new_for_name
g_time_zone_new_local
g_time_zone_new_utc
+g_time_zone_ref
+g_time_zone_unref
+g_time_zone_adjust_time
+g_time_zone_find_interval
+g_time_zone_get_abbreviation
+g_time_zone_get_offset
+g_time_zone_is_dst
#endif
#endif
diff --git a/glib/gtimezone.c b/glib/gtimezone.c
new file mode 100644
index 0000000..ce42f50
--- /dev/null
+++ b/glib/gtimezone.c
@@ -0,0 +1,790 @@
+/*
+ * Copyright © 2010 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ */
+
+/* Prologue {{{1 */
+
+#include "gtimezone.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include "gmappedfile.h"
+#include "gtestutils.h"
+#include "gfileutils.h"
+#include "gstrfuncs.h"
+#include "ghash.h"
+#include "gthread.h"
+#include "gbuffer.h"
+
+/**
+ * SECTION:timezone
+ * @title: GTimeZone
+ * @short_description: A structure representing a time zone
+ * @see_also: #GDateTime
+ *
+ * #GTimeZone is a structure that represents a time zone, at no
+ * particular point in time. It is refcounted and immutable.
+ *
+ * A time zone contains a number of intervals. Each interval has
+ * an abbreviation to describe it, an offet to UTC and a flag indicating
+ * if the daylight savings time is in effect during that interval. A
+ * time zone always has at least one interval -- interval 0.
+ *
+ * Every UTC time is contained within exactly one interval, but a given
+ * local time may be contained within zero, one or two intervals (due to
+ * incontinuities associated with daylight savings time).
+ *
+ * An interval may refer to a specific period of time (eg: the duration
+ * of daylight savings time during 2010) or it may refer to many periods
+ * of time that share the same properties (eg: all periods of daylight
+ * savings time). It is also possible (usually for political reasons)
+ * that some properties (like the abbreviation) change between intervals
+ * without other properties changing.
+ *
+ * #GTimeZone is available since GLib 2.26.
+ */
+
+/**
+ * GTimeZone:
+ *
+ * #GDateTime is an opaque structure whose members cannot be accessed
+ * directly.
+ *
+ * Since: 2.26
+ **/
+
+/* zoneinfo file format {{{1 */
+
+/* unaligned */
+typedef struct { gchar bytes[8]; } gint64_be;
+typedef struct { gchar bytes[4]; } gint32_be;
+typedef struct { gchar bytes[4]; } guint32_be;
+
+static inline gint64 gint64_from_be (const gint64_be be) {
+ gint64 tmp; memcpy (&tmp, &be, sizeof tmp); return GINT64_FROM_BE (tmp);
+}
+
+static inline gint32 gint32_from_be (const gint32_be be) {
+ gint32 tmp; memcpy (&tmp, &be, sizeof tmp); return GINT32_FROM_BE (tmp);
+}
+
+static inline guint32 guint32_from_be (const guint32_be be) {
+ guint32 tmp; memcpy (&tmp, &be, sizeof tmp); return GUINT32_FROM_BE (tmp);
+}
+
+struct tzhead
+{
+ gchar tzh_magic[4];
+ gchar tzh_version;
+ guchar tzh_reserved[15];
+
+ guint32_be tzh_ttisgmtcnt;
+ guint32_be tzh_ttisstdcnt;
+ guint32_be tzh_leapcnt;
+ guint32_be tzh_timecnt;
+ guint32_be tzh_typecnt;
+ guint32_be tzh_charcnt;
+};
+
+struct ttinfo
+{
+ gint32_be tt_gmtoff;
+ guint8 tt_isdst;
+ guint8 tt_abbrind;
+};
+
+/* GTimeZone structure and lifecycle {{{1 */
+struct _GTimeZone
+{
+ gchar *name;
+
+ GBuffer *zoneinfo;
+
+ const struct tzhead *header;
+ const struct ttinfo *infos;
+ const gint64_be *trans;
+ const guint8 *indices;
+ const gchar *abbrs;
+ gint timecnt;
+
+ gint ref_count;
+};
+
+G_LOCK_DEFINE_STATIC (time_zones);
+static GHashTable/*<string?, GTimeZone>*/ *time_zones;
+
+static guint
+g_str_hash0 (gconstpointer data)
+{
+ return data ? g_str_hash (data) : 0;
+}
+
+static gboolean
+g_str_equal0 (gconstpointer a,
+ gconstpointer b)
+{
+ if (a == b)
+ return TRUE;
+
+ if (!a || !b)
+ return FALSE;
+
+ return g_str_equal (a, b);
+}
+
+/**
+ * g_time_zone_unref:
+ * @tz: a #GTimeZone
+ *
+ * Decreases the reference count on @tz.
+ *
+ * Since: 2.26
+ **/
+void
+g_time_zone_unref (GTimeZone *tz)
+{
+ g_assert (tz->ref_count > 0);
+
+ if (g_atomic_int_dec_and_test (&tz->ref_count))
+ {
+ G_LOCK(time_zones);
+ g_hash_table_remove (time_zones, tz->name);
+ G_UNLOCK(time_zones);
+
+ if (tz->zoneinfo)
+ g_buffer_unref (tz->zoneinfo);
+
+ g_free (tz->name);
+
+ g_slice_free (GTimeZone, tz);
+ }
+}
+
+/**
+ * g_time_zone_ref:
+ * @tz: a #GTimeZone
+ *
+ * Increases the reference count on @tz.
+ *
+ * Returns: a new reference to @tz.
+ *
+ * Since: 2.26
+ **/
+GTimeZone *
+g_time_zone_ref (GTimeZone *tz)
+{
+ g_assert (tz->ref_count > 0);
+
+ g_atomic_int_inc (&tz->ref_count);
+
+ return tz;
+}
+
+/* fake zoneinfo creation (for RFC3339/ISO 8601 timezones) {{{1 */
+/*
+ * parses strings of the form 'hh' 'hhmm' or 'hh:mm' where:
+ * - hh is 00 to 23
+ * - mm is 00 to 59
+ */
+gboolean
+parse_time (const gchar *time,
+ gint32 *offset)
+{
+ if (*time < '0' || '2' < *time)
+ return FALSE;
+
+ *offset = 10 * 60 * 60 * (*time++ - '0');
+
+ if (*time < '0' || '9' < *time)
+ return FALSE;
+
+ *offset += 60 * 60 * (*time++ - '0');
+
+ if (*offset > 23 * 60 * 60)
+ return FALSE;
+
+ if (*time == '\0')
+ return TRUE;
+
+ if (*time == ':')
+ time++;
+
+ if (*time < '0' || '5' < *time)
+ return FALSE;
+
+ *offset += 10 * 60 * (*time++ - '0');
+
+ if (*time < '0' || '9' < *time)
+ return FALSE;
+
+ *offset += 60 * (*time++ - '0');
+
+ return *time == '\0';
+}
+
+gboolean
+parse_constant_offset (const gchar *name,
+ gint32 *offset)
+{
+ switch (*name++)
+ {
+ case 'Z':
+ *offset = 0;
+ return !*name;
+
+ case '+':
+ return parse_time (name, offset);
+
+ case '-':
+ if (parse_time (name, offset))
+ {
+ *offset = -*offset;
+ return TRUE;
+ }
+
+ default:
+ return FALSE;
+ }
+}
+
+static GBuffer *
+zone_for_constant_offset (const gchar *name)
+{
+ const gchar fake_zoneinfo_headers[] =
+ "TZif" "2..." "...." "...." "...."
+ "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0"
+ "TZif" "2..." "...." "...." "...."
+ "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\1" "\0\0\0\7";
+ struct {
+ struct tzhead headers[2];
+ struct ttinfo info;
+ gchar abbr[8];
+ } *fake;
+ gint32 offset;
+
+ if (name == NULL || !parse_constant_offset (name, &offset))
+ return NULL;
+
+ offset = GINT32_TO_BE (offset);
+
+ fake = g_malloc (sizeof *fake);
+ memcpy (fake, fake_zoneinfo_headers, sizeof fake_zoneinfo_headers);
+ memcpy (&fake->info.tt_gmtoff, &offset, sizeof offset);
+ fake->info.tt_isdst = FALSE;
+ fake->info.tt_abbrind = 0;
+ strcpy (fake->abbr, name);
+
+ return g_buffer_new_take_data (fake, sizeof *fake);
+}
+
+/* Construction {{{1 */
+/**
+ * g_time_zone_new:
+ * @identifier: (allow-none): a timezone identifier
+ *
+ * Creates a #GTimeZone corresponding to @identifier.
+ *
+ * @identifier can either be an RFC3339/ISO 8601 time offset or
+ * something that would pass as a valid value for the
+ * <varname>TZ</varname> environment variable (including %NULL).
+ *
+ * Valid RFC3339 time offsets are <literal>"Z"</literal> (for UTC) or
+ * <literal>"±hh:mm"</literal>. ISO 8601 additionally specifies
+ * <literal>"±hhmm"</literal> and <literal>"±hh"</literal>.
+ *
+ * The <varname>TZ</varname> environment variable typically corresponds
+ * to the name of a file in the zoneinfo database, but there are many
+ * other possibilities. Note that those other possibilities are not
+ * currently implemented, but are planned.
+ *
+ * g_time_zone_new_local() calls this function with the value of the
+ * <varname>TZ</varname> environment variable. This function itself is
+ * independent of the value of <varname>TZ</varname>, but if @identifier
+ * is %NULL then <filename>/etc/localtime</filename> will be consulted
+ * to discover the correct timezone.
+ *
+ * See <ulink
+ * url='http://tools.ietf.org/html/rfc3339#section-5.6'>RFC3339
+ * §5.6</ulink> for a precise definition of valid RFC3339 time offsets
+ * (the <varname>time-offset</varname> expansion) and ISO 8601 for the
+ * full list of valid time offsets. See <ulink
+ * url='http://www.gnu.org/s/libc/manual/html_node/TZ-Variable.html'>The
+ * GNU C Library manual</ulink> for an explanation of the possible
+ * values of the <varname>TZ</varname> environment variable.
+ *
+ * You should release the return value by calling g_time_zone_unref()
+ * when you are done with it.
+ *
+ * Returns: the requested timezone
+ *
+ * Since: 2.26
+ **/
+GTimeZone *
+g_time_zone_new (const gchar *identifier)
+{
+ GTimeZone *tz;
+
+ G_LOCK (time_zones);
+ if (time_zones == NULL)
+ time_zones = g_hash_table_new (g_str_hash0,
+ g_str_equal0);
+
+ tz = g_hash_table_lookup (time_zones, identifier);
+ if (tz == NULL)
+ {
+ tz = g_slice_new0 (GTimeZone);
+ tz->name = g_strdup (identifier);
+ tz->ref_count = 0;
+
+ tz->zoneinfo = zone_for_constant_offset (identifier);
+
+ if (tz->zoneinfo == NULL)
+ {
+ gchar *filename;
+
+ if (identifier != NULL)
+ {
+ const gchar *tzdir;
+
+ tzdir = getenv ("TZDIR");
+ if (tzdir == NULL)
+ tzdir = "/usr/share/zoneinfo";
+
+ filename = g_build_filename (tzdir, identifier, NULL);
+ }
+ else
+ filename = g_strdup ("/etc/localtime");
+
+ tz->zoneinfo = (GBuffer *) g_mapped_file_new (filename, FALSE, NULL);
+ g_free (filename);
+ }
+
+ if (tz->zoneinfo != NULL)
+ {
+ const struct tzhead *header = tz->zoneinfo->data;
+ gsize size = tz->zoneinfo->size;
+
+ /* we only bother to support version 2 */
+ if (size < sizeof (struct tzhead) || memcmp (header, "TZif2", 5))
+ {
+ g_buffer_unref (tz->zoneinfo);
+ tz->zoneinfo = NULL;
+ }
+ else
+ {
+ gint typecnt;
+
+ /* we trust the file completely. */
+ tz->header = (const struct tzhead *)
+ (((const gchar *) (header + 1)) +
+ guint32_from_be(header->tzh_ttisgmtcnt) +
+ guint32_from_be(header->tzh_ttisstdcnt) +
+ 8 * guint32_from_be(header->tzh_leapcnt) +
+ 5 * guint32_from_be(header->tzh_timecnt) +
+ 6 * guint32_from_be(header->tzh_typecnt) +
+ guint32_from_be(header->tzh_charcnt));
+
+ typecnt = guint32_from_be (tz->header->tzh_typecnt);
+ tz->timecnt = guint32_from_be (tz->header->tzh_timecnt);
+ tz->trans = (gconstpointer) (tz->header + 1);
+ tz->indices = (gconstpointer) (tz->trans + tz->timecnt);
+ tz->infos = (gconstpointer) (tz->indices + tz->timecnt);
+ tz->abbrs = (gconstpointer) (tz->infos + typecnt);
+ }
+ }
+
+ g_hash_table_insert (time_zones, tz->name, tz);
+ }
+ g_atomic_int_inc (&tz->ref_count);
+ G_UNLOCK (time_zones);
+
+ return tz;
+}
+
+/**
+ * g_time_zone_new_utc:
+ *
+ * Creates a #GTimeZone corresponding to UTC.
+ *
+ * This is equivalent to calling g_time_zone_new() with a value like
+ * "Z", "UTC", "+00", etc.
+ *
+ * You should release the return value by calling g_time_zone_unref()
+ * when you are done with it.
+ *
+ * Returns: the universal timezone
+ *
+ * Since: 2.26
+ **/
+GTimeZone *
+g_time_zone_new_utc (void)
+{
+ return g_time_zone_new ("UTC");
+}
+
+/**
+ * g_time_zone_new_local:
+ *
+ * Creates a #GTimeZone corresponding to local time.
+ *
+ * This is equivalent to calling g_time_zone_new() with the value of the
+ * <varname>TZ</varname> environment variable (including the possibility
+ * of %NULL). Changes made to <varname>TZ</varname> after the first
+ * call to this function may or may not be noticed by future calls.
+ *
+ * You should release the return value by calling g_time_zone_unref()
+ * when you are done with it.
+ *
+ * Returns: the local timezone
+ *
+ * Since: 2.26
+ **/
+GTimeZone *
+g_time_zone_new_local (void)
+{
+ return g_time_zone_new (getenv ("TZ"));
+}
+
+/* Internal helpers {{{1 */
+inline static const struct ttinfo *
+interval_info (GTimeZone *tz,
+ gint interval)
+{
+ if (interval)
+ return tz->infos + tz->indices[interval - 1];
+
+ return tz->infos;
+}
+
+inline static gint64
+interval_start (GTimeZone *tz,
+ gint interval)
+{
+ if (interval)
+ return gint64_from_be (tz->trans[interval - 1]);
+
+ return G_MININT64;
+}
+
+inline static gint64
+interval_end (GTimeZone *tz,
+ gint interval)
+{
+ if (interval < tz->timecnt)
+ return gint64_from_be (tz->trans[interval]) - 1;
+
+ return G_MAXINT64;
+}
+
+inline static gint32
+interval_offset (GTimeZone *tz,
+ gint interval)
+{
+ return gint32_from_be (interval_info (tz, interval)->tt_gmtoff);
+}
+
+inline static gboolean
+interval_isdst (GTimeZone *tz,
+ gint interval)
+{
+ return interval_info (tz, interval)->tt_isdst;
+}
+
+inline static guint8
+interval_abbrind (GTimeZone *tz,
+ gint interval)
+{
+ return interval_info (tz, interval)->tt_abbrind;
+}
+
+inline static gint64
+interval_local_start (GTimeZone *tz,
+ gint interval)
+{
+ if (interval)
+ return interval_start (tz, interval) + interval_offset (tz, interval);
+
+ return G_MININT64;
+}
+
+inline static gint64
+interval_local_end (GTimeZone *tz,
+ gint interval)
+{
+ if (interval < tz->timecnt)
+ return interval_end (tz, interval) + interval_offset (tz, interval);
+
+ return G_MAXINT64;
+}
+
+static gboolean
+interval_valid (GTimeZone *tz,
+ gint interval)
+{
+ return interval <= tz->timecnt;
+}
+
+/* g_time_zone_find_interval() {{{1 */
+
+/**
+ * g_time_zone_adjust_time:
+ * @tz: a #GTimeZone
+ * @type: the #GTimeType of @time
+ * @time: a pointer to a number of seconds since January 1, 1970
+ *
+ * Finds an interval within @tz that corresponds to the given @time,
+ * possibly adjusting @time if required to fit into an interval.
+ * The meaning of @time depends on @type.
+ *
+ * This function is similar to g_time_zone_find_interval(), with the
+ * difference that it always succeeds (by making the adjustments
+ * described below).
+ *
+ * In any of the cases where g_time_zone_find_interval() succeeds then
+ * this function returns the same value, without modifying @time.
+ *
+ * This function may, however, modify @time in order to deal with
+ * non-existent times. If the non-existent local @time of 02:30 were
+ * requested on March 13th 2010 in Toronto then this function would
+ * adjust @time to be 03:00 and return the interval containing the
+ * adjusted time.
+ *
+ * Returns: the interval containing @time, never -1
+ *
+ * Since: 2.26
+ **/
+gint
+g_time_zone_adjust_time (GTimeZone *tz,
+ GTimeType type,
+ gint64 *time)
+{
+ gint i;
+
+ if (tz->zoneinfo == NULL)
+ return 0;
+
+ /* find the interval containing *time UTC
+ * TODO: this could be binary searched (or better) */
+ for (i = 0; i < tz->timecnt; i++)
+ if (*time <= interval_end (tz, i))
+ break;
+
+ g_assert (interval_start (tz, i) <= *time && *time <= interval_end (tz, i));
+
+ if (type != G_TIME_TYPE_UNIVERSAL)
+ {
+ if (*time < interval_local_start (tz, i))
+ /* if time came before the start of this interval... */
+ {
+ i--;
+
+ /* if it's not in the previous interval... */
+ if (*time > interval_local_end (tz, i))
+ {
+ /* it doesn't exist. fast-forward it. */
+ i++;
+ *time = interval_local_start (tz, i);
+ }
+ }
+
+ else if (*time > interval_local_end (tz, i))
+ /* if time came after the end of this interval... */
+ {
+ i++;
+
+ /* if it's not in the next interval... */
+ if (*time < interval_local_start (tz, i))
+ /* it doesn't exist. fast-forward it. */
+ *time = interval_local_start (tz, i);
+ }
+
+ else if (interval_isdst (tz, i) != type)
+ /* it's in this interval, but dst flag doesn't match.
+ * check neighbours for a better fit. */
+ {
+ if (i && *time <= interval_local_end (tz, i - 1))
+ i--;
+
+ else if (i < tz->timecnt &&
+ *time >= interval_local_start (tz, i + 1))
+ i++;
+ }
+ }
+
+ return i;
+}
+
+/**
+ * g_time_zone_find_interval:
+ * @tz: a #GTimeZone
+ * @type: the #GTimeType of @time
+ * @time: a number of seconds since January 1, 1970
+ *
+ * Finds an the interval within @tz that corresponds to the given @time.
+ * The meaning of @time depends on @type.
+ *
+ * If @type is %G_TIME_TYPE_UNIVERSAL then this function will always
+ * succeed (since universal time is monotonic and continuous).
+ *
+ * Otherwise @time is treated is local time. The distinction between
+ * %G_TIME_TYPE_STANDARD and %G_TIME_TYPE_DAYLIGHT is ignored except in
+ * the case that the given @time is ambiguous. In Toronto, for example,
+ * 01:30 on November 7th 2010 occured twice (once inside of daylight
+ * savings time and the next, an hour later, outside of daylight savings
+ * time). In this case, the different value of @type would result in a
+ * different interval being returned.
+ *
+ * It is still possible for this function to fail. In Toronto, for
+ * example, 02:00 on March 14th 2010 does not exist (due to the leap
+ * forward to begin daylight savings time). -1 is returned in that
+ * case.
+ *
+ * Returns: the interval containing @time, or -1 in case of failure
+ *
+ * Since: 2.26
+ */
+gint
+g_time_zone_find_interval (GTimeZone *tz,
+ GTimeType type,
+ gint64 time)
+{
+ gint i;
+
+ if (tz->zoneinfo == NULL)
+ return 0;
+
+ for (i = 0; i < tz->timecnt; i++)
+ if (time <= interval_end (tz, i))
+ break;
+
+ if (type == G_TIME_TYPE_UNIVERSAL)
+ return i;
+
+ if (time < interval_local_start (tz, i))
+ {
+ if (time > interval_local_end (tz, --i))
+ return -1;
+ }
+
+ else if (time > interval_local_end (tz, i))
+ {
+ if (time < interval_local_start (tz, ++i))
+ return -1;
+ }
+
+ else if (interval_isdst (tz, i) != type)
+ {
+ if (i && time <= interval_local_end (tz, i - 1))
+ i--;
+
+ else if (i < tz->timecnt && time >= interval_local_start (tz, i + 1))
+ i++;
+ }
+
+ return i;
+}
+
+/* Public API accessors {{{1 */
+
+/**
+ * g_time_zone_get_abbreviation:
+ * @tz: a #GTimeZone
+ * @interval: an interval within the timezone
+ *
+ * Determines the time zone abbreviation to be used during a particular
+ * @interval of time in the time zone @tz.
+ *
+ * For example, in Toronto this is currently "EST" during the winter
+ * months and "EDT" during the summer months when daylight savings time
+ * is in effect.
+ *
+ * Returns: the time zone abbreviation, which belongs to @tz
+ *
+ * Since: 2.26
+ **/
+const gchar *
+g_time_zone_get_abbreviation (GTimeZone *tz,
+ gint interval)
+{
+ g_return_val_if_fail (interval_valid (tz, interval), NULL);
+
+ if (tz->header == NULL)
+ return "UTC";
+
+ return tz->abbrs + interval_abbrind (tz, interval);
+}
+
+/**
+ * g_time_zone_get_offset:
+ * @tz: a #GTimeZone
+ * @interval: an interval within the timezone
+ *
+ * Determines the offset to UTC in effect during a particular @interval
+ * of time in the time zone @tz.
+ *
+ * The offset is the number of seconds that you add to UTC time to
+ * arrive at local time for @tz (ie: negative numbers for time zones
+ * west of GMT, positive numbers for east).
+ *
+ * Returns: the number of seconds that should be added to UTC to get the
+ * local time in @tz
+ *
+ * Since: 2.26
+ **/
+gint32
+g_time_zone_get_offset (GTimeZone *tz,
+ gint interval)
+{
+ g_return_val_if_fail (interval_valid (tz, interval), 0);
+
+ if (tz->header == NULL)
+ return 0;
+
+ return interval_offset (tz, interval);
+}
+
+/**
+ * g_time_zone_is_dst:
+ * @tz: a #GTimeZone
+ * @interval: an interval within the timezone
+ *
+ * Determines if daylight savings time is in effect during a particular
+ * @interval of time in the time zone @tz.
+ *
+ * Returns: %TRUE if daylight savings time is in effect
+ *
+ * Since: 2.26
+ **/
+gboolean
+g_time_zone_is_dst (GTimeZone *tz,
+ gint interval)
+{
+ g_return_val_if_fail (interval_valid (tz, interval), FALSE);
+
+ if (tz->header == NULL)
+ return FALSE;
+
+ return interval_isdst (tz, interval);
+}
+
+/* Epilogue {{{1 */
+/* vim:set foldmethod=marker: */
diff --git a/glib/gtimezone.h b/glib/gtimezone.h
new file mode 100644
index 0000000..8bc6684
--- /dev/null
+++ b/glib/gtimezone.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright © 2010 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_TIME_ZONE_H__
+#define __G_TIME_ZONE_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GTimeZone GTimeZone;
+
+/**
+ * GTimeType:
+ * @G_TIME_TYPE_STANDARD: the time is in local standard time
+ * @G_TIME_TYPE_DAYLIGHT: the time is in local daylight time
+ * @G_TIME_TYPE_UNIVERSAL: the time is in UTC
+ *
+ * Disambiguates a given time in two ways.
+ *
+ * First, specifies if the given time is in universal or local time.
+ *
+ * Second, if the time is in local time, specifies if it is local
+ * standard time or local daylight time. This is important for the case
+ * where the same local time occurs twice (during daylight savings time
+ * transitions, for example).
+ */
+typedef enum
+{
+ G_TIME_TYPE_STANDARD,
+ G_TIME_TYPE_DAYLIGHT,
+ G_TIME_TYPE_UNIVERSAL
+} GTimeType;
+
+GTimeZone * g_time_zone_new (const gchar *identifier);
+GTimeZone * g_time_zone_new_utc (void);
+GTimeZone * g_time_zone_new_local (void);
+
+GTimeZone * g_time_zone_ref (GTimeZone *tz);
+void g_time_zone_unref (GTimeZone *tz);
+
+gint g_time_zone_find_interval (GTimeZone *tz,
+ GTimeType type,
+ gint64 time);
+
+gint g_time_zone_adjust_time (GTimeZone *tz,
+ GTimeType type,
+ gint64 *time);
+
+const gchar * g_time_zone_get_abbreviation (GTimeZone *tz,
+ gint interval);
+gint32 g_time_zone_get_offset (GTimeZone *tz,
+ gint interval);
+gboolean g_time_zone_is_dst (GTimeZone *tz,
+ gint interval);
+
+G_END_DECLS
+
+#endif /* __G_TIME_ZONE_H__ */
diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c
index a51afb0..846fbc8 100644
--- a/glib/tests/gdatetime.c
+++ b/glib/tests/gdatetime.c
@@ -73,7 +73,7 @@ test_GDateTime_now (void)
memset (&tm, 0, sizeof (tm));
get_localtime_tm (time (NULL), &tm);
- dt = g_date_time_new_now ();
+ dt = g_date_time_new_now_local ();
g_assert_cmpint (g_date_time_get_year (dt), ==, 1900 + tm.tm_year);
g_assert_cmpint (g_date_time_get_month (dt), ==, 1 + tm.tm_mon);
@@ -87,27 +87,7 @@ test_GDateTime_now (void)
}
static void
-test_GDateTime_today (void)
-{
- GDateTime *dt;
- struct tm tm;
-
- memset (&tm, 0, sizeof (tm));
- get_localtime_tm (time (NULL), &tm);
-
- dt = g_date_time_new_today ();
- g_assert_cmpint (g_date_time_get_year (dt), ==, 1900 + tm.tm_year);
- g_assert_cmpint (g_date_time_get_month (dt), ==, 1 + tm.tm_mon);
- g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, tm.tm_mday);
- g_assert_cmpint (g_date_time_get_hour (dt), ==, 0);
- g_assert_cmpint (g_date_time_get_minute (dt), ==, 0);
- g_assert_cmpint (g_date_time_get_second (dt), ==, 0);
- g_assert_cmpint (g_date_time_get_millisecond (dt), ==, 0);
- g_date_time_unref (dt);
-}
-
-static void
-test_GDateTime_new_from_epoch (void)
+test_GDateTime_new_from_unix (void)
{
GDateTime *dt;
struct tm tm;
@@ -117,7 +97,7 @@ test_GDateTime_new_from_epoch (void)
t = time (NULL);
get_localtime_tm (t, &tm);
- dt = g_date_time_new_from_epoch (t);
+ dt = g_date_time_new_from_unix_local (t);
g_assert_cmpint (g_date_time_get_year (dt), ==, 1900 + tm.tm_year);
g_assert_cmpint (g_date_time_get_month (dt), ==, 1 + tm.tm_mon);
g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, tm.tm_mday);
@@ -135,7 +115,7 @@ test_GDateTime_new_from_epoch (void)
tm.tm_sec = 0;
t = mktime (&tm);
- dt = g_date_time_new_from_epoch (t);
+ dt = g_date_time_new_from_unix_local (t);
g_assert_cmpint (g_date_time_get_year (dt), ==, 1970);
g_assert_cmpint (g_date_time_get_month (dt), ==, 1);
g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, 1);
@@ -146,108 +126,72 @@ test_GDateTime_new_from_epoch (void)
}
static void
-test_GDateTime_is_leap_year (void)
-{
- GDateTime *dt;
- gint i;
-
- for (i = 1; i <= 3000; i++)
- {
- dt = g_date_time_new_from_date (i, 1, 1);
- if ((((i % 4) == 0) && ((i % 100) != 0)) || ((i % 400) == 0))
- g_assert (g_date_time_is_leap_year (dt));
- else
- g_assert (!g_date_time_is_leap_year (dt));
- g_date_time_unref (dt);
- }
-}
-
-static void
test_GDateTime_compare (void)
{
GDateTime *dt1, *dt2;
gint i;
- dt1 = g_date_time_new_from_date (2000, 1, 1);
+ dt1 = g_date_time_new_utc (2000, 1, 1, 0, 0, 0);
for (i = 1; i < 2000; i++)
{
- dt2 = g_date_time_new_from_date (i, 12, 31);
+ dt2 = g_date_time_new_utc (i, 12, 31, 0, 0, 0);
g_assert_cmpint (1, ==, g_date_time_compare (dt1, dt2));
g_date_time_unref (dt2);
}
- dt2 = g_date_time_new_full (1999, 12, 31, 23, 59, 59, NULL);
+ dt2 = g_date_time_new_utc (1999, 12, 31, 23, 59, 59);
g_assert_cmpint (1, ==, g_date_time_compare (dt1, dt2));
g_date_time_unref (dt2);
- dt2 = g_date_time_new_full (2000, 1, 1, 0, 0, 1, NULL);
+ dt2 = g_date_time_new_utc (2000, 1, 1, 0, 0, 1);
g_assert_cmpint (-1, ==, g_date_time_compare (dt1, dt2));
g_date_time_unref (dt2);
- dt2 = g_date_time_new_full (2000, 1, 1, 0, 0, 0, NULL);
+ dt2 = g_date_time_new_utc (2000, 1, 1, 0, 0, 0);
g_assert_cmpint (0, ==, g_date_time_compare (dt1, dt2));
g_date_time_unref (dt2);
g_date_time_unref (dt1);
}
static void
-test_GDateTime_date (void)
-{
- GDateTime *dt1, *dt2;
-
- dt1 = g_date_time_new_full (2009, 10, 19, 13, 0, 55, NULL);
- dt2 = g_date_time_day (dt1);
- g_assert (dt1 != NULL);
- g_assert (dt2 != NULL);
- g_assert_cmpint (2009, ==, g_date_time_get_year (dt2));
- g_assert_cmpint (10, ==, g_date_time_get_month (dt2));
- g_assert_cmpint (19, ==, g_date_time_get_day_of_month (dt2));
- g_assert_cmpint (0, ==, g_date_time_get_hour (dt2));
- g_assert_cmpint (0, ==, g_date_time_get_minute (dt2));
- g_assert_cmpint (0, ==, g_date_time_get_second (dt2));
- g_date_time_unref (dt1);
- g_date_time_unref (dt2);
-}
-
-static void
test_GDateTime_equal (void)
{
GDateTime *dt1, *dt2;
- GTimeZone *time_zone;
+ GTimeZone *tz;
- dt1 = g_date_time_new_from_date (2009, 10, 19);
- dt2 = g_date_time_new_from_date (2009, 10, 19);
+ dt1 = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
+ dt2 = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
g_assert (g_date_time_equal (dt1, dt2));
g_date_time_unref (dt1);
g_date_time_unref (dt2);
- dt1 = g_date_time_new_from_date (2009, 10, 18);
- dt2 = g_date_time_new_from_date (2009, 10, 19);
+ dt1 = g_date_time_new_local (2009, 10, 18, 0, 0, 0);
+ dt2 = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
g_assert (!g_date_time_equal (dt1, dt2));
g_date_time_unref (dt1);
g_date_time_unref (dt2);
/* UTC-0300 and not in DST */
- time_zone = g_time_zone_new (-3 * 3600, FALSE);
- dt1 = g_date_time_new_full (2010, 5, 24, 8, 0, 0, time_zone);
+ tz = g_time_zone_new ("-03:00");
+ dt1 = g_date_time_new (tz, 2010, 5, 24, 8, 0, 0);
+ g_time_zone_unref (tz);
g_assert_cmpint (g_date_time_get_utc_offset (dt1) / G_USEC_PER_SEC, ==, (-3 * 3600));
/* UTC */
- dt2 = g_date_time_new_full (2010, 5, 24, 11, 0, 0, NULL);
+ dt2 = g_date_time_new_utc (2010, 5, 24, 11, 0, 0);
g_assert_cmpint (g_date_time_get_utc_offset (dt2), ==, 0);
g_assert (g_date_time_equal (dt1, dt2));
g_date_time_unref (dt1);
- g_time_zone_free (time_zone);
/* America/Recife is in UTC-0300 */
- time_zone = g_time_zone_new_for_name ("America/Recife");
- dt1 = g_date_time_new_full (2010, 5, 24, 8, 0, 0, time_zone);
+ tz = g_time_zone_new ("America/Recife");
+ dt1 = g_date_time_new (tz, 2010, 5, 24, 8, 0, 0);
+ g_time_zone_unref (tz);
g_assert_cmpint (g_date_time_get_utc_offset (dt1) / G_USEC_PER_SEC, ==, (-3 * 3600));
g_assert (g_date_time_equal (dt1, dt2));
g_date_time_unref (dt1);
g_date_time_unref (dt2);
- g_time_zone_free (time_zone);
}
static void
@@ -255,11 +199,11 @@ test_GDateTime_get_day_of_week (void)
{
GDateTime *dt;
- dt = g_date_time_new_from_date (2009, 10, 19);
+ dt = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
g_assert_cmpint (1, ==, g_date_time_get_day_of_week (dt));
g_date_time_unref (dt);
- dt = g_date_time_new_from_date (2000, 10, 1);
+ dt = g_date_time_new_local (2000, 10, 1, 0, 0, 0);
g_assert_cmpint (7, ==, g_date_time_get_day_of_week (dt));
g_date_time_unref (dt);
}
@@ -269,25 +213,25 @@ test_GDateTime_get_day_of_month (void)
{
GDateTime *dt;
- dt = g_date_time_new_from_date (2009, 10, 19);
+ dt = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, 19);
g_date_time_unref (dt);
- dt = g_date_time_new_from_date (1400, 3, 12);
+ dt = g_date_time_new_local (1400, 3, 12, 0, 0, 0);
g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, 12);
g_date_time_unref (dt);
- dt = g_date_time_new_from_date (1800, 12, 31);
+ dt = g_date_time_new_local (1800, 12, 31, 0, 0, 0);
g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, 31);
g_date_time_unref (dt);
- dt = g_date_time_new_from_date (1000, 1, 1);
+ dt = g_date_time_new_local (1000, 1, 1, 0, 0, 0);
g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, 1);
g_date_time_unref (dt);
}
static void
-test_GDateTime_get_dmy (void)
+test_GDateTime_get_ymd (void)
{
GDateTime *dt;
struct tm tm;
@@ -301,8 +245,8 @@ test_GDateTime_get_dmy (void)
memset (&tm, 0, sizeof (struct tm));
get_localtime_tm (t, &tm);
- dt = g_date_time_new_from_epoch (t);
- g_date_time_get_dmy(dt, &d, &m, &y);
+ dt = g_date_time_new_from_unix_utc (t);
+ g_date_time_get_ymd(dt, &y, &m, &d);
g_assert_cmpint(y, ==, tm.tm_year + 1900);
g_assert_cmpint(m, ==, tm.tm_mon + 1);
g_assert_cmpint(d, ==, tm.tm_mday);
@@ -318,9 +262,9 @@ test_GDateTime_get_dmy (void)
{
for (d = 1; d <= days[leap][m]; d++)
{
- GDateTime *dt1 = g_date_time_new_from_date (y, m, d);
+ GDateTime *dt1 = g_date_time_new_utc (y, m, d, 0, 0, 0);
- g_date_time_get_dmy (dt1, &d2, &m2, &y2);
+ g_date_time_get_ymd (dt1, &y2, &m2, &d2);
g_assert_cmpint (y, ==, y2);
g_assert_cmpint (m, ==, m2);
g_assert_cmpint (d, ==, d2);
@@ -335,86 +279,53 @@ test_GDateTime_get_hour (void)
{
GDateTime *dt;
- dt = g_date_time_new_full (2009, 10, 19, 15, 13, 11, NULL);
+ dt = g_date_time_new_utc (2009, 10, 19, 15, 13, 11);
g_assert_cmpint (15, ==, g_date_time_get_hour (dt));
g_date_time_unref (dt);
- dt = g_date_time_new_full (100, 10, 19, 1, 0, 0, NULL);
+ dt = g_date_time_new_utc (100, 10, 19, 1, 0, 0);
g_assert_cmpint (1, ==, g_date_time_get_hour (dt));
g_date_time_unref (dt);
- dt = g_date_time_new_full (100, 10, 19, 0, 0, 0, NULL);
+ dt = g_date_time_new_utc (100, 10, 19, 0, 0, 0);
g_assert_cmpint (0, ==, g_date_time_get_hour (dt));
g_date_time_unref (dt);
- dt = g_date_time_new_full (100, 10, 1, 23, 59, 59, NULL);
+ dt = g_date_time_new_utc (100, 10, 1, 23, 59, 59);
g_assert_cmpint (23, ==, g_date_time_get_hour (dt));
g_date_time_unref (dt);
}
static void
-test_GDateTime_get_julian (void)
-{
- GDateTime *dt;
- gint period, julian, hour = 1, min = 1, sec = 1;
-
- dt = g_date_time_new_from_date (1984, 8, 16);
- g_date_time_get_julian (dt, &period, &julian, &hour, &min, &sec);
- g_assert_cmpint (period, ==, 0);
- g_assert_cmpint (julian, ==, 2445929);
- g_assert_cmpint (hour, ==, 0);
- g_assert_cmpint (min, ==, 0);
- g_assert_cmpint (sec, ==, 0);
- g_date_time_unref (dt);
-}
-
-static void
test_GDateTime_get_microsecond (void)
{
GTimeVal tv;
GDateTime *dt;
g_get_current_time (&tv);
- dt = g_date_time_new_from_timeval (&tv);
+ dt = g_date_time_new_from_timeval_local (&tv);
g_assert_cmpint (tv.tv_usec, ==, g_date_time_get_microsecond (dt));
g_date_time_unref (dt);
}
static void
-test_GDateTime_get_millisecond (void)
-{
- GTimeVal tv;
- GDateTime *dt;
-
- g_get_current_time (&tv);
- dt = g_date_time_new_from_timeval (&tv);
- g_assert_cmpint ((tv.tv_usec / 1000), ==, g_date_time_get_millisecond (dt));
- g_date_time_unref (dt);
-
- dt = g_date_time_new_full (2010, 9, 15, 12, 0, 0.1234, NULL);
- g_assert_cmpint (123, ==, g_date_time_get_millisecond (dt));
- g_assert_cmpint (123400, ==, g_date_time_get_microsecond (dt));
- g_date_time_unref (dt);
-}
-
-static void
test_GDateTime_get_year (void)
{
GDateTime *dt;
- dt = g_date_time_new_from_date (2009, 1, 1);
+ dt = g_date_time_new_local (2009, 1, 1, 0, 0, 0);
g_assert_cmpint (2009, ==, g_date_time_get_year (dt));
g_date_time_unref (dt);
- dt = g_date_time_new_from_date (1, 1, 1);
+ dt = g_date_time_new_local (1, 1, 1, 0, 0, 0);
g_assert_cmpint (1, ==, g_date_time_get_year (dt));
g_date_time_unref (dt);
- dt = g_date_time_new_from_date (13, 1, 1);
+ dt = g_date_time_new_local (13, 1, 1, 0, 0, 0);
g_assert_cmpint (13, ==, g_date_time_get_year (dt));
g_date_time_unref (dt);
- dt = g_date_time_new_from_date (3000, 1, 1);
+ dt = g_date_time_new_local (3000, 1, 1, 0, 0, 0);
g_assert_cmpint (3000, ==, g_date_time_get_year (dt));
g_date_time_unref (dt);
}
@@ -427,7 +338,7 @@ test_GDateTime_hash (void)
h = g_hash_table_new_full (g_date_time_hash, g_date_time_equal,
(GDestroyNotify)g_date_time_unref,
NULL);
- g_hash_table_insert (h, g_date_time_new_now (), NULL);
+ g_hash_table_insert (h, g_date_time_new_now_local (), NULL);
g_hash_table_remove_all (h);
g_hash_table_destroy (h);
}
@@ -439,7 +350,7 @@ test_GDateTime_new_from_timeval (void)
GTimeVal tv, tv2;
g_get_current_time (&tv);
- dt = g_date_time_new_from_timeval (&tv);
+ dt = g_date_time_new_from_timeval_local (&tv);
if (g_test_verbose ())
g_print ("\nDT%04d-%02d-%02dT%02d:%02d:%02d%s\n",
@@ -449,7 +360,7 @@ test_GDateTime_new_from_timeval (void)
g_date_time_get_hour (dt),
g_date_time_get_minute (dt),
g_date_time_get_second (dt),
- g_date_time_get_timezone_name (dt));
+ g_date_time_get_timezone_abbreviation (dt));
g_date_time_to_timeval (dt, &tv2);
g_assert_cmpint (tv.tv_sec, ==, tv2.tv_sec);
@@ -458,14 +369,14 @@ test_GDateTime_new_from_timeval (void)
}
static void
-test_GDateTime_to_epoch (void)
+test_GDateTime_to_unix (void)
{
GDateTime *dt;
time_t t;
t = time (NULL);
- dt = g_date_time_new_from_epoch (t);
- g_assert_cmpint (g_date_time_to_epoch (dt), ==, t);
+ dt = g_date_time_new_from_unix_local (t);
+ g_assert_cmpint (g_date_time_to_unix (dt), ==, t);
g_date_time_unref (dt);
}
@@ -474,7 +385,7 @@ test_GDateTime_add_years (void)
{
GDateTime *dt, *dt2;
- dt = g_date_time_new_from_date (2009, 10, 19);
+ dt = g_date_time_new_local (2009, 10, 19, 0, 0, 0);
dt2 = g_date_time_add_years (dt, 1);
g_assert_cmpint (2010, ==, g_date_time_get_year (dt2));
g_date_time_unref (dt);
@@ -484,11 +395,9 @@ test_GDateTime_add_years (void)
static void
test_GDateTime_add_months (void)
{
- GTimeZone *utc_tz = g_time_zone_new_utc ();
-
#define TEST_ADD_MONTHS(y,m,d,a,ny,nm,nd) G_STMT_START { \
GDateTime *dt, *dt2; \
- dt = g_date_time_new_full (y, m, d, 0, 0, 0, utc_tz); \
+ dt = g_date_time_new_utc (y, m, d, 0, 0, 0); \
dt2 = g_date_time_add_months (dt, a); \
ASSERT_DATE (dt2, ny, nm, nd); \
g_date_time_unref (dt); \
@@ -506,8 +415,6 @@ test_GDateTime_add_months (void)
TEST_ADD_MONTHS (2000, 8, 16, -12, 1999, 8, 16);
TEST_ADD_MONTHS (2011, 2, 1, -13, 2010, 1, 1);
TEST_ADD_MONTHS (1776, 7, 4, 1200, 1876, 7, 4);
-
- g_time_zone_free (utc_tz);
}
static void
@@ -515,7 +422,7 @@ test_GDateTime_add_days (void)
{
#define TEST_ADD_DAYS(y,m,d,a,ny,nm,nd) G_STMT_START { \
GDateTime *dt, *dt2; \
- dt = g_date_time_new_from_date (y, m, d); \
+ dt = g_date_time_new_local (y, m, d, 0, 0, 0); \
dt2 = g_date_time_add_days (dt, a); \
g_assert_cmpint (ny, ==, g_date_time_get_year (dt2)); \
g_assert_cmpint (nm, ==, g_date_time_get_month (dt2)); \
@@ -538,7 +445,7 @@ test_GDateTime_add_weeks (void)
{
#define TEST_ADD_WEEKS(y,m,d,a,ny,nm,nd) G_STMT_START { \
GDateTime *dt, *dt2; \
- dt = g_date_time_new_from_date (y, m, d); \
+ dt = g_date_time_new_local (y, m, d, 0, 0, 0); \
dt2 = g_date_time_add_weeks (dt, a); \
g_assert_cmpint (ny, ==, g_date_time_get_year (dt2)); \
g_assert_cmpint (nm, ==, g_date_time_get_month (dt2)); \
@@ -558,7 +465,7 @@ test_GDateTime_add_hours (void)
{
#define TEST_ADD_HOURS(y,m,d,h,mi,s,a,ny,nm,nd,nh,nmi,ns) G_STMT_START { \
GDateTime *dt, *dt2; \
- dt = g_date_time_new_full (y, m, d, h, mi, s, NULL); \
+ dt = g_date_time_new_utc (y, m, d, h, mi, s); \
dt2 = g_date_time_add_hours (dt, a); \
g_assert_cmpint (ny, ==, g_date_time_get_year (dt2)); \
g_assert_cmpint (nm, ==, g_date_time_get_month (dt2)); \
@@ -579,7 +486,7 @@ test_GDateTime_add_full (void)
{
#define TEST_ADD_FULL(y,m,d,h,mi,s,ay,am,ad,ah,ami,as,ny,nm,nd,nh,nmi,ns) G_STMT_START { \
GDateTime *dt, *dt2; \
- dt = g_date_time_new_full (y, m, d, h, mi, s, NULL); \
+ dt = g_date_time_new_utc (y, m, d, h, mi, s); \
dt2 = g_date_time_add_full (dt, ay, am, ad, ah, ami, as); \
g_assert_cmpint (ny, ==, g_date_time_get_year (dt2)); \
g_assert_cmpint (nm, ==, g_date_time_get_month (dt2)); \
@@ -609,29 +516,11 @@ test_GDateTime_add_full (void)
}
static void
-test_GDateTime_add_milliseconds (void)
-{
-#define TEST_ADD_MILLISECOND(i,o) G_STMT_START { \
- GDateTime *dt, *dt2; \
- dt = g_date_time_new_from_date (2000, 1, 1); \
- dt2 = g_date_time_add_milliseconds (dt, i); \
- g_assert_cmpint (o, ==, g_date_time_get_millisecond (dt2)); \
- g_date_time_unref (dt); \
- g_date_time_unref (dt2); \
-} G_STMT_END
-
- TEST_ADD_MILLISECOND (199, 199);
- TEST_ADD_MILLISECOND (10001, 1);
- TEST_ADD_MILLISECOND (22201, 201);
- TEST_ADD_MILLISECOND (-1000, 0);
-}
-
-static void
test_GDateTime_add_minutes (void)
{
#define TEST_ADD_MINUTES(i,o) G_STMT_START { \
GDateTime *dt, *dt2; \
- dt = g_date_time_new_from_date (2000, 1, 1); \
+ dt = g_date_time_new_local (2000, 1, 1, 0, 0, 0); \
dt2 = g_date_time_add_minutes (dt, i); \
g_assert_cmpint (o, ==, g_date_time_get_minute (dt2)); \
g_date_time_unref (dt); \
@@ -641,8 +530,8 @@ test_GDateTime_add_minutes (void)
TEST_ADD_MINUTES (60, 0);
TEST_ADD_MINUTES (100, 40);
TEST_ADD_MINUTES (5, 5);
- TEST_ADD_MINUTES (86401, 1);
- TEST_ADD_MINUTES (-86401, 59);
+ TEST_ADD_MINUTES (1441, 1);
+ TEST_ADD_MINUTES (-1441, 59);
}
static void
@@ -650,7 +539,7 @@ test_GDateTime_add_seconds (void)
{
#define TEST_ADD_SECONDS(i,o) G_STMT_START { \
GDateTime *dt, *dt2; \
- dt = g_date_time_new_from_date (2000, 1, 1); \
+ dt = g_date_time_new_local (2000, 1, 1, 0, 0, 0); \
dt2 = g_date_time_add_seconds (dt, i); \
g_assert_cmpint (o, ==, g_date_time_get_second (dt2)); \
g_date_time_unref (dt); \
@@ -674,9 +563,9 @@ test_GDateTime_diff (void)
#define TEST_DIFF(y,m,d,y2,m2,d2,u) G_STMT_START { \
GDateTime *dt1, *dt2; \
GTimeSpan ts = 0; \
- dt1 = g_date_time_new_from_date (y, m, d); \
- dt2 = g_date_time_new_from_date (y2, m2, d2); \
- ts = g_date_time_difference (dt1, dt2); \
+ dt1 = g_date_time_new_local (y, m, d, 0, 0, 0); \
+ dt2 = g_date_time_new_local (y2, m2, d2, 0, 0, 0); \
+ ts = g_date_time_difference (dt2, dt1); \
g_assert_cmpint (ts, ==, u); \
g_date_time_unref (dt1); \
g_date_time_unref (dt2); \
@@ -695,7 +584,7 @@ test_GDateTime_get_minute (void)
{
GDateTime *dt;
- dt = g_date_time_new_full (2009, 12, 1, 1, 31, 0, NULL);
+ dt = g_date_time_new_utc (2009, 12, 1, 1, 31, 0);
g_assert_cmpint (31, ==, g_date_time_get_minute (dt));
g_date_time_unref (dt);
}
@@ -705,7 +594,7 @@ test_GDateTime_get_month (void)
{
GDateTime *dt;
- dt = g_date_time_new_full (2009, 12, 1, 1, 31, 0, NULL);
+ dt = g_date_time_new_utc (2009, 12, 1, 1, 31, 0);
g_assert_cmpint (12, ==, g_date_time_get_month (dt));
g_date_time_unref (dt);
}
@@ -715,30 +604,18 @@ test_GDateTime_get_second (void)
{
GDateTime *dt;
- dt = g_date_time_new_full (2009, 12, 1, 1, 31, 44, NULL);
+ dt = g_date_time_new_utc (2009, 12, 1, 1, 31, 44);
g_assert_cmpint (44, ==, g_date_time_get_second (dt));
g_date_time_unref (dt);
}
static void
-test_GDateTime_new_from_date (void)
-{
- GDateTime *dt;
-
- dt = g_date_time_new_from_date (2009, 12, 11);
- g_assert_cmpint (2009, ==, g_date_time_get_year (dt));
- g_assert_cmpint (12, ==, g_date_time_get_month (dt));
- g_assert_cmpint (11, ==, g_date_time_get_day_of_month (dt));
- g_date_time_unref (dt);
-}
-
-static void
test_GDateTime_new_full (void)
{
+ GTimeZone *tz;
GDateTime *dt;
- GTimeZone *time_zone;
- dt = g_date_time_new_full (2009, 12, 11, 12, 11, 10, NULL);
+ dt = g_date_time_new_utc (2009, 12, 11, 12, 11, 10);
g_assert_cmpint (2009, ==, g_date_time_get_year (dt));
g_assert_cmpint (12, ==, g_date_time_get_month (dt));
g_assert_cmpint (11, ==, g_date_time_get_day_of_month (dt));
@@ -747,22 +624,22 @@ test_GDateTime_new_full (void)
g_assert_cmpint (10, ==, g_date_time_get_second (dt));
g_date_time_unref (dt);
- time_zone = g_time_zone_new_for_name ("America/Recife");
- dt = g_date_time_new_full (2010, 5, 24, 8, 4, 0, time_zone);
+ tz = g_time_zone_new ("America/Recife");
+ dt = g_date_time_new (tz, 2010, 5, 24, 8, 4, 0);
+ g_time_zone_unref (tz);
g_assert_cmpint (2010, ==, g_date_time_get_year (dt));
g_assert_cmpint (5, ==, g_date_time_get_month (dt));
g_assert_cmpint (24, ==, g_date_time_get_day_of_month (dt));
g_assert_cmpint (8, ==, g_date_time_get_hour (dt));
g_assert_cmpint (4, ==, g_date_time_get_minute (dt));
g_assert_cmpint (0, ==, g_date_time_get_second (dt));
- g_assert_cmpstr ("BRT", ==, g_date_time_get_timezone_name (dt));
+ g_assert_cmpstr ("BRT", ==, g_date_time_get_timezone_abbreviation (dt));
g_assert (!g_date_time_is_daylight_savings (dt));
g_date_time_unref (dt);
- g_time_zone_free (time_zone);
}
static void
-test_GDateTime_utc_now (void)
+test_GDateTime_now_utc (void)
{
GDateTime *dt;
time_t t;
@@ -781,7 +658,7 @@ test_GDateTime_utc_now (void)
memcpy (&tm, tmp, sizeof (struct tm));
}
#endif
- dt = g_date_time_new_utc_now ();
+ dt = g_date_time_new_now_utc ();
g_assert_cmpint (tm.tm_year + 1900, ==, g_date_time_get_year (dt));
g_assert_cmpint (tm.tm_mon + 1, ==, g_date_time_get_month (dt));
g_assert_cmpint (tm.tm_mday, ==, g_date_time_get_day_of_month (dt));
@@ -801,7 +678,7 @@ test_GDateTime_get_utc_offset (void)
memset (&tm, 0, sizeof (tm));
get_localtime_tm (time (NULL), &tm);
- dt = g_date_time_new_now ();
+ dt = g_date_time_new_now_local ();
ts = g_date_time_get_utc_offset (dt);
#ifdef HAVE_STRUCT_TM_TM_GMTOFF
g_assert_cmpint (ts, ==, (tm.tm_gmtoff * G_TIME_SPAN_SECOND));
@@ -819,7 +696,7 @@ test_GDateTime_to_timeval (void)
memset (&tv2, 0, sizeof (tv2));
g_get_current_time (&tv1);
- dt = g_date_time_new_from_timeval (&tv1);
+ dt = g_date_time_new_from_timeval_local (&tv1);
g_date_time_to_timeval (dt, &tv2);
g_assert_cmpint (tv1.tv_sec, ==, tv2.tv_sec);
g_assert_cmpint (tv1.tv_usec, ==, tv2.tv_usec);
@@ -831,8 +708,8 @@ test_GDateTime_to_local (void)
{
GDateTime *utc, *now, *dt;
- utc = g_date_time_new_utc_now ();
- now = g_date_time_new_now ();
+ utc = g_date_time_new_now_utc ();
+ now = g_date_time_new_now_local ();
dt = g_date_time_to_local (utc);
g_assert_cmpint (g_date_time_get_year (now), ==, g_date_time_get_year (dt));
@@ -863,7 +740,7 @@ test_GDateTime_to_utc (void)
memcpy (&tm, tmp, sizeof (struct tm));
}
#endif
- dt2 = g_date_time_new_now ();
+ dt2 = g_date_time_new_now_local ();
dt = g_date_time_to_utc (dt2);
g_assert_cmpint (tm.tm_year + 1900, ==, g_date_time_get_year (dt));
g_assert_cmpint (tm.tm_mon + 1, ==, g_date_time_get_month (dt));
@@ -879,7 +756,7 @@ static void
test_GDateTime_get_day_of_year (void)
{
#define TEST_DAY_OF_YEAR(y,m,d,o) G_STMT_START { \
- GDateTime *__dt = g_date_time_new_from_date ((y), (m), (d)); \
+ GDateTime *__dt = g_date_time_new_local ((y), (m), (d), 0, 0, 0); \
g_assert_cmpint ((o), ==, g_date_time_get_day_of_year (__dt)); \
g_date_time_unref (__dt); } G_STMT_END
@@ -898,21 +775,21 @@ test_GDateTime_printf (void)
gchar t_str[16];
#define TEST_PRINTF(f,o) G_STMT_START { \
-GDateTime *__dt = g_date_time_new_from_date (2009, 10, 24); \
+GDateTime *__dt = g_date_time_new_local (2009, 10, 24, 0, 0, 0);\
gchar *__p = g_date_time_format (__dt, (f)); \
g_assert_cmpstr (__p, ==, (o)); \
g_date_time_unref (__dt); \
g_free (__p); } G_STMT_END
#define TEST_PRINTF_DATE(y,m,d,f,o) G_STMT_START { \
- GDateTime *dt = g_date_time_new_from_date ((y), (m), (d)); \
+ GDateTime *dt = g_date_time_new_local (y, m, d, 0, 0, 0); \
gchar *p = g_date_time_format (dt, (f)); \
g_assert_cmpstr (p, ==, (o)); \
g_date_time_unref (dt); \
g_free (p); } G_STMT_END
#define TEST_PRINTF_TIME(h,m,s,f,o) G_STMT_START { \
- GDateTime *dt = g_date_time_new_full (2009, 10, 24, (h), (m), (s), NULL); \
+ GDateTime *dt = g_date_time_new_local (2009, 10, 24, (h), (m), (s)); \
gchar *p = g_date_time_format (dt, (f)); \
g_assert_cmpstr (p, ==, (o)); \
g_date_time_unref (dt); \
@@ -991,36 +868,34 @@ test_GDateTime_dst (void)
GDateTime *dt1, *dt2;
GTimeZone *tz;
- tz = g_time_zone_new_for_name ("Europe/London");
-
/* this date has the DST state set for Europe/London */
- dt1 = g_date_time_new_full (2009, 8, 15, 3, 0, 1, tz);
+ tz = g_time_zone_new ("Europe/London");
+ dt1 = g_date_time_new (tz, 2009, 8, 15, 3, 0, 1);
g_assert (g_date_time_is_daylight_savings (dt1));
g_assert_cmpint (g_date_time_get_utc_offset (dt1) / G_USEC_PER_SEC, ==, 3600);
g_assert_cmpint (g_date_time_get_hour (dt1), ==, 3);
- /* add 6 months to clear the DST flag and go back one hour */
+ /* add 6 months to clear the DST flag but keep the same time */
dt2 = g_date_time_add_months (dt1, 6);
g_assert (!g_date_time_is_daylight_savings (dt2));
g_assert_cmpint (g_date_time_get_utc_offset (dt2) / G_USEC_PER_SEC, ==, 0);
- g_assert_cmpint (g_date_time_get_hour (dt2), ==, 2);
+ g_assert_cmpint (g_date_time_get_hour (dt2), ==, 3);
g_date_time_unref (dt2);
g_date_time_unref (dt1);
/* now do the reverse: start with a non-DST state and move to DST */
- dt1 = g_date_time_new_full (2009, 2, 15, 2, 0, 1, tz);
+ dt1 = g_date_time_new (tz, 2009, 2, 15, 2, 0, 1);
g_assert (!g_date_time_is_daylight_savings (dt1));
g_assert_cmpint (g_date_time_get_hour (dt1), ==, 2);
dt2 = g_date_time_add_months (dt1, 6);
g_assert (g_date_time_is_daylight_savings (dt2));
- g_assert_cmpint (g_date_time_get_hour (dt2), ==, 3);
+ g_assert_cmpint (g_date_time_get_hour (dt2), ==, 2);
g_date_time_unref (dt2);
g_date_time_unref (dt1);
-
- g_time_zone_free (tz);
+ g_time_zone_unref (tz);
}
gint
@@ -1034,43 +909,36 @@ main (gint argc,
g_test_add_func ("/GDateTime/add_days", test_GDateTime_add_days);
g_test_add_func ("/GDateTime/add_full", test_GDateTime_add_full);
g_test_add_func ("/GDateTime/add_hours", test_GDateTime_add_hours);
- g_test_add_func ("/GDateTime/add_milliseconds", test_GDateTime_add_milliseconds);
g_test_add_func ("/GDateTime/add_minutes", test_GDateTime_add_minutes);
g_test_add_func ("/GDateTime/add_months", test_GDateTime_add_months);
g_test_add_func ("/GDateTime/add_seconds", test_GDateTime_add_seconds);
g_test_add_func ("/GDateTime/add_weeks", test_GDateTime_add_weeks);
g_test_add_func ("/GDateTime/add_years", test_GDateTime_add_years);
g_test_add_func ("/GDateTime/compare", test_GDateTime_compare);
- g_test_add_func ("/GDateTime/date", test_GDateTime_date);
g_test_add_func ("/GDateTime/diff", test_GDateTime_diff);
g_test_add_func ("/GDateTime/equal", test_GDateTime_equal);
g_test_add_func ("/GDateTime/get_day_of_week", test_GDateTime_get_day_of_week);
g_test_add_func ("/GDateTime/get_day_of_month", test_GDateTime_get_day_of_month);
g_test_add_func ("/GDateTime/get_day_of_year", test_GDateTime_get_day_of_year);
- g_test_add_func ("/GDateTime/get_dmy", test_GDateTime_get_dmy);
+ g_test_add_func ("/GDateTime/get_ymd", test_GDateTime_get_ymd);
g_test_add_func ("/GDateTime/get_hour", test_GDateTime_get_hour);
- g_test_add_func ("/GDateTime/get_julian", test_GDateTime_get_julian);
g_test_add_func ("/GDateTime/get_microsecond", test_GDateTime_get_microsecond);
- g_test_add_func ("/GDateTime/get_millisecond", test_GDateTime_get_millisecond);
g_test_add_func ("/GDateTime/get_minute", test_GDateTime_get_minute);
g_test_add_func ("/GDateTime/get_month", test_GDateTime_get_month);
g_test_add_func ("/GDateTime/get_second", test_GDateTime_get_second);
g_test_add_func ("/GDateTime/get_utc_offset", test_GDateTime_get_utc_offset);
g_test_add_func ("/GDateTime/get_year", test_GDateTime_get_year);
g_test_add_func ("/GDateTime/hash", test_GDateTime_hash);
- g_test_add_func ("/GDateTime/is_leap_year", test_GDateTime_is_leap_year);
- g_test_add_func ("/GDateTime/new_from_date", test_GDateTime_new_from_date);
- g_test_add_func ("/GDateTime/new_from_epoch", test_GDateTime_new_from_epoch);
+ g_test_add_func ("/GDateTime/new_from_unix", test_GDateTime_new_from_unix);
g_test_add_func ("/GDateTime/new_from_timeval", test_GDateTime_new_from_timeval);
g_test_add_func ("/GDateTime/new_full", test_GDateTime_new_full);
g_test_add_func ("/GDateTime/now", test_GDateTime_now);
g_test_add_func ("/GDateTime/printf", test_GDateTime_printf);
g_test_add_func ("/GDateTime/to_local", test_GDateTime_to_local);
- g_test_add_func ("/GDateTime/to_epoch", test_GDateTime_to_epoch);
+ g_test_add_func ("/GDateTime/to_unix", test_GDateTime_to_unix);
g_test_add_func ("/GDateTime/to_timeval", test_GDateTime_to_timeval);
g_test_add_func ("/GDateTime/to_utc", test_GDateTime_to_utc);
- g_test_add_func ("/GDateTime/today", test_GDateTime_today);
- g_test_add_func ("/GDateTime/utc_now", test_GDateTime_utc_now);
+ g_test_add_func ("/GDateTime/now_utc", test_GDateTime_now_utc);
g_test_add_func ("/GDateTime/dst", test_GDateTime_dst);
return g_test_run ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]