[glib] Add GDateTime to GLib
- From: Emmanuele Bassi <ebassi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] Add GDateTime to GLib
- Date: Tue, 24 Aug 2010 23:11:54 +0000 (UTC)
commit e1f13ee9ed38d4f14bf927b6fa3f28530afc3640
Author: Thiago Santos <thiago sousa santos collabora co uk>
Date: Fri May 28 08:19:29 2010 -0300
Add GDateTime to GLib
GDateTime is an opaque data type containing a date and time
representation. It's immutable once created and reference
counted.
https://bugzilla.gnome.org/show_bug.cgi?id=50076
Based on the code by: Christian Hergert <chris dronelabs com>
Signed-off-by: Emmanuele Bassi <ebassi linux intel com>
glib/Makefile.am | 16 +-
glib/gdatetime.c | 2227 ++++++++++++++++++++++++++++++++++++++++++++++++
glib/gdatetime.h | 190 ++++
glib/glib.h | 1 +
glib/glib.symbols | 51 ++
glib/tests/.gitignore | 1 +
glib/tests/Makefile.am | 5 +-
glib/tests/gdatetime.c | 962 +++++++++++++++++++++
8 files changed, 3445 insertions(+), 8 deletions(-)
---
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 69f9028..b8ce522 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -134,7 +134,8 @@ libglib_2_0_la_SOURCES = \
gconvert.c \
gdataset.c \
gdatasetprivate.h \
- gdate.c \
+ gdate.c \
+ gdatetime.c \
gdir.c \
gerror.c \
gfileutils.c \
@@ -142,11 +143,11 @@ libglib_2_0_la_SOURCES = \
ghook.c \
ghostutils.c \
giochannel.c \
- gkeyfile.c \
+ gkeyfile.c \
glibintl.h \
glib_trace.h \
glist.c \
- gmain.c \
+ gmain.c \
gmappedfile.c \
gmarkup.c \
gmem.c \
@@ -233,6 +234,7 @@ glibsubinclude_HEADERS = \
gconvert.h \
gdataset.h \
gdate.h \
+ gdatetime.h \
gdir.h \
gerror.h \
gfileutils.h \
@@ -277,7 +279,7 @@ glibsubinclude_HEADERS = \
gtree.h \
gtypes.h \
gunicode.h \
- gurifuncs.h \
+ gurifuncs.h \
gutils.h \
gvarianttype.h \
gvariant.h \
@@ -289,7 +291,7 @@ install-data-local: install-ms-lib install-def-file
echo "*** Old headers found in $(glibincludedir). You should remove the" ; \
echo "*** contents of this directory and type 'make install' again." ; \
false ; \
- fi
+ fi
uninstall-local: uninstall-ms-lib uninstall-def-file
@@ -400,8 +402,8 @@ bin_SCRIPTS = ${auto_config_binscripts}
EXTRA_DIST += ${auto_config_binscripts}
CONFIGVARS = \
- "bindir" : "${bindir}", \
- "glib-version" : "${GLIB_VERSION}"
+ "bindir" : "${bindir}", \
+ "glib-version" : "${GLIB_VERSION}"
install-exec-hook:
for sf in ${auto_config_binscripts} ; do \
diff --git a/glib/gdatetime.c b/glib/gdatetime.c
new file mode 100644
index 0000000..b7cc7aa
--- /dev/null
+++ b/glib/gdatetime.c
@@ -0,0 +1,2227 @@
+/* gdatetime.c
+ *
+ * Copyright (C) 2009-2010 Christian Hergert <chris dronelabs com>
+ *
+ * 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 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
+ */
+
+/* Algorithms within this file are based on the Calendar FAQ by
+ * Claus Tondering. It can be found at
+ * http://www.tondering.dk/claus/cal/calendar29.txt
+ *
+ * Copyright and disclaimer
+ * ------------------------
+ * This document is Copyright (C) 2008 by Claus Tondering.
+ * E-mail: claus tondering dk (Please include the word
+ * "calendar" in the subject line.)
+ * The document may be freely distributed, provided this
+ * copyright notice is included and no money is charged for
+ * the document.
+ *
+ * This document is provided "as is". No warranties are made as
+ * to its correctness.
+ */
+
+#include "config.h"
+
+#include "glib.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifndef G_OS_WIN32
+#include <sys/time.h>
+#include <time.h>
+#endif /* !G_OS_WIN32 */
+
+#include "glibintl.h"
+
+#include "gdatetime.h"
+
+/**
+ * SECTION:date-time
+ * @title: GDateTime
+ * @short_description: A Date and Time structure
+ *
+ * #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 an immutable object: once it has been created it cannot be
+ * modified further. All modifiers will create a new #GDateTime.
+ *
+ * #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 Julian Day Number since the
+ * initial Julian Period (-4712 BC). However, the public API uses the
+ * internationally accepted Gregorian Calendar.
+ *
+ * #GDateTime is available since GLib 2.26.
+ */
+
+#define USEC_PER_SECOND (G_GINT64_CONSTANT (1000000))
+#define USEC_PER_MINUTE (G_GINT64_CONSTANT (60000000))
+#define USEC_PER_HOUR (G_GINT64_CONSTANT (3600000000))
+#define USEC_PER_MILLISECOND (G_GINT64_CONSTANT (1000))
+#define USEC_PER_DAY (G_GINT64_CONSTANT (86400000000))
+
+#define GREGORIAN_LEAP(y) (((y % 4) == 0) && (!(((y % 100) == 0) && ((y % 400) != 0))))
+#define JULIAN_YEAR(d) ((d)->julian / 365.25)
+#define DAYS_PER_PERIOD (G_GINT64_CONSTANT (2914695))
+
+#define ADD_DAYS(d,n) G_STMT_START { \
+ gint __day = d->julian + (n); \
+ if (__day < 1) \
+ { \
+ d->period += -1 + (__day / DAYS_PER_PERIOD); \
+ d->period += DAYS_PER_PERIOD + (__day % DAYS_PER_PERIOD); \
+ } \
+ else if (__day > DAYS_PER_PERIOD) \
+ { \
+ d->period += (d->julian + (n)) / DAYS_PER_PERIOD; \
+ d->julian = (d->julian + (n)) % DAYS_PER_PERIOD; \
+ } \
+ else \
+ d->julian += n; } G_STMT_END
+
+#define ADD_USEC(d,n) G_STMT_START { \
+ gint64 __usec; \
+ gint __days; \
+ __usec = (d)->usec + (n); \
+ __days = __usec / USEC_PER_DAY; \
+ if (__usec < 0) \
+ __days -= 1; \
+ if (__days != 0) \
+ ADD_DAYS ((d), __days); \
+ if (__usec < 0) \
+ d->usec = USEC_PER_DAY + (__usec % USEC_PER_DAY); \
+ else \
+ d->usec = __usec % USEC_PER_DAY; } G_STMT_END
+
+#define GET_AMPM(d,l) ((g_date_time_get_hour (d) < 12) \
+ ? (l ? C_("GDateTime", "am") : C_("GDateTime", "AM")) \
+ : (l ? C_("GDateTime", "pm") : C_("GDateTime", "PM")))
+
+#define WEEKDAY_ABBR(d) (get_weekday_name_abbr (g_date_time_get_day_of_week (datetime)))
+#define WEEKDAY_FULL(d) (get_weekday_name (g_date_time_get_day_of_week (datetime)))
+
+#define MONTH_ABBR(d) (get_month_name_abbr (g_date_time_get_month (datetime)))
+#define MONTH_FULL(d) (get_month_name (g_date_time_get_month (datetime)))
+
+/* Translators: this is the preferred format for expressing the date */
+#define GET_PREFERRED_DATE(d) (g_date_time_printf ((d), C_("GDateTime", "%m/%d/%y")))
+
+/* Translators: this is the preferred format for expressing the time */
+#define GET_PREFERRED_TIME(d) (g_date_time_printf ((d), C_("GDateTime", "%H:%M:%S")))
+
+typedef struct _GTimeZone GTimeZone;
+
+static const guint16 days_in_months[2][13] =
+{
+ { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+
+static const guint16 days_in_year[2][13] =
+{
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+};
+
+static const gchar *
+get_month_name (gint month)
+{
+ switch (month)
+ {
+ case 1:
+ return C_("GDateTime", "January");
+ case 2:
+ return C_("GDateTime", "February");
+ case 3:
+ return C_("GDateTime", "March");
+ case 4:
+ return C_("GDateTime", "April");
+ case 5:
+ return C_("GDateTime", "May");
+ case 6:
+ return C_("GDateTime", "June");
+ case 7:
+ return C_("GDateTime", "July");
+ case 8:
+ return C_("GDateTime", "August");
+ case 9:
+ return C_("GDateTime", "September");
+ case 10:
+ return C_("GDateTime", "October");
+ case 11:
+ return C_("GDateTime", "November");
+ case 12:
+ return C_("GDateTime", "December");
+
+ default:
+ g_warning ("Invalid month number %d", month);
+ }
+
+ return NULL;
+}
+
+static const gchar *
+get_month_name_abbr (gint month)
+{
+ switch (month)
+ {
+ case 1:
+ return C_("GDateTime", "Jan");
+ case 2:
+ return C_("GDateTime", "Feb");
+ case 3:
+ return C_("GDateTime", "Mar");
+ case 4:
+ return C_("GDateTime", "Apr");
+ case 5:
+ return C_("GDateTime", "May");
+ case 6:
+ return C_("GDateTime", "Jun");
+ case 7:
+ return C_("GDateTime", "Jul");
+ case 8:
+ return C_("GDateTime", "Aug");
+ case 9:
+ return C_("GDateTime", "Sep");
+ case 10:
+ return C_("GDateTime", "Oct");
+ case 11:
+ return C_("GDateTime", "Nov");
+ case 12:
+ return C_("GDateTime", "Dec");
+
+ default:
+ g_warning ("Invalid month number %d", month);
+ }
+
+ return NULL;
+}
+
+static const gchar *
+get_weekday_name (gint day)
+{
+ switch (day)
+ {
+ case 1:
+ return C_("GDateTime", "Monday");
+ case 2:
+ return C_("GDateTime", "Tuesday");
+ case 3:
+ return C_("GDateTime", "Wednesday");
+ case 4:
+ return C_("GDateTime", "Thursday");
+ case 5:
+ return C_("GDateTime", "Friday");
+ case 6:
+ return C_("GDateTime", "Saturday");
+ case 7:
+ return C_("GDateTime", "Sunday");
+
+ default:
+ g_warning ("Invalid week day number %d", day);
+ }
+
+ return NULL;
+}
+
+static const gchar *
+get_weekday_name_abbr (gint day)
+{
+ switch (day)
+ {
+ case 1:
+ return C_("GDateTime", "Mon");
+ case 2:
+ return C_("GDateTime", "Tue");
+ case 3:
+ return C_("GDateTime", "Wed");
+ case 4:
+ return C_("GDateTime", "Thu");
+ case 5:
+ return C_("GDateTime", "Fri");
+ case 6:
+ return C_("GDateTime", "Sat");
+ case 7:
+ return C_("GDateTime", "Sun");
+ default:
+ g_warning (_("Invalid week day number %d"), day);
+ }
+
+ return NULL;
+}
+
+struct _GDateTime
+{
+ /* Julian Period, 0 is Initial Epoch */
+ gint period : 3;
+
+ /* Day within Julian Period */
+ guint julian : 22;
+
+ /* Microsecond timekeeping within Day */
+ guint64 usec : 37;
+
+ gint reserved : 2;
+
+ /* TimeZone information, NULL is UTC */
+ GTimeZone *tz;
+
+ volatile gint ref_count;
+};
+
+struct _GTimeZone
+{
+ /* TZ abbreviation (e.g. PST) */
+ gchar *name;
+
+ gint64 offset;
+
+ guint is_dst : 1;
+};
+
+#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)
+{
+ gchar *retval;
+
+ if (tz_name != NULL)
+ {
+ const gchar *tz_dir = g_getenv ("TZDIR");
+
+ if (tz_dir != NULL)
+ retval = g_build_filename (tz_dir, tz_name, NULL);
+ else
+ retval = g_build_filename ("/", "usr", "share", ZONEINFO_DIR, tz_name, NULL);
+ }
+ else
+ {
+ /* an empty tz_name means "the current timezone file". tzset(3) defines
+ * it to be /usr/share/zoneinfo/localtime, and it also allows an
+ * /etc/localtime as a symlink to the localtime file under
+ * /usr/share/zoneinfo or to the correct timezone file. Fedora does not
+ * have /usr/share/zoneinfo/localtime, but it does have a real
+ * /etc/localtime.
+ *
+ * in any case, this path should resolve correctly.
+ */
+ retval = g_build_filename ("/", "etc", "localtime", NULL);
+ }
+
+ return retval;
+}
+
+/*
+ * Parses tzdata database times to get timezone info.
+ *
+ * @tzname: Olson database name for the timezone
+ * @start: Time offset from epoch we want to know the timezone
+ * @_is_dst: Returns if this time in the timezone is in DST
+ * @_offset: Returns the offset from UTC for this timezone
+ * @_name: Returns the abreviated name for thie timezone
+ */
+static gboolean
+parse_tzdata (const gchar *tzname,
+ gint64 start,
+ gboolean is_utc,
+ gboolean *_is_dst,
+ gint64 *_offset,
+ gchar **_name)
+{
+ gchar *filename, *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;
+ GError *error;
+
+ filename = get_tzdata_path (tzname);
+
+ /* XXX: should we be caching this in memory for faster access?
+ * and if so, how do we expire the cache?
+ */
+ error = NULL;
+ if (!g_file_get_contents (filename, &contents, &length, &error))
+ {
+ g_free (filename);
+ return FALSE;
+ }
+
+ g_free (filename);
+
+ if (length < TZ_HEADER_SIZE ||
+ (strncmp (contents, TZ_MAGIC, TZ_MAGIC_LEN) != 0))
+ {
+ g_free (contents);
+ return FALSE;
+ }
+
+ timecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TIMECNT_OFFSET));
+ typecnt = GUINT32_FROM_BE (*(guint32 *)(contents + TZ_TYPECNT_OFFSET));
+
+ 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);
+
+ /*
+ * Find the first transition that contains the 'start' time
+ */
+ for (i = 1; i < timecnt && start_transition == -1; i++)
+ {
+ 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;
+ }
+ }
+
+ if (start_transition == -1)
+ {
+ if (timecnt)
+ start_transition = ttinfo_map[timecnt - 1];
+ else
+ start_transition = 0;
+ }
+
+ /* 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_free (contents);
+
+ if (_offset)
+ *_offset = offset;
+
+ if (_is_dst)
+ *_is_dst = isdst;
+
+ return TRUE;
+}
+
+/*< internal >
+ * g_time_zone_new_from_epoc:
+ * @tzname: The Olson's database timezone name
+ * @epoch: The epoch offset
+ * @is_utc: If the @epoch is in UTC or already in the @tzname timezone
+ *
+ * Creates a new timezone
+ */
+static GTimeZone *
+g_time_zone_new_from_epoch (const gchar *tzname,
+ gint64 epoch,
+ gboolean is_utc)
+{
+ GTimeZone *tz = NULL;
+ gint64 offset;
+ gboolean is_dst;
+ gchar *name = NULL;
+
+ if (parse_tzdata (tzname, epoch, is_utc, &is_dst, &offset, &name))
+ {
+ tz = g_slice_new (GTimeZone);
+ tz->is_dst = is_dst;
+ tz->offset = offset;
+ tz->name = name;
+ }
+
+ return tz;
+}
+
+#define SECS_PER_MINUTE (60)
+#define SECS_PER_HOUR (60 * SECS_PER_MINUTE)
+#define SECS_PER_DAY (24 * SECS_PER_HOUR)
+#define SECS_PER_YEAR (365 * SECS_PER_DAY)
+#define SECS_PER_JULIAN (DAYS_PER_PERIOD * SECS_PER_DAY)
+
+static gint64
+g_date_time_secs_offset (GDateTime * dt)
+{
+ gint64 secs;
+ gint d, y, h, m, s;
+ gint leaps;
+
+ y = g_date_time_get_year (dt) - 1970;
+ d = g_date_time_get_day_of_year (dt);
+ h = g_date_time_get_hour (dt);
+ m = g_date_time_get_minute (dt);
+ s = g_date_time_get_second (dt);
+
+ /* FIXME this is an approximation */
+ leaps = y / 4;
+
+ secs = 0;
+ secs += y * SECS_PER_YEAR;
+ secs += d * SECS_PER_DAY;
+ secs += leaps * SECS_PER_DAY;
+ secs += h * SECS_PER_HOUR;
+ secs += m * SECS_PER_MINUTE;
+ secs += s;
+
+ return secs;
+}
+
+/*< internal >
+ * g_date_time_create_time_zone:
+ * @dt: a #GDateTime
+ * @tzname: the name of the timezone
+ *
+ * Creates a timezone from a #GDateTime (disregarding its own timezone).
+ * This function transforms the #GDateTime into seconds since the epoch
+ * and creates a timezone for it in the @tzname zone.
+ *
+ * Return value: a newly created #GTimeZone
+ */
+static GTimeZone *
+g_date_time_create_time_zone (GDateTime *dt,
+ const gchar *tzname)
+{
+ gint64 secs;
+
+ secs = g_date_time_secs_offset (dt);
+
+ return g_time_zone_new_from_epoch (tzname, secs, FALSE);
+}
+
+static GDateTime *
+g_date_time_new (void)
+{
+ GDateTime *datetime;
+
+ datetime = g_slice_new0 (GDateTime);
+ datetime->ref_count = 1;
+
+ return datetime;
+}
+
+static GTimeZone *
+g_time_zone_copy (const GTimeZone *timezone)
+{
+ GTimeZone *tz;
+
+ if (G_UNLIKELY (timezone == NULL))
+ return NULL;
+
+ tz = g_slice_new (GTimeZone);
+ memcpy (tz, timezone, sizeof (GTimeZone));
+
+ tz->name = g_strdup (timezone->name);
+
+ return tz;
+}
+
+static void
+g_time_zone_free (GTimeZone *timezone)
+{
+ if (G_LIKELY (timezone != NULL))
+ {
+ g_free (timezone->name);
+ g_slice_free (GTimeZone, timezone);
+ }
+}
+
+static void
+g_date_time_free (GDateTime *datetime)
+{
+ if (G_UNLIKELY (datetime == NULL))
+ return;
+
+ if (datetime->tz)
+ g_time_zone_free (datetime->tz);
+
+ g_slice_free (GDateTime, datetime);
+}
+
+static void
+g_date_time_get_week_number (const GDateTime *datetime,
+ gint *week_number,
+ gint *day_of_week,
+ gint *day_of_year)
+{
+ 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;
+ }
+
+ if (day_of_week)
+ *day_of_week = d + 1;
+
+ if (day_of_year)
+ *day_of_year = f + 1;
+}
+
+/**
+ * g_date_time_add:
+ * @datetime: a #GDateTime
+ * @timespan: a #GTimeSpan
+ *
+ * Creates a copy of @datetime and adds the specified timespan to the copy.
+ *
+ * Return value: the newly created #GDateTime which should be freed with
+ * g_date_time_unref().
+ *
+ * Since: 2.26
+ */
+GDateTime*
+g_date_time_add (const GDateTime *datetime,
+ GTimeSpan timespan)
+{
+ GDateTime *dt;
+
+ g_return_val_if_fail (datetime != NULL, NULL);
+
+ dt = g_date_time_copy (datetime);
+ ADD_USEC (dt, timespan);
+
+ return dt;
+}
+
+/**
+ * g_date_time_add_years:
+ * @datetime: a #GDateTime
+ * @years: the number of years
+ *
+ * Creates a copy of @datetime and adds the specified number of years to the
+ * copy.
+ *
+ * Return value: the newly created #GDateTime which should be freed with
+ * g_date_time_unref().
+ *
+ * Since: 2.26
+ */
+GDateTime*
+g_date_time_add_years (const GDateTime *datetime,
+ gint years)
+{
+ GDateTime *dt;
+ gint day;
+
+ g_return_val_if_fail (datetime != NULL, NULL);
+
+ day = g_date_time_get_day_of_month (datetime);
+ if (g_date_time_is_leap_year (datetime) &&
+ g_date_time_get_month (datetime) == 2)
+ {
+ if (day == 29)
+ day--;
+ }
+
+ dt = g_date_time_new_from_date (g_date_time_get_year (datetime) + years,
+ g_date_time_get_month (datetime),
+ day);
+ dt->usec = datetime->usec;
+
+ return dt;
+}
+
+/**
+ * g_date_time_add_months:
+ * @datetime: a #GDateTime
+ * @months: the number of months
+ *
+ * Creates a copy of @datetime and adds the specified number of months to the
+ * copy.
+ *
+ * Return value: the newly created #GDateTime which should be freed with
+ * g_date_time_unref().
+ *
+ * Since: 2.26
+ */
+GDateTime*
+g_date_time_add_months (const GDateTime *datetime,
+ gint months)
+{
+ GDateTime *dt;
+ gint year,
+ month,
+ day,
+ i,
+ a;
+ const guint16 *days;
+
+ g_return_val_if_fail (datetime != NULL, NULL);
+ g_return_val_if_fail (months != 0, NULL);
+
+ month = g_date_time_get_month (datetime);
+ year = g_date_time_get_year (datetime);
+ a = months > 0 ? 1 : -1;
+
+ for (i = 0; i < ABS (months); i++)
+ {
+ month += a;
+ if (month < 1)
+ {
+ year--;
+ month = 12;
+ }
+ else if (month > 12)
+ {
+ year++;
+ month = 1;
+ }
+ }
+
+ day = g_date_time_get_day_of_month (datetime);
+ days = days_in_months [GREGORIAN_LEAP (year) ? 1 : 0];
+
+ if (days[month] < day)
+ day = days[month];
+
+ dt = g_date_time_new_from_date (year, month, day);
+ dt->usec = datetime->usec;
+
+ return dt;
+}
+
+/**
+ * g_date_time_add_weeks:
+ * @datetime: a #GDateTime
+ * @weeks: the number of weeks
+ *
+ * Creates a copy of @datetime and adds the specified number of weeks to the
+ * copy.
+ *
+ * Return value: the newly created #GDateTime which should be freed with
+ * g_date_time_unref().
+ *
+ * Since: 2.26
+ */
+GDateTime*
+g_date_time_add_weeks (const GDateTime *datetime,
+ gint weeks)
+{
+ g_return_val_if_fail (datetime != NULL, NULL);
+
+ return g_date_time_add_days (datetime, weeks * 7);
+}
+
+/**
+ * g_date_time_add_days:
+ * @datetime: a #GDateTime
+ * @days: the number of days
+ *
+ * Creates a copy of @datetime and adds the specified number of days to the
+ * copy.
+ *
+ * Return value: the newly created #GDateTime which should be freed with
+ * g_date_time_unref().
+ *
+ * Since: 2.26
+ */
+GDateTime*
+g_date_time_add_days (const GDateTime *datetime,
+ gint days)
+{
+ GDateTime *dt;
+
+ g_return_val_if_fail (datetime != NULL, NULL);
+
+ dt = g_date_time_copy (datetime);
+ ADD_DAYS (dt, days);
+
+ return dt;
+}
+
+/**
+ * g_date_time_add_hours:
+ * @datetime: a #GDateTime
+ * @hours: the number of hours to add
+ *
+ * Creates a copy of @datetime and adds the specified number of hours
+ *
+ * Return value: the newly created #GDateTime which should be freed with
+ * g_date_time_unref().
+ *
+ * Since: 2.26
+ */
+GDateTime*
+g_date_time_add_hours (const GDateTime *datetime,
+ gint hours)
+{
+ GDateTime *dt;
+ gint64 usec;
+
+ g_return_val_if_fail (datetime != NULL, NULL);
+
+ usec = hours * USEC_PER_HOUR;
+ dt = g_date_time_copy (datetime);
+ ADD_USEC (dt, usec);
+
+ return dt;
+}
+
+/**
+ * g_date_time_add_seconds:
+ * @datetime: a #GDateTime
+ * @seconds: the number of seconds to add
+ *
+ * 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().
+ *
+ * Since: 2.26
+ */
+GDateTime*
+g_date_time_add_seconds (const GDateTime *datetime,
+ gint seconds)
+{
+ GDateTime *dt;
+ gint64 usec;
+
+ g_return_val_if_fail (datetime != NULL, NULL);
+
+ dt = g_date_time_copy (datetime);
+ usec = seconds * USEC_PER_SECOND;
+ ADD_USEC (dt, usec);
+
+ return dt;
+}
+
+/**
+ * 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;
+ guint64 usec;
+
+ g_return_val_if_fail (datetime != NULL, NULL);
+
+ dt = g_date_time_copy (datetime);
+ usec = milliseconds * USEC_PER_MILLISECOND;
+ ADD_USEC (dt, usec);
+
+ return dt;
+}
+
+/**
+ * g_date_time_add_minutes:
+ * @datetime: a #GDateTime
+ * @minutes: the number of minutes to add
+ *
+ * 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().
+ *
+ * Since: 2.26
+ */
+GDateTime*
+g_date_time_add_minutes (const GDateTime *datetime,
+ gint minutes)
+{
+ GDateTime *dt;
+
+ g_return_val_if_fail (datetime != NULL, NULL);
+
+ dt = g_date_time_copy (datetime);
+ ADD_USEC (dt, minutes * USEC_PER_MINUTE);
+
+ return dt;
+}
+
+/**
+ * g_date_time_add_full:
+ * @datetime: a #GDateTime
+ * @years: the number of years to add
+ * @months: the number of months to add
+ * @days: the number of days to add
+ * @hours: the number of hours to add
+ * @minutes: the number of minutes to add
+ * @seconds: the number of seconds to add
+ *
+ * Creates a new #GDateTime adding the specified values to the current date and
+ * time in @datetime.
+ *
+ * Return value: the newly created #GDateTime that should be freed with
+ * g_date_time_unref().
+ *
+ * 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 *tmp, *dt;
+
+ g_return_val_if_fail (datetime != NULL, NULL);
+
+ dt = g_date_time_add_years (datetime, years);
+ tmp = dt;
+
+ dt = g_date_time_add_months (tmp, months);
+ g_date_time_unref (tmp);
+ tmp = dt;
+
+ dt = g_date_time_add_days (tmp, days);
+ g_date_time_unref (tmp);
+ tmp = dt;
+
+ dt = g_date_time_add_hours (tmp, hours);
+ g_date_time_unref (tmp);
+ tmp = dt;
+
+ dt = g_date_time_add_minutes (tmp, minutes);
+ g_date_time_unref (tmp);
+ tmp = dt;
+
+ dt = g_date_time_add_seconds (tmp, seconds);
+ g_date_time_unref (tmp);
+
+ return dt;
+}
+
+/**
+ * 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.
+ *
+ * Return value: 0 for equal, less than zero if dt1 is less than dt2, greater
+ * than zero if dt2 is greator than dt1.
+ *
+ * Since: 2.26
+ */
+gint
+g_date_time_compare (gconstpointer dt1,
+ gconstpointer dt2)
+{
+ const GDateTime *a, *b;
+
+ a = dt1;
+ b = dt2;
+
+ if ((a->period == b->period) &&
+ (a->julian == b->julian) &&
+ (a->usec == b->usec))
+ {
+ return 0;
+ }
+ else if ((a->period > b->period) ||
+ ((a->period == b->period) && (a->julian > b->julian)) ||
+ ((a->period == b->period) && (a->julian == b->julian) && a->usec > b->usec))
+ {
+ return 1;
+ }
+ else
+ return -1;
+}
+
+/**
+ * g_date_time_copy:
+ * @datetime: a #GDateTime
+ *
+ * Creates a copy of @datetime.
+ *
+ * Return value: the newly created #GDateTime which should be freed with
+ * g_date_time_unref().
+ *
+ * Since: 2.26
+ */
+GDateTime*
+g_date_time_copy (const GDateTime *datetime)
+{
+ GDateTime *copied;
+
+ g_return_val_if_fail (datetime != NULL, NULL);
+
+ copied = g_date_time_new ();
+ copied->period = datetime->period;
+ copied->julian = datetime->julian;
+ copied->usec = datetime->usec;
+ copied->tz = g_time_zone_copy (datetime->tz);
+
+ return copied;
+}
+
+/**
+ * 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;
+
+ g_return_val_if_fail (datetime != NULL, NULL);
+
+ date = g_date_time_copy (datetime);
+ date->usec = 0;
+
+ return date;
+}
+
+/**
+ * g_date_time_difference:
+ * @begin: a #GDateTime
+ * @end: 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.
+ *
+ * Return value: the difference between the two #GDateTime, as a time
+ * span expressed in microseconds.
+ *
+ * Since: 2.26
+ */
+GTimeSpan
+g_date_time_difference (const GDateTime *begin,
+ const GDateTime *end)
+{
+ g_return_val_if_fail (begin != NULL, 0);
+ g_return_val_if_fail (end != NULL, 0);
+
+ if (begin->period != 0 || end->period != 0)
+ {
+ g_warning ("GDateTime only supports the current Julian period");
+ return 0;
+ }
+
+ return ((end->julian - begin->julian) * USEC_PER_DAY) + (end->usec - begin->usec);
+}
+
+/**
+ * g_date_time_equal:
+ * @dt1: a #GDateTime
+ * @dt2: a #GDateTime
+ *
+ * Checks to see if @dt1 and @dt2 are equal.
+ *
+ * Equal here means that they represent the same moment after converting
+ * them to the same timezone.
+ *
+ * Return value: %TRUE if @dt1 and @dt2 are equal
+ *
+ * Since: 2.26
+ */
+gboolean
+g_date_time_equal (gconstpointer dt1,
+ gconstpointer dt2)
+{
+ 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 ((GDateTime *) a);
+ b_utc = g_date_time_to_utc ((GDateTime *) 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;
+}
+
+/**
+ * g_date_time_get_day_of_week:
+ * @datetime: a #GDateTime
+ *
+ * Retrieves the day of the week represented by @datetime within the gregorian
+ * calendar. 1 is Sunday, 2 is Monday, etc.
+ *
+ * Return value: the day of the week
+ *
+ * Since: 2.26
+ */
+gint
+g_date_time_get_day_of_week (const GDateTime *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;
+}
+
+/**
+ * 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
+ *
+ * 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
+ *
+ * Retrieves the day of the year represented by @datetime in the Gregorian
+ * calendar.
+ *
+ * Return value: the day of the year
+ *
+ * Since: 2.26
+ */
+gint
+g_date_time_get_day_of_year (const GDateTime *datetime)
+{
+ gint doy = 0;
+
+ g_return_val_if_fail (datetime != NULL, 0);
+
+ g_date_time_get_week_number (datetime, NULL, NULL, &doy);
+ return doy;
+}
+
+/**
+ * g_date_time_get_dmy:
+ * @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.
+ *
+ * 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)
+{
+ gint a, b, c, d, e, m;
+
+ a = datetime->julian + 32044;
+ b = ((4 * a) + 3) / 146097;
+ c = a - ((b * 146097) / 4);
+ d = ((4 * c) + 3) / 1461;
+ e = c - (1461 * d) / 4;
+ m = (5 * e + 2) / 153;
+
+ if (day != NULL)
+ *day = e - (((153 * m) + 2) / 5) + 1;
+
+ if (month != NULL)
+ *month = m + 3 - (12 * (m / 10));
+
+ if (year != NULL)
+ *year = (b * 100) + d - 4800 + (m / 10);
+}
+
+/**
+ * g_date_time_get_hour:
+ * @datetime: a #GDateTime
+ *
+ * Retrieves the hour of the day represented by @datetime
+ *
+ * Return value: the hour of the day
+ *
+ * Since: 2.26
+ */
+gint
+g_date_time_get_hour (const GDateTime *datetime)
+{
+ g_return_val_if_fail (datetime != NULL, 0);
+
+ return (datetime->usec / USEC_PER_HOUR);
+}
+
+/**
+ * g_date_time_get_julian:
+ * @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.
+ *
+ * Since: 2.26
+ */
+void
+g_date_time_get_julian (const GDateTime *datetime,
+ gint *period,
+ gint *julian,
+ gint *hour,
+ gint *minute,
+ gint *second)
+{
+ g_return_if_fail (datetime != NULL);
+
+ if (period)
+ *period = datetime->period;
+
+ if (julian)
+ *julian = datetime->julian;
+
+ if (hour)
+ *hour = (datetime->usec / USEC_PER_HOUR);
+
+ if (minute)
+ *minute = (datetime->usec % USEC_PER_HOUR) / USEC_PER_MINUTE;
+
+ if (second)
+ *second = (datetime->usec % USEC_PER_MINUTE) / USEC_PER_SECOND;
+}
+
+/**
+ * g_date_time_get_microsecond:
+ * @datetime: a #GDateTime
+ *
+ * Retrieves the microsecond of the date represented by @datetime
+ *
+ * Return value: the microsecond of the second
+ *
+ * Since: 2.26
+ */
+gint
+g_date_time_get_microsecond (const GDateTime *datetime)
+{
+ g_return_val_if_fail (datetime != NULL, 0);
+
+ return (datetime->usec % USEC_PER_SECOND);
+}
+
+/**
+ * g_date_time_get_millisecond:
+ * @datetime: a #GDateTime
+ *
+ * Retrieves the millisecond of the date represented by @datetime
+ *
+ * Return value: the millisecond of the second
+ *
+ * Since: 2.26
+ */
+gint
+g_date_time_get_millisecond (const GDateTime *datetime)
+{
+ g_return_val_if_fail (datetime != NULL, 0);
+
+ return (datetime->usec % USEC_PER_SECOND) / USEC_PER_MILLISECOND;
+}
+
+/**
+ * g_date_time_get_minute:
+ * @datetime: a #GDateTime
+ *
+ * Retrieves the minute of the hour represented by @datetime
+ *
+ * Return value: the minute of the hour
+ *
+ * Since: 2.26
+ */
+gint
+g_date_time_get_minute (const GDateTime *datetime)
+{
+ g_return_val_if_fail (datetime != NULL, 0);
+
+ return (datetime->usec % USEC_PER_HOUR) / USEC_PER_MINUTE;
+}
+
+/**
+ * g_date_time_get_month:
+ * @datetime: a #GDateTime
+ *
+ * Retrieves the month of the year represented by @datetime in the Gregorian
+ * calendar.
+ *
+ * Return value: the month represented by @datetime
+ *
+ * Since: 2.26
+ */
+gint
+g_date_time_get_month (const GDateTime *datetime)
+{
+ gint month;
+
+ g_return_val_if_fail (datetime != NULL, 0);
+
+ g_date_time_get_dmy (datetime, NULL, &month, NULL);
+
+ return month;
+}
+
+/**
+ * g_date_time_get_second:
+ * @datetime: a #GDateTime
+ *
+ * Retrieves the second of the minute represented by @datetime
+ *
+ * Return value: the second represented by @datetime
+ *
+ * Since: 2.26
+ */
+gint
+g_date_time_get_second (const GDateTime *datetime)
+{
+ g_return_val_if_fail (datetime != NULL, 0);
+
+ return (datetime->usec % USEC_PER_MINUTE) / USEC_PER_SECOND;
+}
+
+/**
+ * g_date_time_get_utc_offset:
+ * @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.
+ *
+ * Return value: the offset, expressed as a time span expressed in
+ * microseconds.
+ *
+ * Since: 2.26
+ */
+GTimeSpan
+g_date_time_get_utc_offset (const GDateTime *datetime)
+{
+ gint offset = 0;
+
+ g_return_val_if_fail (datetime != NULL, 0);
+
+ if (datetime->tz != NULL)
+ offset = datetime->tz->offset;
+
+ return (gint64) offset * USEC_PER_SECOND;
+}
+
+/**
+ * g_date_time_get_timezone_name:
+ * @datetime: a #GDateTime
+ *
+ * Retrieves the Olson's database timezone name of the timezone specified
+ * 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
+ *
+ * Since: 2.26
+ */
+G_CONST_RETURN gchar *
+g_date_time_get_timezone_name (const GDateTime *datetime)
+{
+ g_return_val_if_fail (datetime != NULL, NULL);
+
+ if (datetime->tz != NULL)
+ return datetime->tz->name;
+
+ return "UTC";
+}
+
+/**
+ * g_date_time_get_year:
+ * @datetime: A #GDateTime
+ *
+ * Retrieves the year represented by @datetime in the Gregorian calendar.
+ *
+ * Return value: the year represented by @datetime
+ *
+ * Since: 2.26
+ */
+gint
+g_date_time_get_year (const GDateTime *datetime)
+{
+ gint year;
+
+ g_return_val_if_fail (datetime != NULL, 0);
+
+ g_date_time_get_dmy (datetime, NULL, NULL, &year);
+
+ return year;
+}
+
+/**
+ * g_date_time_hash:
+ * @datetime: a #GDateTime
+ *
+ * Hashes @datetime into a #guint, suitable for use within #GHashTable.
+ *
+ * Return value: a #guint containing the hash
+ *
+ * Since: 2.26
+ */
+guint
+g_date_time_hash (gconstpointer datetime)
+{
+ return (guint) (*((guint64 *) datetime));
+}
+
+/**
+ * g_date_time_is_leap_year:
+ * @datetime: a #GDateTime
+ *
+ * Determines if @datetime represents a date known to fall within
+ * a leap year in the Gregorian calendar.
+ *
+ * Return value: %TRUE if @datetime is a leap year.
+ *
+ * Since: 2.26
+ */
+gboolean
+g_date_time_is_leap_year (const GDateTime *datetime)
+{
+ gint year;
+
+ g_return_val_if_fail (datetime != NULL, FALSE);
+
+ year = g_date_time_get_year (datetime);
+
+ return GREGORIAN_LEAP (year);
+}
+
+/**
+ * g_date_time_is_daylight_savings:
+ * @datetime: a #GDateTime
+ *
+ * Determines if @datetime represents a date known to fall within daylight
+ * savings time in the gregorian calendar.
+ *
+ * Return value: %TRUE if @datetime falls within daylight savings time.
+ *
+ * Since: 2.26
+ */
+gboolean
+g_date_time_is_daylight_savings (const GDateTime *datetime)
+{
+ g_return_val_if_fail (datetime != NULL, FALSE);
+
+ if (!datetime->tz)
+ return FALSE;
+
+ return datetime->tz->is_dst;
+}
+
+static inline gint
+date_to_julian (gint year,
+ gint month,
+ gint day)
+{
+ gint a = (14 - month) / 12;
+ gint y = year + 4800 - a;
+ gint m = month + (12 * a) - 3;
+
+ return day
+ + (((153 * m) + 2) / 5)
+ + (y * 365)
+ + (y / 4)
+ - (y / 100)
+ + (y / 400)
+ - 32045;
+}
+
+/**
+ * g_date_time_new_from_date:
+ * @year: the Gregorian year
+ * @month: the Gregorian month
+ * @day: the day in the Gregorian month
+ *
+ * Creates a new #GDateTime using the specified date within the Gregorian
+ * calendar.
+ *
+ * Return value: the newly created #GDateTime or %NULL if it is outside of
+ * the representable range.
+ *
+ * Since: 2.26
+ */
+GDateTime *
+g_date_time_new_from_date (gint year,
+ gint month,
+ gint day)
+{
+ 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->julian = date_to_julian (year, month, day);
+ dt->tz = g_date_time_create_time_zone (dt, NULL);
+
+ return dt;
+}
+
+/**
+ * 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.
+ *
+ * Return value: the newly created #GDateTime
+ *
+ * Since: 2.26
+ */
+GDateTime*
+g_date_time_new_from_epoch (gint64 t) /* IN */
+{
+ 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 (&timet);
+
+ 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 */
+
+ return 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,
+ NULL);
+}
+
+/**
+ * g_date_time_new_from_timeval:
+ * @tv: #GTimeVal
+ *
+ * Creates a new #GDateTime using the date and time specified by #GTimeVal.
+ *
+ * Return value: the newly created #GDateTime
+ *
+ * Since: 2.26
+ */
+GDateTime *
+g_date_time_new_from_timeval (GTimeVal *tv)
+{
+ 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_date_time_create_time_zone (datetime, NULL);
+
+ return 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
+ * @timezone: (allow-none): the Olson's database timezone name, or %NULL
+ * for local (e.g. America/New_York)
+ *
+ * Creates a new #GDateTime using the date and times in the Gregorian calendar.
+ *
+ * Return value: the newly created #GDateTime
+ *
+ * Since: 2.26
+ */
+GDateTime *
+g_date_time_new_full (gint year,
+ gint month,
+ gint day,
+ gint hour,
+ gint minute,
+ gint second,
+ const gchar *timezone)
+{
+ 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 && second <= 60, NULL);
+
+ if ((dt = g_date_time_new_from_date (year, month, day)) == NULL)
+ return NULL;
+
+ dt->usec = (hour * USEC_PER_HOUR)
+ + (minute * USEC_PER_MINUTE)
+ + (second * USEC_PER_SECOND);
+
+ dt->tz = g_date_time_create_time_zone (dt, timezone);
+ if (timezone != NULL && dt->tz == NULL)
+ {
+ /* timezone creation failed */
+ g_date_time_unref (dt);
+ dt = NULL;
+ }
+
+ return dt;
+}
+
+/**
+ * g_date_time_new_now:
+ *
+ * Creates a new #GDateTime representing the current date and time.
+ *
+ * Return value: the newly created #GDateTime which should be freed with
+ * g_date_time_unref().
+ *
+ * Since: 2.26
+ */
+GDateTime*
+g_date_time_new_now (void)
+{
+ GTimeVal tv;
+
+ g_get_current_time (&tv);
+
+ return g_date_time_new_from_timeval (&tv);
+}
+
+/**
+ * g_date_time_printf:
+ * @datetime: A #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 date.
+ * %%X The preferred date representation for the current locale without
+ * the time.
+ * %%y The year as a decimal number without the century.
+ * %%Y The year as a decimal number including the century.
+ * %%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().
+ *
+ * Since: 2.26
+ */
+gchar *
+g_date_time_printf (const GDateTime *datetime,
+ const gchar *format)
+{
+ GString *outstr;
+ const gchar *tmp;
+ gchar *tmp2,
+ c;
+ glong utf8len;
+ gint i;
+ gboolean in_mod;
+
+ g_return_val_if_fail (datetime != NULL, NULL);
+ g_return_val_if_fail (format != NULL, NULL);
+ g_return_val_if_fail (g_utf8_validate (format, -1, NULL), NULL);
+
+ outstr = g_string_sized_new (strlen (format) * 2);
+ utf8len = g_utf8_strlen (format, -1);
+ in_mod = FALSE;
+
+ for (i = 0; i < utf8len; i++)
+ {
+ tmp = g_utf8_offset_to_pointer (format, i);
+ c = g_utf8_get_char (tmp);
+
+ switch (c) {
+ case '%':
+ if (!in_mod)
+ {
+ in_mod = TRUE;
+ break;
+ }
+ /* Fall through */
+ default:
+ if (in_mod)
+ {
+ switch (c) {
+ case 'a':
+ g_string_append (outstr, WEEKDAY_ABBR (datetime));
+ break;
+ case 'A':
+ g_string_append (outstr, WEEKDAY_FULL (datetime));
+ break;
+ case 'b':
+ g_string_append (outstr, MONTH_ABBR (datetime));
+ break;
+ case 'B':
+ g_string_append (outstr, MONTH_FULL (datetime));
+ break;
+ case 'd':
+ g_string_append_printf (outstr, "%02d",
+ g_date_time_get_day_of_month (datetime));
+ break;
+ case 'e':
+ g_string_append_printf (outstr, "%2d",
+ g_date_time_get_day_of_month (datetime));
+ break;
+ case 'F':
+ g_string_append_printf (outstr, "%d-%02d-%02d",
+ g_date_time_get_year (datetime),
+ g_date_time_get_month (datetime),
+ g_date_time_get_day_of_month (datetime));
+ break;
+ case 'h':
+ g_string_append (outstr, MONTH_ABBR (datetime));
+ break;
+ case 'H':
+ g_string_append_printf (outstr, "%02d",
+ g_date_time_get_hour (datetime));
+ break;
+ case 'I':
+ if (g_date_time_get_hour (datetime) == 0)
+ g_string_append (outstr, "12");
+ else
+ g_string_append_printf (outstr, "%02d",
+ g_date_time_get_hour (datetime) % 12);
+ break;
+ case 'j':
+ g_string_append_printf (outstr, "%03d",
+ g_date_time_get_day_of_year (datetime));
+ break;
+ case 'k':
+ g_string_append_printf (outstr, "%2d",
+ g_date_time_get_hour (datetime));
+ break;
+ case 'l':
+ if (g_date_time_get_hour (datetime) == 0)
+ g_string_append (outstr, "12");
+ else
+ g_string_append_printf (outstr, "%2d",
+ g_date_time_get_hour (datetime) % 12);
+ break;
+ case 'm':
+ g_string_append_printf (outstr, "%02d",
+ g_date_time_get_month (datetime));
+ break;
+ case 'M':
+ g_string_append_printf (outstr, "%02d",
+ g_date_time_get_minute (datetime));
+ break;
+ case 'N':
+ g_string_append_printf (outstr, "%"G_GUINT64_FORMAT,
+ datetime->usec % USEC_PER_SECOND);
+ break;
+ case 'p':
+ g_string_append (outstr, GET_AMPM (datetime, FALSE));
+ break;
+ case 'P':
+ g_string_append (outstr, GET_AMPM (datetime, TRUE));
+ break;
+ case 'r': {
+ gint hour = g_date_time_get_hour (datetime) % 12;
+ if (hour == 0)
+ hour = 12;
+ g_string_append_printf (outstr, "%02d:%02d:%02d %s",
+ hour,
+ g_date_time_get_minute (datetime),
+ g_date_time_get_second (datetime),
+ GET_AMPM (datetime, FALSE));
+ break;
+ }
+ case 'R':
+ g_string_append_printf (outstr, "%02d:%02d",
+ g_date_time_get_hour (datetime),
+ g_date_time_get_minute (datetime));
+ break;
+ case 's':
+ g_string_append_printf (outstr, "%" G_GINT64_FORMAT,
+ g_date_time_to_epoch (datetime));
+ break;
+ case 'S':
+ g_string_append_printf (outstr, "%02d",
+ g_date_time_get_second (datetime));
+ break;
+ case 't':
+ g_string_append_c (outstr, '\t');
+ break;
+ case 'u':
+ g_string_append_printf (outstr, "%d",
+ g_date_time_get_day_of_week (datetime));
+ break;
+ case 'W':
+ g_string_append_printf (outstr, "%d",
+ g_date_time_get_day_of_year (datetime) / 7);
+ break;
+ case 'x': {
+ tmp2 = GET_PREFERRED_DATE (datetime);
+ g_string_append (outstr, tmp2);
+ g_free (tmp2);
+ break;
+ }
+ case 'X': {
+ tmp2 = GET_PREFERRED_TIME (datetime);
+ g_string_append (outstr, tmp2);
+ g_free (tmp2);
+ break;
+ }
+ case 'y':
+ g_string_append_printf (outstr, "%02d",
+ g_date_time_get_year (datetime) % 100);
+ break;
+ case 'Y':
+ g_string_append_printf (outstr, "%d",
+ g_date_time_get_year (datetime));
+ break;
+ case 'z':
+ if (datetime->tz)
+ g_string_append_printf (outstr, "%s", datetime->tz->name);
+ else
+ g_string_append_printf (outstr, "UTC");
+ break;
+ case '%':
+ g_string_append_c (outstr, '%');
+ break;
+ case 'n':
+ g_string_append_c (outstr, '\n');
+ break;
+ default:
+ goto bad_format;
+ }
+ in_mod = FALSE;
+ }
+ else
+ g_string_append_unichar (outstr, c);
+ }
+ }
+
+ tmp = outstr->str;
+ g_string_free (outstr, FALSE);
+
+ return (gchar*)tmp;
+
+bad_format:
+ g_string_free (outstr, TRUE);
+ return NULL;
+}
+
+/**
+ * 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)
+{
+ g_return_val_if_fail (datetime != NULL, NULL);
+ g_return_val_if_fail (datetime->ref_count > 0, NULL);
+
+ g_atomic_int_inc (&datetime->ref_count);
+
+ return datetime;
+}
+
+/**
+ * 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)
+{
+ 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);
+}
+
+/**
+ * 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;
+ gint offset,
+ year;
+ gint64 usec;
+
+ g_return_val_if_fail (datetime != NULL, NULL);
+
+ dt = g_date_time_copy (datetime);
+
+ if (!dt->tz)
+ {
+ year = g_date_time_get_year (dt);
+ dt->tz = g_date_time_create_time_zone (dt, NULL);
+
+ offset = dt->tz->offset;
+
+ usec = offset * USEC_PER_SECOND;
+ ADD_USEC (dt, usec);
+ }
+
+ 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)
+{
+ struct tm tm;
+ gint year,
+ month,
+ day;
+
+ g_return_val_if_fail (datetime != NULL, 0);
+ g_return_val_if_fail (datetime->period == 0, 0);
+
+ g_date_time_get_dmy (datetime, &day, &month, &year);
+
+ /* FIXME we use gint64, we shold expand these limits */
+ if (year < 1970)
+ return 0;
+ else if (year > 2037)
+ return G_MAXINT64;
+
+ memset (&tm, 0, sizeof (tm));
+
+ tm.tm_year = year - 1900;
+ tm.tm_mon = month - 1;
+ tm.tm_mday = day;
+ tm.tm_hour = g_date_time_get_hour (datetime);
+ tm.tm_min = g_date_time_get_minute (datetime);
+ tm.tm_sec = g_date_time_get_second (datetime);
+ tm.tm_isdst = -1;
+
+ return (gint64) mktime (&tm);
+}
+
+/**
+ * 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);
+
+ tv->tv_sec = 0;
+ tv->tv_usec = 0;
+
+ if (G_LIKELY (datetime->period == 0))
+ {
+ 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);
+ 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;
+}
diff --git a/glib/gdatetime.h b/glib/gdatetime.h
new file mode 100644
index 0000000..5ed2e8c
--- /dev/null
+++ b/glib/gdatetime.h
@@ -0,0 +1,190 @@
+/* gdatetime.h
+ *
+ * Copyright (C) 2009-2010 Christian Hergert <chris dronelabs com>
+ *
+ * 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 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
+ */
+
+#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#ifndef __G_DATE_TIME_H__
+#define __G_DATE_TIME_H__
+
+#include <time.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+/**
+ * G_TIME_SPAN_DAY:
+ *
+ * Evaluates to a time span of one day.
+ *
+ * Since: 2.26
+ */
+#define G_TIME_SPAN_DAY (G_GINT64_CONSTANT (86400000000))
+
+/**
+ * G_TIME_SPAN_HOUR:
+ *
+ * Evaluates to a time span of one hour.
+ *
+ * Since: 2.26
+ */
+#define G_TIME_SPAN_HOUR (G_GINT64_CONSTANT (3600000000))
+
+/**
+ * G_TIME_SPAN_MINUTE:
+ *
+ * Evaluates to a time span of one minute.
+ *
+ * Since: 2.26
+ */
+#define G_TIME_SPAN_MINUTE (G_GINT64_CONSTANT (60000000))
+
+/**
+ * G_TIME_SPAN_SECOND:
+ *
+ * Evaluates to a time span of one second.
+ *
+ * Since: 2.26
+ */
+#define G_TIME_SPAN_SECOND (G_GINT64_CONSTANT (1000000))
+
+/**
+ * G_TIME_SPAN_MILLISECOND:
+ *
+ * Evaluates to a time span of one millisecond.
+ *
+ * Since: 2.26
+ */
+#define G_TIME_SPAN_MILLISECOND (G_GINT64_CONSTANT (1000))
+
+/**
+ * GDateTime:
+ *
+ * <structname>GDateTime</structname> is an opaque structure whose members
+ * cannot be accessed directly.
+ *
+ * Since: 2.26
+ */
+typedef struct _GDateTime GDateTime;
+
+/**
+ * GTimeSpan:
+ *
+ * A value representing an interval of time, in microseconds.
+ *
+ * Since: 2.26
+ */
+typedef gint64 GTimeSpan;
+
+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,
+ gint second,
+ const gchar *timezone);
+
+GDateTime * g_date_time_copy (const GDateTime *datetime);
+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_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_leap_year (const GDateTime *datetime);
+gboolean g_date_time_is_daylight_savings (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_printf (const GDateTime *datetime,
+ const gchar *format) G_GNUC_MALLOC;
+
+G_END_DECLS
+
+#endif /* __G_DATE_TIME_H__ */
diff --git a/glib/glib.h b/glib/glib.h
index e07ec82..cec8f32 100644
--- a/glib/glib.h
+++ b/glib/glib.h
@@ -43,6 +43,7 @@
#include <glib/gconvert.h>
#include <glib/gdataset.h>
#include <glib/gdate.h>
+#include <glib/gdatetime.h>
#include <glib/gdir.h>
#include <glib/gerror.h>
#include <glib/gfileutils.h>
diff --git a/glib/glib.symbols b/glib/glib.symbols
index e3421f1..41e133a 100644
--- a/glib/glib.symbols
+++ b/glib/glib.symbols
@@ -323,6 +323,57 @@ g_date_valid_year G_GNUC_CONST
#endif
#endif
+#if IN_HEADER(__G_DATE_TIME_H__)
+#if IN_FILE(__G_DATE_TIME_C__)
+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_copy
+g_date_time_day
+g_date_time_difference
+g_date_time_equal
+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_utc_offset
+g_date_time_get_year
+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_now
+g_date_time_new_today
+g_date_time_new_utc_now
+g_date_time_printf G_GNUC_MALLOC
+g_date_time_ref
+g_date_time_to_local
+g_date_time_to_epoch
+g_date_time_to_timeval
+g_date_time_to_utc
+g_date_time_unref
+#endif
+#endif
+
#if IN_HEADER(__G_DIR_H__)
#if IN_FILE(__G_DIR_C__)
g_dir_close
diff --git a/glib/tests/.gitignore b/glib/tests/.gitignore
index bcb168a..a2c75e7 100644
--- a/glib/tests/.gitignore
+++ b/glib/tests/.gitignore
@@ -8,6 +8,7 @@ date
dir
error
fileutils
+gdatetime
gvariant
hash
hostutils
diff --git a/glib/tests/Makefile.am b/glib/tests/Makefile.am
index bd200dc..0d54cae 100644
--- a/glib/tests/Makefile.am
+++ b/glib/tests/Makefile.am
@@ -9,7 +9,6 @@ INCLUDES = \
noinst_PROGRAMS = $(TEST_PROGS)
progs_ldadd = $(top_builddir)/glib/libglib-2.0.la
-
TEST_PROGS += testing
testing_SOURCES = testing.c
testing_LDADD = $(progs_ldadd)
@@ -145,6 +144,10 @@ error_LDADD = $(progs_ldadd)
TEST_PROGS += bookmarkfile
bookmarkfile_LDADD = $(progs_ldadd)
+TEST_PROGS += gdatetime
+gdatetime_SOURCES = gdatetime.c
+gdatetime_LDADD = $(progs_ldadd)
+
if OS_UNIX
# some testing of gtester funcitonality
diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c
new file mode 100644
index 0000000..ae8ef3a
--- /dev/null
+++ b/glib/tests/gdatetime.c
@@ -0,0 +1,962 @@
+/* gdatetime-tests.c
+ *
+ * Copyright (C) 2009-2010 Christian Hergert <chris dronelabs com>
+ *
+ * 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 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
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <time.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#define ASSERT_DATE(dt,y,m,d) G_STMT_START { \
+ g_assert_cmpint ((y), ==, g_date_time_get_year ((dt))); \
+ g_assert_cmpint ((m), ==, g_date_time_get_month ((dt))); \
+ g_assert_cmpint ((d), ==, g_date_time_get_day_of_month ((dt))); \
+} G_STMT_END
+#define ASSERT_TIME(dt,H,M,S) G_STMT_START { \
+ g_assert_cmpint ((H), ==, g_date_time_get_hour ((dt))); \
+ g_assert_cmpint ((M), ==, g_date_time_get_minute ((dt))); \
+ g_assert_cmpint ((S), ==, g_date_time_get_second ((dt))); \
+} G_STMT_END
+
+static void
+get_localtime_tm (time_t time_,
+ struct tm *retval)
+{
+#ifdef HAVE_LOCALTIME_R
+ localtime_r (&time_, retval);
+#else
+ {
+ struct tm *ptm = localtime (&time_);
+
+ 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 *) retval, (void *) ptm, sizeof (struct tm));
+ }
+#endif /* HAVE_LOCALTIME_R */
+}
+
+static void
+test_GDateTime_now (void)
+{
+ GDateTime *dt;
+ struct tm tm;
+
+ memset (&tm, 0, sizeof (tm));
+ get_localtime_tm (time (NULL), &tm);
+
+ dt = g_date_time_new_now ();
+ 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), ==, tm.tm_hour);
+ g_assert_cmpint (g_date_time_get_minute (dt), ==, tm.tm_min);
+ g_assert_cmpint (g_date_time_get_second (dt), ==, tm.tm_sec);
+ g_date_time_unref (dt);
+}
+
+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)
+{
+ GDateTime *dt;
+ struct tm tm;
+ time_t t;
+
+ memset (&tm, 0, sizeof (tm));
+ t = time (NULL);
+ get_localtime_tm (t, &tm);
+
+ dt = g_date_time_new_from_epoch (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);
+ g_assert_cmpint (g_date_time_get_hour (dt), ==, tm.tm_hour);
+ g_assert_cmpint (g_date_time_get_minute (dt), ==, tm.tm_min);
+ g_assert_cmpint (g_date_time_get_second (dt), ==, tm.tm_sec);
+ g_date_time_unref (dt);
+
+ memset (&tm, 0, sizeof (tm));
+ tm.tm_year = 70;
+ tm.tm_mday = 1;
+ tm.tm_mon = 0;
+ tm.tm_hour = 0;
+ tm.tm_min = 0;
+ tm.tm_sec = 0;
+ t = mktime (&tm);
+
+ dt = g_date_time_new_from_epoch (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);
+ 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_date_time_unref (dt);
+}
+
+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);
+
+ for (i = 1; i < 2000; i++)
+ {
+ dt2 = g_date_time_new_from_date (i, 12, 31);
+ 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);
+ 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);
+ 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);
+ g_assert_cmpint (0, ==, g_date_time_compare (dt1, dt2));
+ g_date_time_unref (dt2);
+
+ g_date_time_unref (dt1);
+}
+
+static void
+test_GDateTime_copy (void)
+{
+ GDateTime *dt1, *dt2;
+
+ dt1 = g_date_time_new_now ();
+ dt2 = g_date_time_copy (dt1);
+ g_assert (dt1 != NULL);
+ g_assert (dt2 != NULL);
+ g_assert_cmpint (0, ==, g_date_time_compare (dt1, dt2));
+ g_date_time_unref (dt1);
+ g_date_time_unref (dt2);
+}
+
+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;
+
+ dt1 = g_date_time_new_from_date (2009, 10, 19);
+ dt2 = g_date_time_new_from_date (2009, 10, 19);
+ 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);
+ g_assert (!g_date_time_equal (dt1, dt2));
+ g_date_time_unref (dt1);
+ g_date_time_unref (dt2);
+
+ /* America/Recife is GMT-3 and is not in DST for this time */
+ dt1 = g_date_time_new_full (2010, 5, 24, 8, 0, 0, "America/Recife");
+ dt2 = g_date_time_new_full (2010, 5, 24, 11, 0, 0, "UTC");
+ g_assert (g_date_time_equal (dt1, dt2));
+ g_date_time_unref (dt1);
+ g_date_time_unref (dt2);
+}
+
+static void
+test_GDateTime_get_day_of_week (void)
+{
+ GDateTime *dt;
+
+ dt = g_date_time_new_from_date (2009, 10, 19);
+ 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);
+ g_assert_cmpint (7, ==, g_date_time_get_day_of_week (dt));
+ g_date_time_unref (dt);
+}
+
+static void
+test_GDateTime_get_day_of_month (void)
+{
+ GDateTime *dt;
+
+ dt = g_date_time_new_from_date (2009, 10, 19);
+ 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);
+ 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);
+ 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);
+ g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, 1);
+ g_date_time_unref (dt);
+}
+
+static void
+test_GDateTime_get_dmy (void)
+{
+ GDateTime *dt;
+ struct tm tm;
+ time_t t;
+ gint d, m, y;
+
+ t = time (NULL);
+ 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);
+ g_assert_cmpint(y, ==, tm.tm_year + 1900);
+ g_assert_cmpint(m, ==, tm.tm_mon + 1);
+ g_assert_cmpint(d, ==, tm.tm_mday);
+}
+
+static void
+test_GDateTime_get_hour (void)
+{
+ GDateTime *dt;
+
+ dt = g_date_time_new_full (2009, 10, 19, 15, 13, 11, NULL);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+}
+
+static void
+test_GDateTime_get_year (void)
+{
+ GDateTime *dt;
+
+ dt = g_date_time_new_from_date (2009, 1, 1);
+ 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);
+ 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);
+ 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);
+ g_assert_cmpint (3000, ==, g_date_time_get_year (dt));
+ g_date_time_unref (dt);
+}
+
+static void
+test_GDateTime_hash (void)
+{
+ GHashTable *h;
+
+ 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_remove_all (h);
+ g_hash_table_destroy (h);
+}
+
+static void
+test_GDateTime_new_from_timeval (void)
+{
+ GDateTime *dt;
+ GTimeVal tv, tv2;
+
+ g_get_current_time (&tv);
+ dt = g_date_time_new_from_timeval (&tv);
+ g_date_time_to_timeval (dt, &tv2);
+ g_assert_cmpint (tv.tv_sec, ==, tv2.tv_sec);
+ g_assert_cmpint (tv.tv_usec, ==, tv2.tv_usec);
+ g_date_time_unref (dt);
+}
+
+static void
+test_GDateTime_to_epoch (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);
+ g_date_time_unref (dt);
+}
+
+static void
+test_GDateTime_add_years (void)
+{
+ GDateTime *dt, *dt2;
+
+ dt = g_date_time_new_from_date (2009, 10, 19);
+ dt2 = g_date_time_add_years (dt, 1);
+ g_assert_cmpint (2010, ==, g_date_time_get_year (dt2));
+ g_date_time_unref (dt);
+ g_date_time_unref (dt2);
+}
+
+static void
+test_GDateTime_add_months (void)
+{
+#define TEST_ADD_MONTHS(y,m,d,a,ny,nm,nd) G_STMT_START { \
+ GDateTime *dt, *dt2; \
+ dt = g_date_time_new_from_date (y, m, d); \
+ dt2 = g_date_time_add_months (dt, a); \
+ ASSERT_DATE (dt2, ny, nm, nd); \
+ g_date_time_unref (dt); \
+ g_date_time_unref (dt2); \
+} G_STMT_END
+
+ TEST_ADD_MONTHS (2009, 12, 31, 1, 2010, 1, 31);
+ TEST_ADD_MONTHS (2009, 12, 31, 1, 2010, 1, 31);
+ TEST_ADD_MONTHS (2009, 6, 15, 1, 2009, 7, 15);
+ TEST_ADD_MONTHS (1400, 3, 1, 1, 1400, 4, 1);
+ TEST_ADD_MONTHS (1400, 1, 31, 1, 1400, 2, 28);
+ TEST_ADD_MONTHS (1400, 1, 31, 7200, 2000, 1, 31);
+ TEST_ADD_MONTHS (2008, 2, 29, 12, 2009, 2, 28);
+ TEST_ADD_MONTHS (2000, 8, 16, -5, 2000, 3, 16);
+ 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);
+}
+
+static void
+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); \
+ 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)); \
+ g_assert_cmpint (nd, ==, g_date_time_get_day_of_month (dt2)); \
+ g_date_time_unref (dt); \
+ g_date_time_unref (dt2); \
+} G_STMT_END
+
+ TEST_ADD_DAYS (2009, 1, 31, 1, 2009, 2, 1);
+ TEST_ADD_DAYS (2009, 2, 1, -1, 2009, 1, 31);
+ TEST_ADD_DAYS (2008, 2, 28, 1, 2008, 2, 29);
+ TEST_ADD_DAYS (2008, 12, 31, 1, 2009, 1, 1);
+ TEST_ADD_DAYS (1, 1, 1, 1, 1, 1, 2);
+ TEST_ADD_DAYS (1955, 5, 24, 10, 1955, 6, 3);
+ TEST_ADD_DAYS (1955, 5, 24, -10, 1955, 5, 14);
+}
+
+static void
+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); \
+ 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)); \
+ g_assert_cmpint (nd, ==, g_date_time_get_day_of_month (dt2)); \
+ g_date_time_unref (dt); \
+ g_date_time_unref (dt2); \
+} G_STMT_END
+
+ TEST_ADD_WEEKS (2009, 1, 1, 1, 2009, 1, 8);
+ TEST_ADD_WEEKS (2009, 8, 30, 1, 2009, 9, 6);
+ TEST_ADD_WEEKS (2009, 12, 31, 1, 2010, 1, 7);
+ TEST_ADD_WEEKS (2009, 1, 1, -1, 2008, 12, 25);
+}
+
+static void
+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); \
+ 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)); \
+ g_assert_cmpint (nd, ==, g_date_time_get_day_of_month (dt2)); \
+ g_assert_cmpint (nh, ==, g_date_time_get_hour (dt2)); \
+ g_assert_cmpint (nmi, ==, g_date_time_get_minute (dt2)); \
+ g_assert_cmpint (ns, ==, g_date_time_get_second (dt2)); \
+ g_date_time_unref (dt); \
+ g_date_time_unref (dt2); \
+} G_STMT_END
+
+ TEST_ADD_HOURS (2009, 1, 1, 0, 0, 0, 1, 2009, 1, 1, 1, 0, 0);
+ TEST_ADD_HOURS (2008, 12, 31, 23, 0, 0, 1, 2009, 1, 1, 0, 0, 0);
+}
+
+static void
+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); \
+ 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)); \
+ g_assert_cmpint (nd, ==, g_date_time_get_day_of_month (dt2)); \
+ g_assert_cmpint (nh, ==, g_date_time_get_hour (dt2)); \
+ g_assert_cmpint (nmi, ==, g_date_time_get_minute (dt2)); \
+ g_assert_cmpint (ns, ==, g_date_time_get_second (dt2)); \
+ g_date_time_unref (dt); \
+ g_date_time_unref (dt2); \
+} G_STMT_END
+
+ TEST_ADD_FULL (2009, 10, 21, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1,
+ 2010, 11, 22, 1, 1, 1);
+ TEST_ADD_FULL (2000, 1, 1, 1, 1, 1,
+ 0, 1, 0, 0, 0, 0,
+ 2000, 2, 1, 1, 1, 1);
+ TEST_ADD_FULL (2000, 1, 1, 0, 0, 0,
+ -1, 1, 0, 0, 0, 0,
+ 1999, 2, 1, 0, 0, 0);
+}
+
+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); \
+ dt2 = g_date_time_add_minutes (dt, i); \
+ g_assert_cmpint (o, ==, g_date_time_get_minute (dt2)); \
+ g_date_time_unref (dt); \
+ g_date_time_unref (dt2); \
+} G_STMT_END
+
+ 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);
+}
+
+static void
+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); \
+ dt2 = g_date_time_add_seconds (dt, i); \
+ g_assert_cmpint (o, ==, g_date_time_get_second (dt2)); \
+ g_date_time_unref (dt); \
+ g_date_time_unref (dt2); \
+} G_STMT_END
+
+ TEST_ADD_SECONDS (1, 1);
+ TEST_ADD_SECONDS (60, 0);
+ TEST_ADD_SECONDS (61, 1);
+ TEST_ADD_SECONDS (120, 0);
+ TEST_ADD_SECONDS (-61, 59);
+ TEST_ADD_SECONDS (86401, 1);
+ TEST_ADD_SECONDS (-86401, 59);
+ TEST_ADD_SECONDS (-31, 29);
+ TEST_ADD_SECONDS (13, 13);
+}
+
+static void
+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); \
+ g_assert_cmpint (ts, ==, u); \
+ g_date_time_unref (dt1); \
+ g_date_time_unref (dt2); \
+} G_STMT_END
+
+ TEST_DIFF (2009, 1, 1, 2009, 2, 1, G_TIME_SPAN_DAY * 31);
+ TEST_DIFF (2009, 1, 1, 2010, 1, 1, G_TIME_SPAN_DAY * 365);
+ TEST_DIFF (2008, 2, 28, 2008, 2, 29, G_TIME_SPAN_DAY);
+ TEST_DIFF (2008, 2, 29, 2008, 2, 28, -G_TIME_SPAN_DAY);
+
+ /* TODO: Add usec tests */
+}
+
+static void
+test_GDateTime_get_minute (void)
+{
+ GDateTime *dt;
+
+ dt = g_date_time_new_full (2009, 12, 1, 1, 31, 0, NULL);
+ g_assert_cmpint (31, ==, g_date_time_get_minute (dt));
+ g_date_time_unref (dt);
+}
+
+static void
+test_GDateTime_get_month (void)
+{
+ GDateTime *dt;
+
+ dt = g_date_time_new_full (2009, 12, 1, 1, 31, 0, NULL);
+ g_assert_cmpint (12, ==, g_date_time_get_month (dt));
+ g_date_time_unref (dt);
+}
+
+static void
+test_GDateTime_get_second (void)
+{
+ GDateTime *dt;
+
+ dt = g_date_time_new_full (2009, 12, 1, 1, 31, 44, NULL);
+ 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)
+{
+ GDateTime *dt;
+
+ dt = g_date_time_new_full (2009, 12, 11, 12, 11, 10, NULL);
+ 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_assert_cmpint (12, ==, g_date_time_get_hour (dt));
+ g_assert_cmpint (11, ==, g_date_time_get_minute (dt));
+ g_assert_cmpint (10, ==, g_date_time_get_second (dt));
+ g_date_time_unref (dt);
+
+ dt = g_date_time_new_full (2010, 5, 24, 8, 4, 0, "America/Recife");
+ 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 (!g_date_time_is_daylight_savings (dt));
+ g_date_time_unref (dt);
+}
+
+static void
+test_GDateTime_utc_now (void)
+{
+ GDateTime *dt;
+ time_t t;
+ struct tm tm;
+
+ t = time (NULL);
+ gmtime_r (&t, &tm);
+ dt = g_date_time_new_utc_now ();
+ 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));
+ g_assert_cmpint (tm.tm_hour, ==, g_date_time_get_hour (dt));
+ g_assert_cmpint (tm.tm_min, ==, g_date_time_get_minute (dt));
+ g_assert_cmpint (tm.tm_sec, ==, g_date_time_get_second (dt));
+ g_date_time_unref (dt);
+}
+
+static void
+test_GDateTime_get_utc_offset (void)
+{
+ GDateTime *dt;
+ GTimeSpan ts;
+ struct tm tm;
+
+ memset (&tm, 0, sizeof (tm));
+ get_localtime_tm (time (NULL), &tm);
+
+ dt = g_date_time_new_now ();
+ ts = g_date_time_get_utc_offset (dt);
+ g_assert_cmpint (ts, ==, (tm.tm_gmtoff * G_TIME_SPAN_SECOND));
+ g_date_time_unref (dt);
+}
+
+static void
+test_GDateTime_to_timeval (void)
+{
+ GTimeVal tv1, tv2;
+ GDateTime *dt;
+
+ memset (&tv1, 0, sizeof (tv1));
+ memset (&tv2, 0, sizeof (tv2));
+
+ g_get_current_time (&tv1);
+ dt = g_date_time_new_from_timeval (&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);
+ g_date_time_unref (dt);
+}
+
+static void
+test_GDateTime_to_local (void)
+{
+ GDateTime *utc, *now, *dt;
+
+ utc = g_date_time_new_utc_now ();
+ now = g_date_time_new_now ();
+ dt = g_date_time_to_local (utc);
+
+ g_assert_cmpint (g_date_time_get_year (now), ==, g_date_time_get_year (dt));
+ g_assert_cmpint (g_date_time_get_month (now), ==, g_date_time_get_month (dt));
+ g_assert_cmpint (g_date_time_get_day_of_month (now), ==, g_date_time_get_day_of_month (dt));
+ g_assert_cmpint (g_date_time_get_hour (now), ==, g_date_time_get_hour (dt));
+ g_assert_cmpint (g_date_time_get_minute (now), ==, g_date_time_get_minute (dt));
+ g_assert_cmpint (g_date_time_get_second (now), ==, g_date_time_get_second (dt));
+
+ g_date_time_unref (now);
+ g_date_time_unref (utc);
+ g_date_time_unref (dt);
+}
+
+static void
+test_GDateTime_to_utc (void)
+{
+ GDateTime *dt, *dt2;
+ time_t t;
+ struct tm tm;
+
+ t = time (NULL);
+ gmtime_r (&t, &tm);
+ dt2 = g_date_time_new_now ();
+ 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));
+ g_assert_cmpint (tm.tm_mday, ==, g_date_time_get_day_of_month (dt));
+ g_assert_cmpint (tm.tm_hour, ==, g_date_time_get_hour (dt));
+ g_assert_cmpint (tm.tm_min, ==, g_date_time_get_minute (dt));
+ g_assert_cmpint (tm.tm_sec, ==, g_date_time_get_second (dt));
+ g_date_time_unref (dt);
+ g_date_time_unref (dt2);
+}
+
+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)); \
+ g_assert_cmpint ((o), ==, g_date_time_get_day_of_year (__dt)); \
+ g_date_time_unref (__dt); } G_STMT_END
+
+ TEST_DAY_OF_YEAR (2009, 1, 1, 1);
+ TEST_DAY_OF_YEAR (2009, 2, 1, 32);
+ TEST_DAY_OF_YEAR (2009, 8, 16, 228);
+ TEST_DAY_OF_YEAR (2008, 8, 16, 229);
+}
+
+static void
+test_GDateTime_printf (void)
+{
+ gchar dst[16];
+ struct tm tt;
+ time_t t;
+ gchar t_str[16];
+
+#define TEST_PRINTF(f,o) G_STMT_START { \
+GDateTime *__dt = g_date_time_new_from_date (2009, 10, 24); \
+ gchar *__p = g_date_time_printf (__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)); \
+ gchar *p = g_date_time_printf (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); \
+ gchar *p = g_date_time_printf (dt, (f)); \
+ g_assert_cmpstr (p, ==, (o)); \
+ g_date_time_unref (dt); \
+ g_free (p); } G_STMT_END
+
+ /*
+ * This is a little helper to make sure we can compare timezones to
+ * that of the generated timezone.
+ */
+ t = time (NULL);
+ memset (&tt, 0, sizeof(tt));
+ get_localtime_tm (t, &tt);
+ tt.tm_year = 2009 - 1900;
+ tt.tm_mon = 9; /* 0 indexed */
+ tt.tm_mday = 24;
+ t = mktime (&tt);
+ memset (&tt, 0, sizeof(tt));
+ get_localtime_tm (t, &tt);
+ strftime (dst, sizeof(dst), "%Z", &tt);
+
+ /* get current time_t for 20090924 in the local timezone */
+ tt.tm_sec = 0;
+ tt.tm_min = 0;
+ tt.tm_hour = 0;
+ t = mktime (&tt);
+ g_sprintf (t_str, "%ld", t);
+
+ TEST_PRINTF ("%a", "Sat");
+ TEST_PRINTF ("%A", "Saturday");
+ TEST_PRINTF ("%b", "Oct");
+ TEST_PRINTF ("%B", "October");
+ TEST_PRINTF ("%d", "24");
+ TEST_PRINTF_DATE (2009, 1, 1, "%d", "01");
+ TEST_PRINTF ("%e", "24"); // fixme
+ TEST_PRINTF ("%h", "Oct");
+ TEST_PRINTF ("%H", "00");
+ TEST_PRINTF_TIME (15, 0, 0, "%H", "15");
+ TEST_PRINTF ("%I", "12");
+ TEST_PRINTF_TIME (15, 0, 0, "%I", "03");
+ TEST_PRINTF ("%j", "297");
+ TEST_PRINTF ("%k", " 0");
+ TEST_PRINTF_TIME (13, 13, 13, "%k", "13");
+ TEST_PRINTF ("%l", "12");
+ TEST_PRINTF_TIME (13, 13, 13, "%l", " 1");
+ TEST_PRINTF_TIME (10, 13, 13, "%l", "10");
+ TEST_PRINTF ("%m", "10");
+ TEST_PRINTF ("%M", "00");
+ TEST_PRINTF ("%N", "0");
+ TEST_PRINTF ("%p", "AM");
+ TEST_PRINTF_TIME (13, 13, 13, "%p", "PM");
+ TEST_PRINTF ("%P", "am");
+ TEST_PRINTF_TIME (13, 13, 13, "%P", "pm");
+ TEST_PRINTF ("%r", "12:00:00 AM");
+ TEST_PRINTF_TIME (13, 13, 13, "%r", "01:13:13 PM");
+ TEST_PRINTF ("%R", "00:00");
+ TEST_PRINTF_TIME (13, 13, 31, "%R", "13:13");
+ TEST_PRINTF ("%s", t_str);
+ TEST_PRINTF ("%S", "00");
+ TEST_PRINTF ("%t", " ");
+ TEST_PRINTF ("%W", "42");
+ TEST_PRINTF ("%u", "6");
+ TEST_PRINTF ("%x", "10/24/09");
+ TEST_PRINTF ("%X", "00:00:00");
+ TEST_PRINTF_TIME (13, 14, 15, "%X", "13:14:15");
+ TEST_PRINTF ("%y", "09");
+ TEST_PRINTF ("%Y", "2009");
+ TEST_PRINTF ("%%", "%");
+ TEST_PRINTF ("%", "");
+ TEST_PRINTF ("%9", NULL);
+ TEST_PRINTF ("%z", dst);
+}
+
+gint
+main (gint argc,
+ gchar *argv[])
+{
+ g_test_init (&argc, &argv, NULL);
+
+ /* GDateTime Tests */
+
+ 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/copy", test_GDateTime_copy);
+ 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_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_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_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);
+
+ return g_test_run ();
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]