[glib] Add GDateTime to GLib



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]