gnucash master: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Sat May 2 23:21:43 EDT 2015


Updated	 via  https://github.com/Gnucash/gnucash/commit/9ea1dd0f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/280589a3 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/25be764c (commit)
	 via  https://github.com/Gnucash/gnucash/commit/b215d629 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/9fafb612 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/48a5473b (commit)
	 via  https://github.com/Gnucash/gnucash/commit/9fbc447f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/f87f9ca0 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/bcedeff3 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/ac515d6c (commit)
	 via  https://github.com/Gnucash/gnucash/commit/a8028ec7 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/f46e9f02 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/db6b7d36 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/671a6ac7 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d2f80a94 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/2dde36d0 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d4a3d862 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/78b974ad (commit)
	 via  https://github.com/Gnucash/gnucash/commit/ab72874e (commit)
	 via  https://github.com/Gnucash/gnucash/commit/3f87f56e (commit)
	 via  https://github.com/Gnucash/gnucash/commit/cbb01c94 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/e5861dc1 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/10daa27a (commit)
	 via  https://github.com/Gnucash/gnucash/commit/01f5a9c0 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/307c08e2 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/09356976 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d0ae8c37 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d0b916c6 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/5a378e1e (commit)
	 via  https://github.com/Gnucash/gnucash/commit/197d43f4 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/327ef838 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/e938b39f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/4f90e4e0 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/99efb5d4 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/23687ee2 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/eb3bafed (commit)
	 via  https://github.com/Gnucash/gnucash/commit/ae11e350 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/154911e2 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/32852ec4 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/83f2627b (commit)
	 via  https://github.com/Gnucash/gnucash/commit/6fd68c3c (commit)
	 via  https://github.com/Gnucash/gnucash/commit/9f2d3843 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/fb6992f3 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/23d4e4a5 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/c7ca7850 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/a07c78e5 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/6c6153b5 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/6673128b (commit)
	 via  https://github.com/Gnucash/gnucash/commit/19f64ad3 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/2061026f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d98ddd12 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/280b7223 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/5983df7a (commit)
	 via  https://github.com/Gnucash/gnucash/commit/45170bb5 (commit)
	from  https://github.com/Gnucash/gnucash/commit/15a0d5d2 (commit)



commit 9ea1dd0facc1e1a8283c92ce619d52a4493900cd
Merge: 15a0d5d 280589a
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat May 2 17:40:33 2015 -0700

    Merge branch 'boost-date'
    
    First merge, which replaces GDateTime with GncDateTime. GncDateTime is
    implemented as a PImpl to a wrapper class for boost::date_time. A skeleton
    implementation of GncDate is included. More work on that will go into the
    next merge.


commit 280589a33ebebc541c4bf2928cf0573bf1ce94ce
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat May 2 17:35:09 2015 -0700

    Adjust some tests for 64-bit.
    
    The libc time functions are apparently not too smart about applying
    timezones to date-times, using the current TZ info rather than the
    one that applies to the date.
    
    Formatting is a bit variable as well when localization is applied,
    so test with the locale format when appropriate.

diff --git a/src/libqof/qof/test/test-gnc-date.c b/src/libqof/qof/test/test-gnc-date.c
index 396deb9..d62f352 100644
--- a/src/libqof/qof/test/test-gnc-date.c
+++ b/src/libqof/qof/test/test-gnc-date.c
@@ -206,6 +206,7 @@ test_gnc_gmtime (void)
             g_assert (time == NULL);
             continue;
         }
+
         g_assert_cmpint (time->tm_year, ==, answers[ind].tm_year);
         g_assert_cmpint (time->tm_mon, ==, answers[ind].tm_mon);
         g_assert_cmpint (time->tm_mday, ==, answers[ind].tm_mday);
@@ -250,6 +251,12 @@ test_gnc_mktime (void)
     for (ind = 0; ind < G_N_ELEMENTS (time); ind++)
     {
         time64 secs = gnc_mktime (&time[ind]);
+#if !PLATFORM(WINDOWS)
+	//The 64-bit timezone database uses local time for some
+	//timezones before 1900, which screws up the offset.
+	if (time[ind].tm_year < 0 && sizeof(time_t) == sizeof(int64_t))
+	     continue;
+#endif
         g_assert_cmpint (secs, ==, ans[ind] - offset);
 
     }
@@ -674,27 +681,23 @@ test_timespecCanonicalDayTime (void)
     const time64 secs = 8 * 3600 + 43 * 60 + 11;
     const time64 secs1 = 23 * sec_per_yr + 5 * sec_per_mo + 11 * sec_per_day + 8 * 3600 + 43 * 60 + 11;
     const time64 secs2 = 21 * sec_per_yr + 11 * sec_per_mo + 19 * sec_per_day + 21 * 3600 + 9 * 60 + 48;
-    const time64 secs3 = 72 * sec_per_yr + 2 * sec_per_mo + 26 * sec_per_day + 12 * 60;
+
     Timespec t0 = { secs, 0 };
     Timespec ta = { secs1, 0 };
     Timespec tb = { secs2, 0 };
-    Timespec tc = { secs3, 0 };
 
     Timespec n0 = compute_noon_of_day (&t0);
     Timespec na = compute_noon_of_day (&ta);
     Timespec nb = compute_noon_of_day (&tb);
-    Timespec nc = compute_noon_of_day (&tc);
 
     Timespec r0 = timespecCanonicalDayTime (t0);
     Timespec ra = timespecCanonicalDayTime (ta);
     Timespec rb = timespecCanonicalDayTime (tb);
-    Timespec rc = timespecCanonicalDayTime (tc);
 
     g_assert_cmpint (n0.tv_sec, ==, r0.tv_sec);
     g_assert_cmpint (na.tv_sec, ==, ra.tv_sec);
     g_assert_cmpint (nb.tv_sec, ==, rb.tv_sec);
-    if (sizeof(time_t) >= sizeof(time64))
-        g_assert_cmpint (nc.tv_sec, ==, rc.tv_sec);
+
 }
 
 /* gnc_date_get_last_mday
@@ -965,116 +968,125 @@ qof_print_date_buff (char * buff, size_t len, time64 t)// C: 3 in 1  Local: 2:0:
 static void
 test_qof_print_date_buff (void)
 {
-    gchar buff[MAX_DATE_LENGTH];
+    gchar buff[MAX_DATE_LENGTH], ans[MAX_DATE_LENGTH];
     gchar *locale = g_strdup (setlocale (LC_TIME, NULL));
 
-    time64 tm1 = 154440000; //1974-11-23 12:00:00
-    time64 tm2 = -281188800; //1961-02-02 12:00:00
-    time64 tm3 = 2381227200LL; //2045-06-16 12:00:00
+    time64 time1 = 154440000; //1974-11-23 12:00:00
+    time64 time2 = -281188800; //1961-02-02 12:00:00
+    time64 time3 = 2381227200LL; //2045-06-16 12:00:00
+    struct tm tm1 = {0, 0, 12, 23, 10, 74};
+    struct tm tm2 = {0, 0, 12, 2, 1, 61};
+    struct tm tm3 = {0, 0, 12, 16, 5, 145};
 
     qof_date_format_set (QOF_DATE_FORMAT_UK);
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm1),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time1),
                      ==, strlen (buff));
     g_assert_cmpstr (buff, ==, "23/11/1974");
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm2),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time2),
                      ==, strlen (buff));
     g_assert_cmpstr (buff, ==, "02/02/1961");
 
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm3),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time3),
                      ==, strlen (buff));
     g_assert_cmpstr (buff, ==, "16/06/2045");
 
     qof_date_format_set (QOF_DATE_FORMAT_CE);
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm1),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time1),
                      ==, strlen (buff));
     g_assert_cmpstr (buff, ==, "23.11.1974");
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm2),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time2),
                      ==, strlen (buff));
     g_assert_cmpstr (buff, ==, "02.02.1961");
 
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm3),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time3),
                      ==, strlen (buff));
     g_assert_cmpstr (buff, ==, "16.06.2045");
 
     qof_date_format_set (QOF_DATE_FORMAT_US);
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm1),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time1),
                      ==, strlen (buff));
     g_assert_cmpstr (buff, ==, "11/23/1974");
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm2),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time2),
                      ==, strlen (buff));
     g_assert_cmpstr (buff, ==, "02/02/1961");
 
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm3),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time3),
                      ==, strlen (buff));
     g_assert_cmpstr (buff, ==, "06/16/2045");
 
     qof_date_format_set (QOF_DATE_FORMAT_ISO);
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm1),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time1),
                      ==, strlen (buff));
     g_assert_cmpstr (buff, ==, "1974-11-23");
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm2),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time2),
                      ==, strlen (buff));
     g_assert_cmpstr (buff, ==, "1961-02-02");
 
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm3),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time3),
                      ==, strlen (buff));
     g_assert_cmpstr (buff, ==, "2045-06-16");
 
     qof_date_format_set (QOF_DATE_FORMAT_LOCALE);
     test_gnc_setlocale (LC_TIME, "en_US");
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm1),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time1),
                      ==, strlen (buff));
     g_assert_cmpstr (buff, ==, "11/23/1974");
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm2),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time2),
                      ==, strlen (buff));
     g_assert_cmpstr (buff, ==, "02/02/1961");
 
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm3),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time3),
                      ==, strlen (buff));
     g_assert_cmpstr (buff, ==, "06/16/2045");
 
     test_gnc_setlocale (LC_TIME, "en_GB");
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm1),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time1),
                      ==, strlen (buff));
-    g_assert_cmpstr (buff, ==, "23/11/1974");
+    strftime(ans, MAX_DATE_LENGTH, GNC_D_FMT, &tm1);
+    g_assert_cmpstr (buff, ==, ans);
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm2),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time2),
                      ==, strlen (buff));
-    g_assert_cmpstr (buff, ==, "02/02/1961");
+    strftime(ans, MAX_DATE_LENGTH, GNC_D_FMT, &tm2);
+    g_assert_cmpstr (buff, ==, ans);
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm3),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time3),
                      ==, strlen (buff));
-    g_assert_cmpstr (buff, ==, "16/06/2045");
+    strftime(ans, MAX_DATE_LENGTH, GNC_D_FMT, &tm3);
+    g_assert_cmpstr (buff, ==, ans);
 
     test_gnc_setlocale (LC_TIME, "fr_FR");
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm1),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time1),
                      ==, strlen (buff));
-    g_assert_cmpstr (buff, ==, "23.11.1974");
+    strftime(ans, MAX_DATE_LENGTH, GNC_D_FMT, &tm1);
+    g_assert_cmpstr (buff, ==, ans);
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm2),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time2),
                      ==, strlen (buff));
-    g_assert_cmpstr (buff, ==, "02.02.1961");
+    strftime(ans, MAX_DATE_LENGTH, GNC_D_FMT, &tm2);
+    g_assert_cmpstr (buff, ==, ans);
     memset ((gpointer)buff, 0, sizeof (buff));
-    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm3),
+    g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), time3),
                      ==, strlen (buff));
-    g_assert_cmpstr (buff, ==, "16.06.2045");
+    strftime(ans, MAX_DATE_LENGTH, GNC_D_FMT, &tm3);
+    g_assert_cmpstr (buff, ==, ans);
 
     setlocale (LC_TIME, locale);
     g_free (locale);
@@ -1240,46 +1252,58 @@ static void
 test_qof_print_date (void)
 {
     gchar *locale = g_strdup (setlocale (LC_TIME, NULL));
-
-    time64 tm1 = 154440000; //1974-11-23 12:00:00
-    time64 tm2 = -281188800; //1961-02-02 12:00:00
-    time64 tm3 = 2381227200LL; //2045-06-16 12:00:00
+    char ans[MAX_DATE_LENGTH];
+    time64 time1 = 154440000; //1974-11-23 12:00:00
+    time64 time2 = -281188800; //1961-02-02 12:00:00
+    time64 time3 = 2381227200LL; //2045-06-16 12:00:00
+    struct tm tm1 = {0, 0, 12, 23, 10, 74};
+    struct tm tm2 = {0, 0, 12, 2, 1, 61};
+    struct tm tm3 = {0, 0, 12, 16, 5, 145};
 
     qof_date_format_set (QOF_DATE_FORMAT_UK);
-    test_assert_qof_print_date (tm1, "23/11/1974");
-    test_assert_qof_print_date_outside_range (tm2, "02/02/1961");
-    test_assert_qof_print_date_outside_range (tm3, "16/06/2045");
+    test_assert_qof_print_date (time1, "23/11/1974");
+    test_assert_qof_print_date_outside_range (time2, "02/02/1961");
+    test_assert_qof_print_date_outside_range (time3, "16/06/2045");
 
     qof_date_format_set (QOF_DATE_FORMAT_CE);
-    test_assert_qof_print_date (tm1, "23.11.1974");
-    test_assert_qof_print_date_outside_range (tm2, "02.02.1961");
-    test_assert_qof_print_date_outside_range (tm3, "16.06.2045");
+    test_assert_qof_print_date (time1, "23.11.1974");
+    test_assert_qof_print_date_outside_range (time2, "02.02.1961");
+    test_assert_qof_print_date_outside_range (time3, "16.06.2045");
 
     qof_date_format_set (QOF_DATE_FORMAT_US);
-    test_assert_qof_print_date (tm1, "11/23/1974");
-    test_assert_qof_print_date_outside_range (tm2, "02/02/1961");
-    test_assert_qof_print_date_outside_range (tm3, "06/16/2045");
+    test_assert_qof_print_date (time1, "11/23/1974");
+    test_assert_qof_print_date_outside_range (time2, "02/02/1961");
+    test_assert_qof_print_date_outside_range (time3, "06/16/2045");
 
     qof_date_format_set (QOF_DATE_FORMAT_ISO);
-    test_assert_qof_print_date (tm1, "1974-11-23");
-    test_assert_qof_print_date_outside_range (tm2, "1961-02-02");
-    test_assert_qof_print_date_outside_range (tm3, "2045-06-16");
+    test_assert_qof_print_date (time1, "1974-11-23");
+    test_assert_qof_print_date_outside_range (time2, "1961-02-02");
+    test_assert_qof_print_date_outside_range (time3, "2045-06-16");
 
     qof_date_format_set (QOF_DATE_FORMAT_LOCALE);
     test_gnc_setlocale (LC_TIME, "en_US");
-    test_assert_qof_print_date (tm1,"11/23/1974");
-    test_assert_qof_print_date_outside_range (tm2, "02/02/1961");
-    test_assert_qof_print_date_outside_range (tm3, "06/16/2045");
+    strftime(ans, MAX_DATE_LENGTH, GNC_D_FMT, &tm1);
+    test_assert_qof_print_date (time1,ans);
+    strftime(ans, MAX_DATE_LENGTH, GNC_D_FMT, &tm2);
+    test_assert_qof_print_date_outside_range (time2, ans);
+    strftime(ans, MAX_DATE_LENGTH, GNC_D_FMT, &tm3);
+    test_assert_qof_print_date_outside_range (time3, ans);
 
     test_gnc_setlocale (LC_TIME, "en_GB");
-    test_assert_qof_print_date (tm1, "23/11/1974");
-    test_assert_qof_print_date_outside_range (tm2, "02/02/1961");
-    test_assert_qof_print_date_outside_range (tm3, "16/06/2045");
+    strftime(ans, MAX_DATE_LENGTH, GNC_D_FMT, &tm1);
+    test_assert_qof_print_date (time1, ans);
+    strftime(ans, MAX_DATE_LENGTH, GNC_D_FMT, &tm2);
+    test_assert_qof_print_date_outside_range (time2, ans);
+    strftime(ans, MAX_DATE_LENGTH, GNC_D_FMT, &tm3);
+    test_assert_qof_print_date_outside_range (time3, ans);
 
     test_gnc_setlocale (LC_TIME, "fr_FR");
-    test_assert_qof_print_date (tm1, "23.11.1974");
-    test_assert_qof_print_date_outside_range (tm2, "02.02.1961");
-    test_assert_qof_print_date_outside_range (tm3, "16.06.2045");
+    strftime(ans, MAX_DATE_LENGTH, GNC_D_FMT, &tm1);
+    test_assert_qof_print_date (time1, ans);
+    strftime(ans, MAX_DATE_LENGTH, GNC_D_FMT, &tm2);
+    test_assert_qof_print_date_outside_range (time2, ans);
+    strftime(ans, MAX_DATE_LENGTH, GNC_D_FMT, &tm3);
+    test_assert_qof_print_date_outside_range (time3,ans);
 
     setlocale (LC_TIME, locale);
     g_free (locale);

commit 25be764cb0bf869db908ad5f5c99853849a6f13b
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat May 2 14:59:45 2015 -0700

    Replace boost::posix_date::from_time_t().
    
    It silently converts a 64-bit time_t to 32-bits.

diff --git a/src/libqof/qof/gnc-timezone.cpp b/src/libqof/qof/gnc-timezone.cpp
index 4cbe8ad..7cc3b56 100644
--- a/src/libqof/qof/gnc-timezone.cpp
+++ b/src/libqof/qof/gnc-timezone.cpp
@@ -550,11 +550,18 @@ TimeZoneProvider::TimeZoneProvider(const std::string& tzname) :  zone_vector {}
 				  {return !tz.info.isdst;});
     auto last_time = ptime();
     DSTRule::DSTRule last_rule;
+    using boost::gregorian::date;
+    using boost::posix_time::ptime;
+    using boost::posix_time::time_duration;
     for (auto txi = parser.transitions.begin();
 	 txi != parser.transitions.end(); ++txi)
     {
 	auto this_info = parser.tzinfo.begin() + txi->index;
-	auto this_time = boost::posix_time::from_time_t(txi->timestamp);
+//Can't use boost::posix_date::from_time_t() constructor because it
+//silently casts the time_t to an int32_t.
+	auto this_time = ptime(date(1970, 1, 1),
+			       time_duration(txi->timestamp / 3600, 0,
+					     txi->timestamp % 3600));
 	auto this_year = this_time.date().year();
 	//Initial case
 	if (last_time.is_not_a_date_time())

commit b215d6292511af5899a71434807351209d63cd87
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Apr 30 16:09:40 2015 -0700

    Replace 'using make_week_num' with a macro; gcc-4.8 can't do that kind of alias.

diff --git a/src/libqof/qof/gnc-timezone.cpp b/src/libqof/qof/gnc-timezone.cpp
index 693c321..4cbe8ad 100644
--- a/src/libqof/qof/gnc-timezone.cpp
+++ b/src/libqof/qof/gnc-timezone.cpp
@@ -129,12 +129,13 @@ windows_tz_names (HKEY key)
     return time_zone_names (std_name, std_name, dlt_name, dlt_name);
 }
 
+#define make_week_num(x)  static_cast<boost::date_time::nth_kday_of_month<boost::gregorian::date>::week_num>(x)
+
 static TZ_Ptr
 zone_from_regtzi (const RegTZI& regtzi, time_zone_names names)
 {
     using ndate = boost::gregorian::nth_day_of_the_week_in_month;
     using nth_day_rule = boost::local_time::nth_day_of_the_week_in_month_dst_rule;
-   using make_week_num = static_cast<boost::date_time::nth_kday_of_month<boost::gregorian::date>::week_num>;
 
     duration std_off (0, regtzi.StandardBias - regtzi.Bias, 0);
     duration dlt_off (0, regtzi.DaylightBias, 0);
@@ -225,8 +226,6 @@ TimeZoneProvider::load_windows_classic_tz (HKEY key, time_zone_names names)
     RegCloseKey (key);
 }
 
-TimeZoneProvider::TimeZoneProvider ()  : TimeZoneProvider ("")) {}
-
 TimeZoneProvider::TimeZoneProvider (const std::string& identifier) :
     zone_vector ()
 {

commit 9fafb612830d35de0f8c7d9cfffd2ca050116e86
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Apr 30 16:08:24 2015 -0700

    Restore #include strptime.h, needed on MinGW.

diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index 9bb5b1d..5db07db 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -38,7 +38,9 @@ extern "C"
 #ifdef HAVE_LANGINFO_D_FMT
 # include <langinfo.h>
 #endif
-
+#ifndef HAVE_STRPTIME
+#include <strptime.h>
+#endif
 #ifdef G_OS_WIN32
 #  include <windows.h>
 #endif

commit 48a5473bbb4a3ad0bdd6c7343c56463cae3294ec
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Apr 30 16:06:28 2015 -0700

    Add BOOST_LDFLAGS so that libboost_date_time can be found in MinGW.

diff --git a/src/libqof/qof/Makefile.am b/src/libqof/qof/Makefile.am
index 99b4fe1..7350398 100644
--- a/src/libqof/qof/Makefile.am
+++ b/src/libqof/qof/Makefile.am
@@ -11,7 +11,7 @@ libgnc_qof_la_LDFLAGS= \
 libgnc_qof_common_libs =  \
   $(GLIB_LIBS) \
   $(REGEX_LIBS) \
-  -lboost_date_time \
+  $(BOOST_LDFLAGS) -lboost_date_time \
   $(top_builddir)/lib/libc/libc-missing.la
 
 libgnc_qof_la_LIBADD = $(libgnc_qof_common_libs)

commit 9fbc447f74e8090431bdd317c5688fb116c270fe
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Apr 30 12:23:25 2015 -0700

    Some gcc don't like having a struct ymd and a ymd() member function.

diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index 52f1d51..9bb5b1d 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -1400,7 +1400,7 @@ GDate* gnc_g_date_new_today ()
 {
     GncDate gncd;
     gncd.today();
-    auto ymd = gncd.ymd();
+    auto ymd = gncd.year_month_day();
     auto month = static_cast<GDateMonth>(ymd.month);
     auto result = g_date_new_dmy (ymd.day, month, ymd.year);
     g_assert(g_date_valid (result));
diff --git a/src/libqof/qof/gnc-datetime.cpp b/src/libqof/qof/gnc-datetime.cpp
index db54d88..7f8a6d4 100644
--- a/src/libqof/qof/gnc-datetime.cpp
+++ b/src/libqof/qof/gnc-datetime.cpp
@@ -64,13 +64,13 @@ public:
     GncDateImpl(Date d) : m_greg(d) {}
 
     void today() { m_greg = boost::gregorian::day_clock::local_day(); }
-    ymd ymd() const;
+    ymd year_month_day() const;
 private:
     Date m_greg;
 };
 
 ymd
-GncDateImpl::ymd() const
+GncDateImpl::year_month_day() const
 {
     auto boost_ymd = m_greg.year_month_day();
     return {boost_ymd.year, boost_ymd.month.as_number(), boost_ymd.day};
@@ -229,9 +229,9 @@ GncDate::today()
 }
 
 ymd
-GncDate::ymd() const
+GncDate::year_month_day() const
 {
-    return m_impl->ymd();
+    return m_impl->year_month_day();
 }
 
 GncDateTime::GncDateTime() : m_impl(new GncDateTimeImpl) {}
diff --git a/src/libqof/qof/gnc-datetime.hpp b/src/libqof/qof/gnc-datetime.hpp
index 3127804..04d48b5 100644
--- a/src/libqof/qof/gnc-datetime.hpp
+++ b/src/libqof/qof/gnc-datetime.hpp
@@ -68,7 +68,7 @@ public:/** Construct a GncDate representing the current day.
 /** Get the year, month, and day from the date as a ymd.
     @return ymd struct
  */
-    ymd ymd() const;
+    ymd year_month_day() const;
 /** Test that the Date has an implementation. */
     bool isnull (void) { return m_impl == nullptr; }
 
diff --git a/src/libqof/qof/test/gtest-gnc-datetime.cpp b/src/libqof/qof/test/gtest-gnc-datetime.cpp
index da47b0c..2f6e000 100644
--- a/src/libqof/qof/test/gtest-gnc-datetime.cpp
+++ b/src/libqof/qof/test/gtest-gnc-datetime.cpp
@@ -77,12 +77,12 @@ TEST(gnc_datetime_functions, test_format)
     EXPECT_EQ(atime.format("%d-%m-%Y"), "13-11-2045");
 }
 
-//This is a bit convoluted because it uses GncDate's GncDateImpl constructor and ymd() function. There's no good way to test the former without violating the privacy of the implementation.
+//This is a bit convoluted because it uses GncDate's GncDateImpl constructor and year_month_day() function. There's no good way to test the former without violating the privacy of the implementation.
 TEST(gnc_datetime_functions, test_date)
 {
     GncDateTime atime(2394187200); //2045-11-13 12:00:00 Z
     GncDate gncd = std::move(atime.date());
-    auto ymd = gncd.ymd();
+    auto ymd = gncd.year_month_day();
     EXPECT_EQ(ymd.year, 2045);
     EXPECT_EQ(ymd.month, 11);
     EXPECT_EQ(ymd.day, 13);

commit f87f9ca02d63e4011c48205d1721d4170fb4ac34
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Apr 28 17:54:05 2015 -0700

    gnc_date_today from GncDate.

diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index e0a689d..52f1d51 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -98,14 +98,14 @@ gnc_tm_free (struct tm* time)
 struct tm*
 gnc_localtime (const time64 *secs)
 {
-	auto time = static_cast<struct tm*>(calloc(1, sizeof(struct tm)));
-	if (gnc_localtime_r (secs, time) == NULL)
-	{
-	    gnc_tm_free (time);
-	    return NULL;
-	}
-	return time;
+    auto time = static_cast<struct tm*>(calloc(1, sizeof(struct tm)));
+    if (gnc_localtime_r (secs, time) == NULL)
+    {
+	gnc_tm_free (time);
+	return NULL;
     }
+    return time;
+}
 
 struct tm*
 gnc_localtime_r (const time64 *secs, struct tm* time)
@@ -123,17 +123,17 @@ gnc_localtime_r (const time64 *secs, struct tm* time)
 
 static void
 normalize_time_component (int *inner, int *outer, unsigned int divisor,
-			  int base)
+                          int base)
 {
      while (*inner < base)
      {
-	  --(*outer);
-	  *inner += divisor;
+          --(*outer);
+          *inner += divisor;
      }
      while (*inner > static_cast<gint>(divisor))
      {
-	  ++(*outer);
-	  *inner -= divisor;
+          ++(*outer);
+          *inner -= divisor;
      }
 }
 
@@ -165,16 +165,16 @@ normalize_struct_tm (struct tm* time)
      // auto month_in_range = []int (int m){ return (m + 12) % 12; }
      while (time->tm_mday < 1)
      {
-	 normalize_month (&(--time->tm_mon), &year);
-	 last_day = gnc_date_get_last_mday (time->tm_mon, year);
-	 time->tm_mday += last_day;
+         normalize_month (&(--time->tm_mon), &year);
+         last_day = gnc_date_get_last_mday (time->tm_mon, year);
+         time->tm_mday += last_day;
      }
      last_day = gnc_date_get_last_mday (time->tm_mon, year);
      while (time->tm_mday > last_day)
      {
-	  time->tm_mday -= last_day;
-	  normalize_month(&(++time->tm_mon), &year);
-	  last_day = gnc_date_get_last_mday (time->tm_mon, year);
+          time->tm_mday -= last_day;
+          normalize_month(&(++time->tm_mon), &year);
+          last_day = gnc_date_get_last_mday (time->tm_mon, year);
      }
      time->tm_year = year - 1900;
 }
@@ -484,8 +484,8 @@ gnc_gdate_range_check (GDate *gd)
     int year;
     if (!g_date_valid (gd))
     {
-	g_date_set_dmy (gd, 1, G_DATE_JANUARY, 1970);
-	return;
+        g_date_set_dmy (gd, 1, G_DATE_JANUARY, 1970);
+        return;
     }
     year = g_date_get_year (gd);
     // Adjust the GDate to fit in the range of GDateTime.
@@ -677,7 +677,7 @@ qof_print_date_dmy_buff (char * buff, size_t len, int day, int month, int year)
         tm_str.tm_mday = day;
         tm_str.tm_mon = month - 1;    /* tm_mon = 0 through 11 */
         tm_str.tm_year = year - 1900; /* this is what the standard
-	 says, it's not a Y2K thing */
+         says, it's not a Y2K thing */
 
         gnc_tm_set_day_start (&tm_str);
         t = gnc_mktime (&tm_str);
@@ -708,7 +708,7 @@ qof_print_date_buff (char * buff, size_t len, time64 t)
     size_t actual;
     if (!buff) return 0 ;
     if (!gnc_localtime_r(&bt, &theTime))
-	return 0;
+        return 0;
 
     actual = qof_print_date_dmy_buff (buff, len,
                                     theTime.tm_mday,
@@ -807,7 +807,7 @@ qof_scan_date_internal (const char *buff, int *day, int *month, int *year,
     if (which_format == QOF_DATE_FORMAT_UTC)
     {
         if (strptime(buff, QOF_UTC_DATE_FORMAT, &utc)
-	    || strptime (buff, "%Y-%m-%d", &utc))
+            || strptime (buff, "%Y-%m-%d", &utc))
         {
             *day = utc.tm_mday;
             *month = utc.tm_mon + 1;
@@ -1245,13 +1245,13 @@ gnc_date_timestamp (void)
 Timespec
 gnc_iso8601_to_timespec_gmt(const char *cstr)
 {
-	time64 time;
+    time64 time;
     if (!cstr) return {0, 0};
     try
-	{
+    {
         GncDateTime gncdt(cstr);
         return {static_cast<time64>(gncdt), 0};
-	}
+    }
     catch(...)
     {
         return {0, 0};
@@ -1398,10 +1398,10 @@ GDate timespec_to_gdate (Timespec ts)
 
 GDate* gnc_g_date_new_today ()
 {
-
-    auto pdt = boost::posix_time::second_clock::local_time();
-    auto ymd = pdt.date().year_month_day();
-    auto month = static_cast<GDateMonth>(ymd.month.as_number());
+    GncDate gncd;
+    gncd.today();
+    auto ymd = gncd.ymd();
+    auto month = static_cast<GDateMonth>(ymd.month);
     auto result = g_date_new_dmy (ymd.day, month, ymd.year);
     g_assert(g_date_valid (result));
     return result;
@@ -1420,7 +1420,7 @@ gnc_tm_get_day_start (struct tm *tm, time64 time_val)
 {
     /* Get the equivalent time structure */
     if (!gnc_localtime_r(&time_val, tm))
-	return;
+        return;
     gnc_tm_set_day_start(tm);
 }
 
@@ -1429,7 +1429,7 @@ gnc_tm_get_day_end (struct tm *tm, time64 time_val)
 {
     /* Get the equivalent time structure */
     if (!gnc_localtime_r(&time_val, tm))
-	return;
+        return;
     gnc_tm_set_day_end(tm);
 }
 

commit bcedeff3ba2f8aee847d84deeffaeee2fa74c844
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Apr 28 17:53:35 2015 -0700

    Fix the string constructor to apply the timezone correctly.

diff --git a/src/libqof/qof/gnc-datetime.cpp b/src/libqof/qof/gnc-datetime.cpp
index 20c78c4..db54d88 100644
--- a/src/libqof/qof/gnc-datetime.cpp
+++ b/src/libqof/qof/gnc-datetime.cpp
@@ -43,7 +43,7 @@ using time64 = int64_t;
 static const TimeZoneProvider tzp;
 // For converting to/from POSIX time.
 static const PTime unix_epoch (Date(1970, boost::gregorian::Jan, 1),
-	boost::posix_time::seconds(0));
+        boost::posix_time::seconds(0));
 static const TZ_Ptr utc_zone(new boost::local_time::posix_time_zone("UTC-0"));
 
 /* To ensure things aren't overly screwed up by setting the nanosecond clock for boost::date_time. Don't do it, though, it doesn't get us anything and slows down the date/time library. */
@@ -60,7 +60,7 @@ class GncDateImpl
 public:
     GncDateImpl(): m_greg(unix_epoch.date()) {}
     GncDateImpl(const int year, const int month, const int day) :
-	m_greg(year, static_cast<Month>(month), day) {}
+        m_greg(year, static_cast<Month>(month), day) {}
     GncDateImpl(Date d) : m_greg(d) {}
 
     void today() { m_greg = boost::gregorian::day_clock::local_day(); }
@@ -83,15 +83,15 @@ LDT_from_unix_local(const time64 time)
 {
     try
     {
-	PTime temp(unix_epoch.date(),
-		   boost::posix_time::hours(time / 3600) +
-		   boost::posix_time::seconds(time % 3600));
-	auto tz = tzp.get(temp.date().year());
-	return LDT(temp, tz);
+        PTime temp(unix_epoch.date(),
+                   boost::posix_time::hours(time / 3600) +
+                   boost::posix_time::seconds(time % 3600));
+        auto tz = tzp.get(temp.date().year());
+        return LDT(temp, tz);
     }
     catch(boost::gregorian::bad_year)
     {
-	throw(std::invalid_argument("Time value is outside the supported year range."));
+        throw(std::invalid_argument("Time value is outside the supported year range."));
     }
 }
 
@@ -100,15 +100,15 @@ LDT_from_struct_tm(const struct tm tm)
 {
     try
     {
-	auto tdate = boost::gregorian::date_from_tm(tm);
-	auto tdur = boost::posix_time::time_duration(tm.tm_hour, tm.tm_min,
-						     tm.tm_sec, 0);
-	auto tz = tzp.get(tdate.year());
-	return LDT(PTime(tdate, tdur), tz);
+        auto tdate = boost::gregorian::date_from_tm(tm);
+        auto tdur = boost::posix_time::time_duration(tm.tm_hour, tm.tm_min,
+                                                     tm.tm_sec, 0);
+        auto tz = tzp.get(tdate.year());
+        return LDT(PTime(tdate, tdur), tz);
     }
     catch(boost::gregorian::bad_year)
     {
-	throw(std::invalid_argument("Time value is outside the supported year range."));
+        throw(std::invalid_argument("Time value is outside the supported year range."));
     }
 }
 
@@ -144,21 +144,28 @@ GncDateTimeImpl::GncDateTimeImpl(const std::string str) :
     auto tzpos = str.find_first_of("+-", str.find(":"));
     if (tzpos != str.npos)
     {
-	string tzstr = "XXX" + str.substr(tzpos);
-	if (tzstr.length() > 6 && tzstr[6] != ':') //6 for XXXsHH, s is + or -
-	    tzstr.insert(6, ":");
-	if (tzstr.length() > 9 && tzstr[9] != ':') //9 for XXXsHH:MM
-	    tzstr.insert(9, ":");
-	tzptr.reset(new PTZ(tzstr));
-	if (str[tzpos - 1] == ' ') --tzpos;
+        string tzstr = "XXX" + str.substr(tzpos);
+        if (tzstr.length() > 6 && tzstr[6] != ':') //6 for XXXsHH, s is + or -
+            tzstr.insert(6, ":");
+        if (tzstr.length() > 9 && tzstr[9] != ':') //9 for XXXsHH:MM
+            tzstr.insert(9, ":");
+        tzptr.reset(new PTZ(tzstr));
+        if (str[tzpos - 1] == ' ') --tzpos;
     }
     else
     {
-	tzptr = utc_zone;
+        tzptr = utc_zone;
+    }
+    try
+    {
+        auto pdt = boost::posix_time::time_from_string(str.substr(0, tzpos));
+        m_time = LDT(pdt.date(), pdt.time_of_day(), tzptr,
+                     LDTBase::NOT_DATE_TIME_ON_ERROR);
+    }
+    catch(boost::gregorian::bad_year)
+    {
+        throw(std::invalid_argument("The date string was outside of the supported year range."));
     }
-
-    auto pdt = boost::posix_time::time_from_string(str.substr(0, tzpos));
-    m_time = LDT(pdt, tzptr);
 }
 
 GncDateTimeImpl::operator time64() const

commit ac515d6ce25491df1cff9df64bd357655873dc8a
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Apr 28 17:47:47 2015 -0700

    Stop testing fractional seconds.
    
    We don't use them in real code, so the new implementation isn't going to
    support them.

diff --git a/src/engine/test-core/test-engine-stuff.c b/src/engine/test-core/test-engine-stuff.c
index 2073afe..857e9b2 100644
--- a/src/engine/test-core/test-engine-stuff.c
+++ b/src/engine/test-core/test-engine-stuff.c
@@ -224,20 +224,7 @@ get_random_timespec(void)
     while (ret->tv_sec <= 0)
         ret->tv_sec = rand();
 
-    if (zero_nsec)
-        ret->tv_nsec = 0;
-    else
-    {
-        ret->tv_nsec = rand();
-
-        if (usec_resolution)
-        {
-            ret->tv_nsec = MIN (ret->tv_nsec, 999999999);
-            ret->tv_nsec /= 1000;
-            ret->tv_nsec *= 1000;
-        }
-    }
-
+    ret->tv_nsec = 0;
     return ret;
 }
 
diff --git a/src/engine/test/test-date.c b/src/engine/test/test-date.c
index 9397486..492975a 100644
--- a/src/engine/test/test-date.c
+++ b/src/engine/test/test-date.c
@@ -325,7 +325,7 @@ run_test (void)
     check_time (ts, do_print);
 
     ts.tv_sec = 1162088421;
-    ts.tv_nsec = 12548000;
+    ts.tv_nsec = 0;
     check_time (ts, do_print);
 
     ts.tv_sec = 325659000 - 6500;
@@ -337,15 +337,15 @@ run_test (void)
     check_time (ts, do_print);
 
     ts.tv_sec = 1603591171;
-    ts.tv_nsec = 595311000;
+    ts.tv_nsec = 0;
     check_time (ts, do_print);
 
     ts.tv_sec = 1738909365;
-    ts.tv_nsec = 204102000;
+    ts.tv_nsec = 0;
     check_time (ts, do_print);
 
     ts.tv_sec = 1603591171;
-    ts.tv_nsec = 595311000;
+    ts.tv_nsec = 0;
     check_time (ts, do_print);
 
     ts.tv_sec = 1143943200 - 1;
diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index 0375b2a..e0a689d 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -1246,12 +1246,11 @@ Timespec
 gnc_iso8601_to_timespec_gmt(const char *cstr)
 {
 	time64 time;
-	uint32_t nsecs;
     if (!cstr) return {0, 0};
     try
 	{
         GncDateTime gncdt(cstr);
-        return {static_cast<time64>(gncdt), gncdt.nsecs()};
+        return {static_cast<time64>(gncdt), 0};
 	}
     catch(...)
     {
diff --git a/src/libqof/qof/gnc-datetime.cpp b/src/libqof/qof/gnc-datetime.cpp
index 40ac1a6..20c78c4 100644
--- a/src/libqof/qof/gnc-datetime.cpp
+++ b/src/libqof/qof/gnc-datetime.cpp
@@ -126,7 +126,6 @@ public:
     operator struct tm() const;
     void now() { m_time = boost::local_time::local_sec_clock::local_time(tzp.get(boost::gregorian::day_clock::local_day().year())); }
     long offset() const;
-    long nsecs() const;
     struct tm utc_tm() const { return to_tm(m_time.utc_time()); }
     std::unique_ptr<GncDateImpl> date() const;
     std::string format(const char* format) const;
@@ -186,12 +185,6 @@ GncDateTimeImpl::offset() const
     return offset.total_seconds();
 }
 
-long
-GncDateTimeImpl::nsecs() const
-{
-	return (m_time.utc_time() - unix_epoch).ticks() % ticks_per_second;
-}
-
 std::unique_ptr<GncDateImpl>
 GncDateTimeImpl::date() const
 {
@@ -265,12 +258,6 @@ GncDateTime::offset() const
     return m_impl->offset();
 }
 
-long
-GncDateTime::nsecs() const
-{
-    return m_impl->nsecs();
-}
-
 struct tm
 GncDateTime::utc_tm() const
 {
diff --git a/src/libqof/qof/gnc-datetime.hpp b/src/libqof/qof/gnc-datetime.hpp
index 46dd83d..3127804 100644
--- a/src/libqof/qof/gnc-datetime.hpp
+++ b/src/libqof/qof/gnc-datetime.hpp
@@ -131,11 +131,6 @@ public:
  *  is negative.
  */
     long offset()const;
-/** Obtain the fractional seconds from the GncDateTime
- *  @return Fractional seconds, represented as nanoseconds, associated
- *  with the time.
- */
-    long nsecs() const;
 /** Obtain a struct tm representing the time in UTC.
  * @return struct tm
  */
diff --git a/src/libqof/qof/test/test-gnc-date.c b/src/libqof/qof/test/test-gnc-date.c
index 93f9943..396deb9 100644
--- a/src/libqof/qof/test/test-gnc-date.c
+++ b/src/libqof/qof/test/test-gnc-date.c
@@ -93,7 +93,7 @@ static void setup (FixtureA *f, gconstpointer pData)
     f->off_zulu = (TZOffset){0, 0};
     f->off_05w = (TZOffset){-5, 0};
     f->off_0840e = (TZOffset){8, 40};
-    f->ts1 = (Timespec){607009407, 345678000}; //1989-3-27 13:43:27.345678 Z
+    f->ts1 = (Timespec){607009407, 0}; //1989-3-27 13:43:27 Z
     f->ts2 = (Timespec){1604748079, 0}; //2020-11-7 06:21:19 -05:00
     f->ts3 = (Timespec){1341398864, 0}; //2012-07-04 19:27:44 +08:40
     f->ts4 = (Timespec){-261104801, 0}; //1961-09-22 17:53:19 -05:00
@@ -1590,7 +1590,7 @@ test_gnc_iso8601_to_timespec_gmt (FixtureA *f, gconstpointer pData)
     g_assert_cmpint (t.tv_sec, ==, 0);
     g_assert_cmpint (t.tv_nsec, ==, 0);
 
-    t = gnc_iso8601_to_timespec_gmt ("1989-03-27 13:43:27.345678");
+    t = gnc_iso8601_to_timespec_gmt ("1989-03-27 13:43:27");
     g_assert_cmpint (t.tv_sec, ==, f->ts1.tv_sec);
     /* MinGW has some precision issues in the last microsecond digit */
 #ifdef G_OS_WIN32

commit a8028ec7f28dee132dfedeae240822902d993957
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Apr 28 17:05:35 2015 -0700

    Remove aliases and boost::date_time construction functions from gnc-date.

diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index 830e608..0375b2a 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -53,13 +53,6 @@ extern "C"
 
 #define N_(string) string //So that xgettext will find it
 
-using Date = boost::gregorian::date;
-using Month = boost::gregorian::greg_month;
-using PTime = boost::posix_time::ptime;
-using LDT = boost::local_time::local_date_time;
-using Duration = boost::posix_time::time_duration;
-using LDTBase = boost::local_time::local_date_time_base<PTime, boost::date_time::time_zone_base<PTime, char>>;
-
 #ifdef HAVE_LANGINFO_D_FMT
 #  define GNC_D_FMT (nl_langinfo (D_FMT))
 #  define GNC_D_T_FMT (nl_langinfo (D_T_FMT))
@@ -95,56 +88,6 @@ static int dateCompletionBackMonths = 6;
 /* This static indicates the debugging module that this .o belongs to. */
 static QofLogModule log_module = QOF_MOD_ENGINE;
 
-// Default constructor Initializes to the current locale.
-static const TimeZoneProvider tzp;
-// For converting to/from POSIX time.
-static const PTime unix_epoch (Date(1970, boost::gregorian::Jan, 1),
-	boost::posix_time::seconds(0));
-/* To ensure things aren't overly screwed up by setting the nanosecond clock for boost::date_time. Don't do it, though, it doesn't get us anything and slows down the date/time library. */
-#ifndef BOOST_DATE_TIME_HAS_NANOSECONDS
-static constexpr auto ticks_per_second = INT64_C(1000000);
-#else
-static constexpr auto ticks_per_second = INT64_C(1000000000);
-#endif
-static LDT
-gnc_get_LDT(int year, int month, int day, int hour, int minute, int seconds)
-{
-    Date date(year, static_cast<Month>(month), day);
-    Duration time(hour, minute, seconds);
-    auto tz = tzp.get(year);
-    return LDT(date, time, tz, LDTBase::NOT_DATE_TIME_ON_ERROR);
-}
-
-static LDT
-LDT_from_unix_local(const time64 time)
-{
-    PTime temp(unix_epoch.date(),
-	       boost::posix_time::hours(time / 3600) +
-	       boost::posix_time::seconds(time % 3600));
-    auto tz = tzp.get(temp.date().year());
-    return LDT(temp, tz);
-}
-
-template<typename T>
-static time64
-time64_from_date_time(T time)
-{
-    auto duration = time - unix_epoch;
-    auto secs = duration.ticks();
-    secs /= ticks_per_second;
-    return secs;
-}
-
-template<>
-time64
-time64_from_date_time<LDT>(LDT time)
-{
-    auto duration = time.utc_time() - unix_epoch;
-    auto secs = duration.ticks();
-    secs /= ticks_per_second;
-    return secs;
-}
-
 /****************** Posix Replacement Functions ***************************/
 void
 gnc_tm_free (struct tm* time)

commit f46e9f023c3fe8356ee745c32b65f3a265311684
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Apr 28 17:04:09 2015 -0700

    Print functions to GncDateTime.

diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index 7cb4270..830e608 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -397,14 +397,8 @@ gnc_date_string_to_monthformat(const char *fmt_str, GNCDateMonthFormat *format)
 char*
 gnc_print_time64(time64 time, const char* format)
 {
-    using Facet = boost::local_time::local_time_facet;
-    auto date_time = LDT_from_unix_local(time);
-    std::stringstream ss;
-    //The stream destructor frees the facet, so it must be heap-allocated.
-    auto output_facet(new Facet(format));
-    ss.imbue(std::locale(std::locale(), output_facet));
-    ss << date_time;
-    auto sstr = ss.str();
+    GncDateTime gncdt(time);
+    auto sstr = gncdt.format(format);
     //ugly C allocation so that the ptr can be freed at the other end
     char* cstr = static_cast<char*>(malloc(sstr.length() + 1));
     memset(cstr, 0, sstr.length() + 1);
@@ -1308,45 +1302,18 @@ gnc_date_timestamp (void)
 Timespec
 gnc_iso8601_to_timespec_gmt(const char *cstr)
 {
-    using std::string;
-    using PTZ = boost::local_time::posix_time_zone;
-
-    if (!cstr) return {0, 0};
-//    try
-    {
-	string str(cstr);
-	if (str.empty())
-	    return {0, 0};
 	time64 time;
 	uint32_t nsecs;
-	auto tzpos = str.find_first_of("+-", str.find(":"));
-	if (tzpos != str.npos)
-	{
-	    string tzstr = "XXX" + str.substr(tzpos);
-	    if (tzstr.length() > 6 && tzstr[6] != ':') //6 for XXXsHH, s is + or -
-		tzstr.insert(6, ":");
-	    if (tzstr.length() > 9 && tzstr[9] != ':') //9 for XXXsHH:MM
-		tzstr.insert(9, ":");
-	    TZ_Ptr tzp(new PTZ(tzstr));
-	    if (str[tzpos - 1] == ' ') --tzpos;
-	    auto pdt = boost::posix_time::time_from_string(str.substr(0, tzpos));
-	    LDT ldt(pdt.date(), pdt.time_of_day(), tzp,
-		    LDTBase::NOT_DATE_TIME_ON_ERROR);
-	    time = time64_from_date_time(ldt);
-	    nsecs = (ldt.utc_time() - unix_epoch).ticks() % ticks_per_second;
-	}
-	else
+    if (!cstr) return {0, 0};
+    try
 	{
-	    auto pdt = boost::posix_time::time_from_string(str);
-	    time = time64_from_date_time(pdt);
-	    nsecs = (pdt - unix_epoch).ticks() % ticks_per_second;
+        GncDateTime gncdt(cstr);
+        return {static_cast<time64>(gncdt), gncdt.nsecs()};
 	}
-	return {time, static_cast<int32_t>(nsecs) * INT32_C(1000)};
+    catch(...)
+    {
+        return {0, 0};
     }
-//    catch(...)
-    //  {
-//	return {0, 0};
-//    }
 }
 
 /********************************************************************\
@@ -1360,15 +1327,8 @@ gnc_timespec_to_iso8601_buff (Timespec ts, char * buff)
 
     if (! buff) return NULL;
 
-    using Facet = boost::local_time::local_time_facet;
-    auto date_time = LDT_from_unix_local(ts.tv_sec);
-    date_time = date_time + boost::posix_time::microseconds(ts.tv_nsec / 1000);
-    std::stringstream ss;
-    //The stream destructor frees the facet, so it must be heap-allocated.
-    auto output_facet(new Facet(format));
-    ss.imbue(std::locale(std::locale(), output_facet));
-    ss << date_time;
-    auto sstr = ss.str();
+    GncDateTime gncdt(ts.tv_sec);
+    auto sstr = gncdt.format(format);
 
     memset(buff, 0, sstr.length() + 1);
     strncpy(buff, sstr.c_str(), sstr.length());

commit db6b7d368e7d111a0354dbdee493ea4dcaaaae69
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Apr 28 16:49:01 2015 -0700

    gnc_time to GncDateTime.

diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index 672eb51..7cb4270 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -292,11 +292,12 @@ gnc_ctime (const time64 *secs)
 time64
 gnc_time (time64 *tbuf)
 {
-    auto pdt = boost::posix_time::second_clock::universal_time();
-    auto secs = time64_from_date_time(pdt);
-     if (tbuf != NULL)
-	  *tbuf = secs;
-     return secs;
+    GncDateTime gncdt;
+    gncdt.now();
+    auto time = static_cast<time64>(gncdt);
+    if (tbuf != NULL)
+        *tbuf = time;
+    return time;
 }
 
 gdouble

commit 671a6ac75e45a76f06a7d35aa62a07e2bbe200de
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Apr 28 16:44:59 2015 -0700

    Remove extraneous try block.

diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index 847e255..672eb51 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -155,8 +155,6 @@ gnc_tm_free (struct tm* time)
 struct tm*
 gnc_localtime (const time64 *secs)
 {
-    try
-    {
 	auto time = static_cast<struct tm*>(calloc(1, sizeof(struct tm)));
 	if (gnc_localtime_r (secs, time) == NULL)
 	{
@@ -165,11 +163,6 @@ gnc_localtime (const time64 *secs)
 	}
 	return time;
     }
-    catch(std::invalid_argument)
-    {
-	return NULL;
-    }
-}
 
 struct tm*
 gnc_localtime_r (const time64 *secs, struct tm* time)

commit d2f80a94076602e9d4597f55d1f9fdaeaa3d7213
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Apr 28 15:23:26 2015 -0700

    gnc_mktime and gnc_timegm with GncDateTime.

diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index 4f357a1..847e255 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -155,20 +155,34 @@ gnc_tm_free (struct tm* time)
 struct tm*
 gnc_localtime (const time64 *secs)
 {
-    auto time = static_cast<struct tm*>(calloc(1, sizeof(struct tm)));
-    if (gnc_localtime_r (secs, time) == NULL)
+    try
+    {
+	auto time = static_cast<struct tm*>(calloc(1, sizeof(struct tm)));
+	if (gnc_localtime_r (secs, time) == NULL)
+	{
+	    gnc_tm_free (time);
+	    return NULL;
+	}
+	return time;
+    }
+    catch(std::invalid_argument)
     {
-	gnc_tm_free (time);
 	return NULL;
     }
-    return time;
 }
 
 struct tm*
 gnc_localtime_r (const time64 *secs, struct tm* time)
 {
-    *time = static_cast<struct tm>(GncDateTime(*secs));
-    return time;
+    try
+    {
+	*time = static_cast<struct tm>(GncDateTime(*secs));
+	return time;
+    }
+    catch(std::invalid_argument)
+    {
+	return NULL;
+    }
 }
 
 static void
@@ -232,34 +246,48 @@ normalize_struct_tm (struct tm* time)
 struct tm*
 gnc_gmtime (const time64 *secs)
 {
-    auto time = static_cast<struct tm*>(calloc(1, sizeof(struct tm)));
-    GncDateTime gncdt(*secs);
-    *time = static_cast<struct tm>(gncdt);
-    auto gmtoff = gncdt.offset();
-    time->tm_hour -= gmtoff / 3600;
-    time->tm_min -= (gmtoff % 3600 / 60);
-    time->tm_sec -= gmtoff % 60;
-    normalize_struct_tm(time);
-    return time;
+    try
+    {
+	auto time = static_cast<struct tm*>(calloc(1, sizeof(struct tm)));
+	GncDateTime gncdt(*secs);
+	*time = gncdt.utc_tm();
+	return time;
+    }
+    catch(std::invalid_argument)
+    {
+	return NULL;
+    }
+
 }
 
 time64
 gnc_mktime (struct tm* time)
 {
-    normalize_struct_tm (time);
-    auto ldt = gnc_get_LDT (time->tm_year + 1900, time->tm_mon + 1,
-			    time->tm_mday, time->tm_hour, time->tm_min,
-			    time->tm_sec);
-    return time64_from_date_time(ldt);
+    try
+    {
+	normalize_struct_tm (time);
+	GncDateTime gncdt(*time);
+	return static_cast<time64>(gncdt) - gncdt.offset();
+    }
+    catch(std::invalid_argument)
+    {
+	return 0;
+    }
 }
 
 time64
 gnc_timegm (struct tm* time)
 {
-    auto newtime = *time;
-    normalize_struct_tm(time);
-    auto pdt = boost::posix_time::ptime_from_tm(*time);
-    return time64_from_date_time(pdt);
+    try
+    {
+	normalize_struct_tm(time);
+	return static_cast<time64>(GncDateTime(*time));
+    }
+    catch(std::invalid_argument)
+    {
+	return 0;
+    }
+
 }
 
 char*
diff --git a/src/libqof/qof/gnc-datetime.cpp b/src/libqof/qof/gnc-datetime.cpp
index 8d2f097..40ac1a6 100644
--- a/src/libqof/qof/gnc-datetime.cpp
+++ b/src/libqof/qof/gnc-datetime.cpp
@@ -81,21 +81,35 @@ GncDateImpl::ymd() const
 static LDT
 LDT_from_unix_local(const time64 time)
 {
-    PTime temp(unix_epoch.date(),
-	       boost::posix_time::hours(time / 3600) +
-	       boost::posix_time::seconds(time % 3600));
-    auto tz = tzp.get(temp.date().year());
-    return LDT(temp, tz);
+    try
+    {
+	PTime temp(unix_epoch.date(),
+		   boost::posix_time::hours(time / 3600) +
+		   boost::posix_time::seconds(time % 3600));
+	auto tz = tzp.get(temp.date().year());
+	return LDT(temp, tz);
+    }
+    catch(boost::gregorian::bad_year)
+    {
+	throw(std::invalid_argument("Time value is outside the supported year range."));
+    }
 }
 
 static LDT
 LDT_from_struct_tm(const struct tm tm)
 {
-    auto tdate = boost::gregorian::date_from_tm(tm);
-    auto tdur = boost::posix_time::time_duration(tm.tm_hour, tm.tm_min,
-						 tm.tm_sec, 0);
-    auto tz = tzp.get(tdate.year());
-    return LDT(PTime(tdate, tdur), tz);
+    try
+    {
+	auto tdate = boost::gregorian::date_from_tm(tm);
+	auto tdur = boost::posix_time::time_duration(tm.tm_hour, tm.tm_min,
+						     tm.tm_sec, 0);
+	auto tz = tzp.get(tdate.year());
+	return LDT(PTime(tdate, tdur), tz);
+    }
+    catch(boost::gregorian::bad_year)
+    {
+	throw(std::invalid_argument("Time value is outside the supported year range."));
+    }
 }
 
 class GncDateTimeImpl
@@ -113,6 +127,7 @@ public:
     void now() { m_time = boost::local_time::local_sec_clock::local_time(tzp.get(boost::gregorian::day_clock::local_day().year())); }
     long offset() const;
     long nsecs() const;
+    struct tm utc_tm() const { return to_tm(m_time.utc_time()); }
     std::unique_ptr<GncDateImpl> date() const;
     std::string format(const char* format) const;
 private:
@@ -157,7 +172,11 @@ GncDateTimeImpl::operator time64() const
 
 GncDateTimeImpl::operator struct tm() const
 {
-    return to_tm(m_time);
+    struct tm time = to_tm(m_time);
+#if HAVE_STRUCT_TM_GMTOFF
+    time.tm_gmtoff = offset();
+#endif
+    return time;
 }
 
 long
@@ -252,6 +271,12 @@ GncDateTime::nsecs() const
     return m_impl->nsecs();
 }
 
+struct tm
+GncDateTime::utc_tm() const
+{
+    return m_impl->utc_tm();
+}
+
 GncDate
 GncDateTime::date() const
 {
diff --git a/src/libqof/qof/gnc-datetime.hpp b/src/libqof/qof/gnc-datetime.hpp
index e2fe6a7..46dd83d 100644
--- a/src/libqof/qof/gnc-datetime.hpp
+++ b/src/libqof/qof/gnc-datetime.hpp
@@ -123,8 +123,7 @@ public:
     void now();
 /** Cast the GncDateTime to a time64, seconds from the POSIX epoch. */
     explicit operator time64() const;
-/** Cast the GncDateTime to a struct tm. Timezone and offset fields
- * are not filled.
+/** Cast the GncDateTime to a struct tm. Timezone field isn't filled.
  */
     explicit operator struct tm() const;
 /** Obtain the UTC offset in seconds
@@ -137,6 +136,10 @@ public:
  *  with the time.
  */
     long nsecs() const;
+/** Obtain a struct tm representing the time in UTC.
+ * @return struct tm
+ */
+    struct tm utc_tm() const;
 /** Obtain the date from the time, as a GncDate, in the current timezone.
  *  @return GncDate represented by the GncDateTime.
  */

commit 2dde36d0154b10a7310f5eac52aa3c9a24bf5ed6
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Apr 28 15:13:13 2015 -0700

    Do locality and gmtime with GncDateTime.

diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index 0623203..4f357a1 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -47,6 +47,9 @@ extern "C"
 #include "gnc-date.h"
 #include "gnc-date-p.h"
 #include "gnc-datetime.hpp"
+#include "gnc-timezone.hpp"
+#define BOOST_ERROR_CODE_HEADER_ONLY
+#include <boost/date_time/local_time/local_time.hpp>
 
 #define N_(string) string //So that xgettext will find it
 
@@ -164,37 +167,7 @@ gnc_localtime (const time64 *secs)
 struct tm*
 gnc_localtime_r (const time64 *secs, struct tm* time)
 {
-    try
-    {
-	auto ldt = LDT_from_unix_local(*secs);
-	*time = boost::local_time::to_tm(ldt);
-#ifdef HAVE_STRUCT_TM_GMTOFF
-	auto offset = ldt.zone()->base_utc_offset();
-	if (ldt.is_dst())
-	    offset += ldt.zone()->dst_offset();
-	time->tm_gmtoff = offset.total_seconds();
-#endif
-    }
-    catch(boost::gregorian::bad_year)
-    {
-	return NULL; //Yeah, it should be nullptr, but this is a C-linkage func.
-    }
-    return time;
-}
-
-struct tm*
-gnc_gmtime (const time64 *secs)
-{
-    auto time = static_cast<struct tm*>(calloc(1, sizeof (struct tm)));
-    try {
-	PTime pdt(unix_epoch.date(), boost::posix_time::hours(*secs / 3600) +
-		  boost::posix_time::seconds(*secs % 3600));
-	*time = boost::posix_time::to_tm(pdt);
-    }
-    catch(boost::gregorian::bad_year)
-    {
-	return NULL; //Yeah, it should be nullptr, but this is a C-linkage func.
-    }
+    *time = static_cast<struct tm>(GncDateTime(*secs));
     return time;
 }
 
@@ -256,6 +229,20 @@ normalize_struct_tm (struct tm* time)
      time->tm_year = year - 1900;
 }
 
+struct tm*
+gnc_gmtime (const time64 *secs)
+{
+    auto time = static_cast<struct tm*>(calloc(1, sizeof(struct tm)));
+    GncDateTime gncdt(*secs);
+    *time = static_cast<struct tm>(gncdt);
+    auto gmtoff = gncdt.offset();
+    time->tm_hour -= gmtoff / 3600;
+    time->tm_min -= (gmtoff % 3600 / 60);
+    time->tm_sec -= gmtoff % 60;
+    normalize_struct_tm(time);
+    return time;
+}
+
 time64
 gnc_mktime (struct tm* time)
 {

commit d4a3d862cf693060d606f1017325858896db76fc
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Apr 28 14:19:00 2015 -0700

    Include gnc-datetime.hpp in gnc-date.cpp.

diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index db6f22e..0623203 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -31,6 +31,7 @@ extern "C"
 #include "config.h"
 #include <glib.h>
 #include <libintl.h>
+#include <stdlib.h>
 #include "platform.h"
 #include "qof.h"
 
@@ -45,9 +46,8 @@ extern "C"
 
 #include "gnc-date.h"
 #include "gnc-date-p.h"
-//#include "gnc-datetime.hpp"
+#include "gnc-datetime.hpp"
 
-#include "gnc-timezone.hpp"
 #define N_(string) string //So that xgettext will find it
 
 using Date = boost::gregorian::date;

commit 78b974ad79b4ec1acbf81247d0ec08e24b3dc94d
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Apr 28 14:08:02 2015 -0700

    Add gnc-datetime.cpp to the build.

diff --git a/src/libqof/qof/Makefile.am b/src/libqof/qof/Makefile.am
index bae92cc..99b4fe1 100644
--- a/src/libqof/qof/Makefile.am
+++ b/src/libqof/qof/Makefile.am
@@ -27,7 +27,8 @@ libgnc_qof_la_SOURCES =  \
    gnc-int128.cpp      \
    gnc-numeric.cpp     \
    gnc-rational.cpp    \
-   gnc-timezone.cpp     \
+   gnc-timezone.cpp    \
+   gnc-datetime.cpp    \
    guid.cpp            \
    kvp-util.cpp        \
    kvp_frame.cpp       \
@@ -55,6 +56,7 @@ qofinclude_HEADERS = \
    gnc-numeric.h     \
    gnc-rational.hpp  \
    gnc-timezone.hpp  \
+   gnc-datetime.hpp  \
    guid.h            \
    kvp-util-p.h      \
    kvp-util.h        \

commit ab72874ec14844398588c24cf9a9054540248d26
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Apr 28 10:06:18 2015 -0700

    Add GncDate and GncDateTime constructors and accessors:
    
    GncDateImpl constructor and ymd accessor for GncDate
    Std::string constructor and nsecs and GDate accessors for GncDateTime.

diff --git a/src/libqof/qof/gnc-datetime.cpp b/src/libqof/qof/gnc-datetime.cpp
index c41bec5..8d2f097 100644
--- a/src/libqof/qof/gnc-datetime.cpp
+++ b/src/libqof/qof/gnc-datetime.cpp
@@ -44,6 +44,7 @@ static const TimeZoneProvider tzp;
 // For converting to/from POSIX time.
 static const PTime unix_epoch (Date(1970, boost::gregorian::Jan, 1),
 	boost::posix_time::seconds(0));
+static const TZ_Ptr utc_zone(new boost::local_time::posix_time_zone("UTC-0"));
 
 /* To ensure things aren't overly screwed up by setting the nanosecond clock for boost::date_time. Don't do it, though, it doesn't get us anything and slows down the date/time library. */
 #ifndef BOOST_DATE_TIME_HAS_NANOSECONDS
@@ -63,10 +64,18 @@ public:
     GncDateImpl(Date d) : m_greg(d) {}
 
     void today() { m_greg = boost::gregorian::day_clock::local_day(); }
+    ymd ymd() const;
 private:
     Date m_greg;
 };
 
+ymd
+GncDateImpl::ymd() const
+{
+    auto boost_ymd = m_greg.year_month_day();
+    return {boost_ymd.year, boost_ymd.month.as_number(), boost_ymd.day};
+}
+
 /** Private implementation of GncDateTime. See the documentation for that class.
  */
 static LDT
@@ -95,6 +104,7 @@ public:
     GncDateTimeImpl() : m_time(unix_epoch, tzp.get(unix_epoch.date().year())) {}
     GncDateTimeImpl(const time64 time) : m_time(LDT_from_unix_local(time)) {}
     GncDateTimeImpl(const struct tm tm) : m_time(LDT_from_struct_tm(tm)) {}
+    GncDateTimeImpl(const std::string str);
     GncDateTimeImpl(PTime&& pt) : m_time(pt, tzp.get(pt.date().year())) {}
     GncDateTimeImpl(LDT&& ldt) : m_time(ldt) {}
 
@@ -102,11 +112,41 @@ public:
     operator struct tm() const;
     void now() { m_time = boost::local_time::local_sec_clock::local_time(tzp.get(boost::gregorian::day_clock::local_day().year())); }
     long offset() const;
+    long nsecs() const;
+    std::unique_ptr<GncDateImpl> date() const;
     std::string format(const char* format) const;
 private:
     LDT m_time;
 };
 
+GncDateTimeImpl::GncDateTimeImpl(const std::string str) :
+    m_time(unix_epoch, utc_zone)
+{
+    if (str.empty()) return;
+
+    using std::string;
+    using PTZ = boost::local_time::posix_time_zone;
+    TZ_Ptr tzptr;
+    auto tzpos = str.find_first_of("+-", str.find(":"));
+    if (tzpos != str.npos)
+    {
+	string tzstr = "XXX" + str.substr(tzpos);
+	if (tzstr.length() > 6 && tzstr[6] != ':') //6 for XXXsHH, s is + or -
+	    tzstr.insert(6, ":");
+	if (tzstr.length() > 9 && tzstr[9] != ':') //9 for XXXsHH:MM
+	    tzstr.insert(9, ":");
+	tzptr.reset(new PTZ(tzstr));
+	if (str[tzpos - 1] == ' ') --tzpos;
+    }
+    else
+    {
+	tzptr = utc_zone;
+    }
+
+    auto pdt = boost::posix_time::time_from_string(str.substr(0, tzpos));
+    m_time = LDT(pdt, tzptr);
+}
+
 GncDateTimeImpl::operator time64() const
 {
     auto duration = m_time.utc_time() - unix_epoch;
@@ -127,6 +167,18 @@ GncDateTimeImpl::offset() const
     return offset.total_seconds();
 }
 
+long
+GncDateTimeImpl::nsecs() const
+{
+	return (m_time.utc_time() - unix_epoch).ticks() % ticks_per_second;
+}
+
+std::unique_ptr<GncDateImpl>
+GncDateTimeImpl::date() const
+{
+    return std::unique_ptr<GncDateImpl>(new GncDateImpl(m_time.local_time().date()));
+}
+
 std::string
 GncDateTimeImpl::format(const char* format) const
 {
@@ -143,19 +195,33 @@ GncDateTimeImpl::format(const char* format) const
 GncDate::GncDate() : m_impl{new GncDateImpl} {}
 GncDate::GncDate(int year, int month, int day) :
     m_impl(new GncDateImpl(year, month, day)) {}
+GncDate::GncDate(std::unique_ptr<GncDateImpl> impl) :
+    m_impl(std::move(impl)) {}
+GncDate::GncDate(GncDate&&) = default;
 GncDate::~GncDate() = default;
 
+GncDate&
+GncDate::operator=(GncDate&&) = default;
+
 void
 GncDate::today()
 {
     m_impl->today();
 }
 
+ymd
+GncDate::ymd() const
+{
+    return m_impl->ymd();
+}
+
 GncDateTime::GncDateTime() : m_impl(new GncDateTimeImpl) {}
 GncDateTime::GncDateTime(const time64 time) :
     m_impl(new GncDateTimeImpl(time)) {}
 GncDateTime::GncDateTime(const struct tm tm) :
     m_impl(new GncDateTimeImpl(tm)) {}
+GncDateTime::GncDateTime(const std::string str) :
+    m_impl(new GncDateTimeImpl(str)) {}
 GncDateTime::~GncDateTime() = default;
 
 void
@@ -180,6 +246,18 @@ GncDateTime::offset() const
     return m_impl->offset();
 }
 
+long
+GncDateTime::nsecs() const
+{
+    return m_impl->nsecs();
+}
+
+GncDate
+GncDateTime::date() const
+{
+    return std::move(GncDate(m_impl->date()));
+}
+
 std::string
 GncDateTime::format(const char* format) const
 {
diff --git a/src/libqof/qof/gnc-datetime.hpp b/src/libqof/qof/gnc-datetime.hpp
index 938200c..e2fe6a7 100644
--- a/src/libqof/qof/gnc-datetime.hpp
+++ b/src/libqof/qof/gnc-datetime.hpp
@@ -27,6 +27,14 @@
 
 #include <cstdint>
 #include <memory>
+#include <string>
+
+typedef struct
+{
+    int year;  //1400-9999
+    int month; //1-12
+    int day; //1-31
+} ymd;
 
 class GncDateImpl;
 class GncDateTimeImpl;
@@ -34,8 +42,7 @@ using time64 = int64_t;
 
 class GncDate
 {
-public:
-/** Construct a GncDate representing the current day.
+public:/** Construct a GncDate representing the current day.
  */
     GncDate();;
 /** Construct a GncDate representing the given year, month, and day in
@@ -52,14 +59,21 @@ public:
  * of the constrained range.
  */
     GncDate(int year, int month, int day);
+    GncDate(std::unique_ptr<GncDateImpl> impl);
+    GncDate(GncDate&&);
     ~GncDate();
+    GncDate& operator=(GncDate&&);
 /** Set the date object to the computer clock's current day. */
     void today();
+/** Get the year, month, and day from the date as a ymd.
+    @return ymd struct
+ */
+    ymd ymd() const;
 /** Test that the Date has an implementation. */
     bool isnull (void) { return m_impl == nullptr; }
 
 private:
-	std::unique_ptr<GncDateImpl> m_impl;
+    std::unique_ptr<GncDateImpl> m_impl;
 };
 
 /** GnuCash DateTime class
@@ -88,13 +102,54 @@ public:
  * @exception std::invalid_argument if the year is outside the constraints.
  */
     GncDateTime(const time64 time);
+/** Construct a GncDateTime in the current timezone representing the
+ * standard struct tm provided.
+ * @param tm: A C-standard struct tm representing the date and
+ * time. Note that the timezone and offset are ignored on those
+ * systems which include them in struct tm.
+ * @exception std::invalid_argument if the year is outside the constraints.
+ */
     GncDateTime(const struct tm tm);
+/** Construct a GncDateTime 
+ * @param str: A string representing the date and time in some
+ * recognizable format. Note that if a timezone is not specified the
+ * default is UTC, not the local one.
+ * @exception std::invalid_argument if the year is outside the constraints.
+ */
+    GncDateTime(const std::string str);
     ~GncDateTime();
+/** Set the GncDateTime to the date and time indicated in the computer's clock.
+ */
     void now();
+/** Cast the GncDateTime to a time64, seconds from the POSIX epoch. */
     explicit operator time64() const;
+/** Cast the GncDateTime to a struct tm. Timezone and offset fields
+ * are not filled.
+ */
     explicit operator struct tm() const;
-    long offset() const;
+/** Obtain the UTC offset in seconds
+ *  @return seconds difference between this local time and UTC. West
+ *  is negative.
+ */
+    long offset()const;
+/** Obtain the fractional seconds from the GncDateTime
+ *  @return Fractional seconds, represented as nanoseconds, associated
+ *  with the time.
+ */
+    long nsecs() const;
+/** Obtain the date from the time, as a GncDate, in the current timezone.
+ *  @return GncDate represented by the GncDateTime.
+ */
+    GncDate date() const;
+/** Test if the GncDateTime has a member pointer. Testing only. */
     bool isnull (void) { return m_impl == nullptr; }
+/** Format the GncDateTime into a std::string
+
+ *  @return a std::string containing a representation of the date
+ *  according to the format. Consult the boost::date_time
+ *  documentation for format characters; while they mostly compy with
+ *  POSIX there are a few differences.
+ */
     std::string format(const char* format) const;
 
 private:
diff --git a/src/libqof/qof/test/Makefile.am b/src/libqof/qof/test/Makefile.am
index 84dfa86..f81ddc0 100644
--- a/src/libqof/qof/test/Makefile.am
+++ b/src/libqof/qof/test/Makefile.am
@@ -95,7 +95,9 @@ test_gnc_datetime_CPPFLAGS =\
 	-I$(GTEST_HEADERS) \
 	-I$(top_srcdir)/src \
 	$(BOOST_CPPFLAGS)
-test_gnc_datetime_LDADD = $(GTEST_LIBS)
+test_gnc_datetime_LDADD = \
+	-lboost_date_time \
+	$(GTEST_LIBS)
 if !GOOGLE_TEST_LIBS
 nodist_test_gnc_datetime_SOURCES = \
 	$(GTEST_SRC)/src/gtest_main.cc
diff --git a/src/libqof/qof/test/gtest-gnc-datetime.cpp b/src/libqof/qof/test/gtest-gnc-datetime.cpp
index b49ea96..da47b0c 100644
--- a/src/libqof/qof/test/gtest-gnc-datetime.cpp
+++ b/src/libqof/qof/test/gtest-gnc-datetime.cpp
@@ -76,3 +76,14 @@ TEST(gnc_datetime_functions, test_format)
     //Date only to finesse timezone issues. It will still fail in +12 DST.
     EXPECT_EQ(atime.format("%d-%m-%Y"), "13-11-2045");
 }
+
+//This is a bit convoluted because it uses GncDate's GncDateImpl constructor and ymd() function. There's no good way to test the former without violating the privacy of the implementation.
+TEST(gnc_datetime_functions, test_date)
+{
+    GncDateTime atime(2394187200); //2045-11-13 12:00:00 Z
+    GncDate gncd = std::move(atime.date());
+    auto ymd = gncd.ymd();
+    EXPECT_EQ(ymd.year, 2045);
+    EXPECT_EQ(ymd.month, 11);
+    EXPECT_EQ(ymd.day, 13);
+}

commit 3f87f56e2ed41e5c93c284dc19c375f155176430
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Apr 26 18:01:23 2015 -0700

    Implement formatted output.

diff --git a/src/libqof/qof/gnc-datetime.cpp b/src/libqof/qof/gnc-datetime.cpp
index f2ab5b6..c41bec5 100644
--- a/src/libqof/qof/gnc-datetime.cpp
+++ b/src/libqof/qof/gnc-datetime.cpp
@@ -102,7 +102,7 @@ public:
     operator struct tm() const;
     void now() { m_time = boost::local_time::local_sec_clock::local_time(tzp.get(boost::gregorian::day_clock::local_day().year())); }
     long offset() const;
-
+    std::string format(const char* format) const;
 private:
     LDT m_time;
 };
@@ -127,6 +127,18 @@ GncDateTimeImpl::offset() const
     return offset.total_seconds();
 }
 
+std::string
+GncDateTimeImpl::format(const char* format) const
+{
+    using Facet = boost::local_time::local_time_facet;
+    std::stringstream ss;
+    //The stream destructor frees the facet, so it must be heap-allocated.
+    auto output_facet(new Facet(format));
+    ss.imbue(std::locale(std::locale(), output_facet));
+    ss << m_time;
+    return ss.str();
+}
+
 /* =================== Presentation-class Implementations ====================*/
 GncDate::GncDate() : m_impl{new GncDateImpl} {}
 GncDate::GncDate(int year, int month, int day) :
@@ -167,3 +179,9 @@ GncDateTime::offset() const
 {
     return m_impl->offset();
 }
+
+std::string
+GncDateTime::format(const char* format) const
+{
+    return m_impl->format(format);
+}
diff --git a/src/libqof/qof/gnc-datetime.hpp b/src/libqof/qof/gnc-datetime.hpp
index d676d59..938200c 100644
--- a/src/libqof/qof/gnc-datetime.hpp
+++ b/src/libqof/qof/gnc-datetime.hpp
@@ -95,6 +95,7 @@ public:
     explicit operator struct tm() const;
     long offset() const;
     bool isnull (void) { return m_impl == nullptr; }
+    std::string format(const char* format) const;
 
 private:
     std::unique_ptr<GncDateTimeImpl> m_impl;
diff --git a/src/libqof/qof/test/gtest-gnc-datetime.cpp b/src/libqof/qof/test/gtest-gnc-datetime.cpp
index dab386f..b49ea96 100644
--- a/src/libqof/qof/test/gtest-gnc-datetime.cpp
+++ b/src/libqof/qof/test/gtest-gnc-datetime.cpp
@@ -69,3 +69,10 @@ TEST(gnc_datetime_constructors, test_struct_tm_constructor)
     EXPECT_EQ((24 + tm1.tm_hour - atime.offset() / 3600) % 24, tm.tm_hour);
     EXPECT_EQ(tm1.tm_min, tm.tm_min);
 }
+
+TEST(gnc_datetime_functions, test_format)
+{
+    GncDateTime atime(2394187200); //2045-11-13 12:00:00 Z
+    //Date only to finesse timezone issues. It will still fail in +12 DST.
+    EXPECT_EQ(atime.format("%d-%m-%Y"), "13-11-2045");
+}

commit cbb01c94ae8d76a01d08410b09d7e4e74e3bca0f
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Apr 26 16:44:39 2015 -0700

    Implement struct tm constructor and cast, offset accessor.

diff --git a/src/libqof/qof/gnc-datetime.cpp b/src/libqof/qof/gnc-datetime.cpp
index 7c5774b..f2ab5b6 100644
--- a/src/libqof/qof/gnc-datetime.cpp
+++ b/src/libqof/qof/gnc-datetime.cpp
@@ -79,16 +79,29 @@ LDT_from_unix_local(const time64 time)
     return LDT(temp, tz);
 }
 
+static LDT
+LDT_from_struct_tm(const struct tm tm)
+{
+    auto tdate = boost::gregorian::date_from_tm(tm);
+    auto tdur = boost::posix_time::time_duration(tm.tm_hour, tm.tm_min,
+						 tm.tm_sec, 0);
+    auto tz = tzp.get(tdate.year());
+    return LDT(PTime(tdate, tdur), tz);
+}
+
 class GncDateTimeImpl
 {
 public:
     GncDateTimeImpl() : m_time(unix_epoch, tzp.get(unix_epoch.date().year())) {}
     GncDateTimeImpl(const time64 time) : m_time(LDT_from_unix_local(time)) {}
+    GncDateTimeImpl(const struct tm tm) : m_time(LDT_from_struct_tm(tm)) {}
     GncDateTimeImpl(PTime&& pt) : m_time(pt, tzp.get(pt.date().year())) {}
     GncDateTimeImpl(LDT&& ldt) : m_time(ldt) {}
 
     operator time64() const;
+    operator struct tm() const;
     void now() { m_time = boost::local_time::local_sec_clock::local_time(tzp.get(boost::gregorian::day_clock::local_day().year())); }
+    long offset() const;
 
 private:
     LDT m_time;
@@ -102,6 +115,18 @@ GncDateTimeImpl::operator time64() const
     return secs;
 }
 
+GncDateTimeImpl::operator struct tm() const
+{
+    return to_tm(m_time);
+}
+
+long
+GncDateTimeImpl::offset() const
+{
+    auto offset = m_time.local_time() - m_time.utc_time();
+    return offset.total_seconds();
+}
+
 /* =================== Presentation-class Implementations ====================*/
 GncDate::GncDate() : m_impl{new GncDateImpl} {}
 GncDate::GncDate(int year, int month, int day) :
@@ -115,7 +140,10 @@ GncDate::today()
 }
 
 GncDateTime::GncDateTime() : m_impl(new GncDateTimeImpl) {}
-GncDateTime::GncDateTime(time64 time) : m_impl(new GncDateTimeImpl(time)) {}
+GncDateTime::GncDateTime(const time64 time) :
+    m_impl(new GncDateTimeImpl(time)) {}
+GncDateTime::GncDateTime(const struct tm tm) :
+    m_impl(new GncDateTimeImpl(tm)) {}
 GncDateTime::~GncDateTime() = default;
 
 void
@@ -128,3 +156,14 @@ GncDateTime::operator time64() const
 {
     return m_impl->operator time64();
 }
+
+GncDateTime::operator struct tm() const
+{
+    return m_impl->operator struct tm();
+}
+
+long
+GncDateTime::offset() const
+{
+    return m_impl->offset();
+}
diff --git a/src/libqof/qof/gnc-datetime.hpp b/src/libqof/qof/gnc-datetime.hpp
index 015b884..d676d59 100644
--- a/src/libqof/qof/gnc-datetime.hpp
+++ b/src/libqof/qof/gnc-datetime.hpp
@@ -87,10 +87,13 @@ public:
  * @param time: Seconds from the POSIX epoch.
  * @exception std::invalid_argument if the year is outside the constraints.
  */
-    GncDateTime(time64 time);
+    GncDateTime(const time64 time);
+    GncDateTime(const struct tm tm);
     ~GncDateTime();
     void now();
     explicit operator time64() const;
+    explicit operator struct tm() const;
+    long offset() const;
     bool isnull (void) { return m_impl == nullptr; }
 
 private:
diff --git a/src/libqof/qof/test/gtest-gnc-datetime.cpp b/src/libqof/qof/test/gtest-gnc-datetime.cpp
index 4f41147..dab386f 100644
--- a/src/libqof/qof/test/gtest-gnc-datetime.cpp
+++ b/src/libqof/qof/test/gtest-gnc-datetime.cpp
@@ -50,3 +50,22 @@ TEST(gnc_datetime_constructors, test_time64_constructor)
     EXPECT_EQ(static_cast<time64>(atime), time);
 }
 
+TEST(gnc_datetime_constructors, test_struct_tm_constructor)
+{
+#ifdef HAVE_STRUCT_TM_GMTOFF
+    const struct tm tm {0, 0, 12, 13, 10, 145, 0, 0, 0, NULL, 0 };
+#else
+    const struct tm tm {0, 0, 12, 13, 10, 145, 0, 0, 0 };
+#endif
+
+    const time64 time = 2394187200; //2045-11-13 12:00:00 Z
+    GncDateTime atime(tm);
+    EXPECT_EQ(static_cast<time64>(atime), time);
+    const struct tm tm1 = static_cast<struct tm>(atime);
+    EXPECT_EQ(tm1.tm_year, tm.tm_year);
+    EXPECT_EQ(tm1.tm_mon, tm.tm_mon);
+    EXPECT_EQ(tm1.tm_mday, tm.tm_mday);
+// We have to contort this a bit to handle offsets > 12, e.g. New Zealand during DST.
+    EXPECT_EQ((24 + tm1.tm_hour - atime.offset() / 3600) % 24, tm.tm_hour);
+    EXPECT_EQ(tm1.tm_min, tm.tm_min);
+}

commit e5861dc119aa3fc15dc8c30bf746cf969d5a19d4
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Apr 10 09:33:51 2015 -0700

    Add operator time64() to enable static_casting a GncDateTime.

diff --git a/src/libqof/qof/gnc-datetime.cpp b/src/libqof/qof/gnc-datetime.cpp
index 0cf4412..7c5774b 100644
--- a/src/libqof/qof/gnc-datetime.cpp
+++ b/src/libqof/qof/gnc-datetime.cpp
@@ -86,11 +86,20 @@ public:
     GncDateTimeImpl(const time64 time) : m_time(LDT_from_unix_local(time)) {}
     GncDateTimeImpl(PTime&& pt) : m_time(pt, tzp.get(pt.date().year())) {}
     GncDateTimeImpl(LDT&& ldt) : m_time(ldt) {}
+
+    operator time64() const;
     void now() { m_time = boost::local_time::local_sec_clock::local_time(tzp.get(boost::gregorian::day_clock::local_day().year())); }
 
 private:
     LDT m_time;
 };
+
+GncDateTimeImpl::operator time64() const
+{
+    auto duration = m_time.utc_time() - unix_epoch;
+    auto secs = duration.ticks();
+    secs /= ticks_per_second;
+    return secs;
 }
 
 /* =================== Presentation-class Implementations ====================*/
@@ -114,4 +123,8 @@ GncDateTime::now()
 {
     m_impl->now();
 }
+
+GncDateTime::operator time64() const
+{
+    return m_impl->operator time64();
 }
diff --git a/src/libqof/qof/gnc-datetime.hpp b/src/libqof/qof/gnc-datetime.hpp
index c70f045..015b884 100644
--- a/src/libqof/qof/gnc-datetime.hpp
+++ b/src/libqof/qof/gnc-datetime.hpp
@@ -90,6 +90,7 @@ public:
     GncDateTime(time64 time);
     ~GncDateTime();
     void now();
+    explicit operator time64() const;
     bool isnull (void) { return m_impl == nullptr; }
 
 private:
diff --git a/src/libqof/qof/test/gtest-gnc-datetime.cpp b/src/libqof/qof/test/gtest-gnc-datetime.cpp
index 4a3d288..4f41147 100644
--- a/src/libqof/qof/test/gtest-gnc-datetime.cpp
+++ b/src/libqof/qof/test/gtest-gnc-datetime.cpp
@@ -40,12 +40,13 @@ TEST(gnc_date_constructors, test_ymd_constructor)
 TEST(gnc_datetime_constructors, test_default_constructor)
 {
     GncDateTime atime;
-    EXPECT_FALSE(atime.isnull());
+    EXPECT_EQ(static_cast<time64>(atime), static_cast<time64>(INT64_C(0)));
 }
 
 TEST(gnc_datetime_constructors, test_time64_constructor)
 {
     const time64 time = 2394187200; //2045-11-13 12:00:00 Z
     GncDateTime atime(time);
-    EXPECT_FALSE(atime.isnull());
+    EXPECT_EQ(static_cast<time64>(atime), time);
 }
+

commit 10daa27abc22bb122ecc504865e22a58c41b073a
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Apr 7 15:36:40 2015 -0700

    Default constructors return the epoch.
    
    GncDate::today() and GncDateTime::now() get the current date and time.
    
    Suggested in a C++Now talk by Jeff Garland, the author of boost::date_time.
    Reasoning is that getting time from the system clock is expensive and so
    shouldn't be done unless needed.

diff --git a/src/libqof/qof/gnc-datetime.cpp b/src/libqof/qof/gnc-datetime.cpp
index 12d7673..0cf4412 100644
--- a/src/libqof/qof/gnc-datetime.cpp
+++ b/src/libqof/qof/gnc-datetime.cpp
@@ -45,30 +45,30 @@ static const TimeZoneProvider tzp;
 static const PTime unix_epoch (Date(1970, boost::gregorian::Jan, 1),
 	boost::posix_time::seconds(0));
 
+/* To ensure things aren't overly screwed up by setting the nanosecond clock for boost::date_time. Don't do it, though, it doesn't get us anything and slows down the date/time library. */
+#ifndef BOOST_DATE_TIME_HAS_NANOSECONDS
+static constexpr auto ticks_per_second = INT64_C(1000000);
+#else
+static constexpr auto ticks_per_second = INT64_C(1000000000);
+#endif
 
 /** Private implementation of GncDate. See the documentation for that class.
  */
 class GncDateImpl
 {
 public:
-    GncDateImpl(): m_greg(boost::gregorian::day_clock::local_day()) {}
+    GncDateImpl(): m_greg(unix_epoch.date()) {}
     GncDateImpl(const int year, const int month, const int day) :
 	m_greg(year, static_cast<Month>(month), day) {}
+    GncDateImpl(Date d) : m_greg(d) {}
+
+    void today() { m_greg = boost::gregorian::day_clock::local_day(); }
 private:
     Date m_greg;
 };
 
 /** Private implementation of GncDateTime. See the documentation for that class.
  */
-class GncDateTimeImpl
-{
-public:
-    GncDateTimeImpl() : m_time(boost::local_time::local_sec_clock::local_time(tzp.get(boost::gregorian::day_clock::local_day().year()))) {}
-    GncDateTimeImpl(const time64 time);
-private:
-    LDT m_time;
-};
-
 static LDT
 LDT_from_unix_local(const time64 time)
 {
@@ -79,14 +79,39 @@ LDT_from_unix_local(const time64 time)
     return LDT(temp, tz);
 }
 
-GncDateTimeImpl::GncDateTimeImpl(const time64 time) :
-    m_time(LDT_from_unix_local(time)) {}
+class GncDateTimeImpl
+{
+public:
+    GncDateTimeImpl() : m_time(unix_epoch, tzp.get(unix_epoch.date().year())) {}
+    GncDateTimeImpl(const time64 time) : m_time(LDT_from_unix_local(time)) {}
+    GncDateTimeImpl(PTime&& pt) : m_time(pt, tzp.get(pt.date().year())) {}
+    GncDateTimeImpl(LDT&& ldt) : m_time(ldt) {}
+    void now() { m_time = boost::local_time::local_sec_clock::local_time(tzp.get(boost::gregorian::day_clock::local_day().year())); }
 
+private:
+    LDT m_time;
+};
+}
+
+/* =================== Presentation-class Implementations ====================*/
 GncDate::GncDate() : m_impl{new GncDateImpl} {}
 GncDate::GncDate(int year, int month, int day) :
     m_impl(new GncDateImpl(year, month, day)) {}
 GncDate::~GncDate() = default;
 
+void
+GncDate::today()
+{
+    m_impl->today();
+}
+
 GncDateTime::GncDateTime() : m_impl(new GncDateTimeImpl) {}
 GncDateTime::GncDateTime(time64 time) : m_impl(new GncDateTimeImpl(time)) {}
 GncDateTime::~GncDateTime() = default;
+
+void
+GncDateTime::now()
+{
+    m_impl->now();
+}
+}
diff --git a/src/libqof/qof/gnc-datetime.hpp b/src/libqof/qof/gnc-datetime.hpp
index b145357..c70f045 100644
--- a/src/libqof/qof/gnc-datetime.hpp
+++ b/src/libqof/qof/gnc-datetime.hpp
@@ -53,7 +53,9 @@ public:
  */
     GncDate(int year, int month, int day);
     ~GncDate();
-
+/** Set the date object to the computer clock's current day. */
+    void today();
+/** Test that the Date has an implementation. */
     bool isnull (void) { return m_impl == nullptr; }
 
 private:
@@ -87,7 +89,7 @@ public:
  */
     GncDateTime(time64 time);
     ~GncDateTime();
-
+    void now();
     bool isnull (void) { return m_impl == nullptr; }
 
 private:

commit 01f5a9c04c4c78f5021470a8297142a0704202b4
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Mar 27 10:00:15 2015 +0900

    Update filename, copyright in comments for gnu-date.c

diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index f523546..db6f22e 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -1,9 +1,9 @@
 /********************************************************************\
- * gnc-date.c -- misc utility functions to handle date and time     *
- *         (to be renamed qofdate.c in libqof2)                     *
+ * gnc-date.cpp -- C interface for date and time                    *
  *                                                                  *
- * Copyright (C) 1997 Robin D. Clark <rclark at cs.hmc.edu>            *
- * Copyright (C) 1998-2000, 2003 Linas Vepstas <linas at linas.org>    *
+ * Copyright 1997 Robin D. Clark <rclark at cs.hmc.edu>                *
+ * Copyright 1998-2000, 2003 Linas Vepstas <linas at linas.org>        *
+ * Copyright 2011-2015 John Ralls <jralls at ceridwen.us               *
  *                                                                  *
  * This program is free software; you can redistribute it and/or    *
  * modify it under the terms of the GNU General Public License as   *
@@ -45,6 +45,7 @@ extern "C"
 
 #include "gnc-date.h"
 #include "gnc-date-p.h"
+//#include "gnc-datetime.hpp"
 
 #include "gnc-timezone.hpp"
 #define N_(string) string //So that xgettext will find it

commit 307c08e2b5c6bc00c0b106a570af2bba6e9afd77
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Mar 27 09:59:06 2015 +0900

    Begin GncDate and GncDateTime classes.
    
    Goal is to get the boost::date_time code out of gnu-date.c, to provide
    date-time functionality directly to C++, and to replace GDate.

diff --git a/src/libqof/qof/gnc-datetime.cpp b/src/libqof/qof/gnc-datetime.cpp
new file mode 100644
index 0000000..12d7673
--- /dev/null
+++ b/src/libqof/qof/gnc-datetime.cpp
@@ -0,0 +1,92 @@
+/********************************************************************\
+ * gnc-datetime.cpp -- Date and Time classes for GnuCash            *
+ *                                                                  *
+ * Copyright 2015 John Ralls <jralls at ceridwen.us>                   *
+ *                                                                  *
+ * This program is free software; you can redistribute it and/or    *
+ * modify it under the terms of the GNU General Public License as   *
+ * published by the Free Software Foundation; either version 2 of   *
+ * the License, or (at your option) any later version.              *
+ *                                                                  *
+ * This program 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 General Public License for more details.                     *
+ *                                                                  *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact:                        *
+ *                                                                  *
+ * Free Software Foundation           Voice:  +1-617-542-5942       *
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
+ *                                                                  *
+\********************************************************************/
+
+extern "C"
+{
+#include "config.h"
+#include "platform.h"
+}
+#include <boost/date_time/gregorian/gregorian.hpp>
+#include <memory>
+#include "gnc-timezone.hpp"
+#include "gnc-datetime.hpp"
+
+using Date = boost::gregorian::date;
+using Month = boost::gregorian::greg_month;
+using PTime = boost::posix_time::ptime;
+using LDT = boost::local_time::local_date_time;
+using Duration = boost::posix_time::time_duration;
+using LDTBase = boost::local_time::local_date_time_base<PTime, boost::date_time::time_zone_base<PTime, char>>;
+using time64 = int64_t;
+
+static const TimeZoneProvider tzp;
+// For converting to/from POSIX time.
+static const PTime unix_epoch (Date(1970, boost::gregorian::Jan, 1),
+	boost::posix_time::seconds(0));
+
+
+/** Private implementation of GncDate. See the documentation for that class.
+ */
+class GncDateImpl
+{
+public:
+    GncDateImpl(): m_greg(boost::gregorian::day_clock::local_day()) {}
+    GncDateImpl(const int year, const int month, const int day) :
+	m_greg(year, static_cast<Month>(month), day) {}
+private:
+    Date m_greg;
+};
+
+/** Private implementation of GncDateTime. See the documentation for that class.
+ */
+class GncDateTimeImpl
+{
+public:
+    GncDateTimeImpl() : m_time(boost::local_time::local_sec_clock::local_time(tzp.get(boost::gregorian::day_clock::local_day().year()))) {}
+    GncDateTimeImpl(const time64 time);
+private:
+    LDT m_time;
+};
+
+static LDT
+LDT_from_unix_local(const time64 time)
+{
+    PTime temp(unix_epoch.date(),
+	       boost::posix_time::hours(time / 3600) +
+	       boost::posix_time::seconds(time % 3600));
+    auto tz = tzp.get(temp.date().year());
+    return LDT(temp, tz);
+}
+
+GncDateTimeImpl::GncDateTimeImpl(const time64 time) :
+    m_time(LDT_from_unix_local(time)) {}
+
+GncDate::GncDate() : m_impl{new GncDateImpl} {}
+GncDate::GncDate(int year, int month, int day) :
+    m_impl(new GncDateImpl(year, month, day)) {}
+GncDate::~GncDate() = default;
+
+GncDateTime::GncDateTime() : m_impl(new GncDateTimeImpl) {}
+GncDateTime::GncDateTime(time64 time) : m_impl(new GncDateTimeImpl(time)) {}
+GncDateTime::~GncDateTime() = default;
diff --git a/src/libqof/qof/gnc-datetime.hpp b/src/libqof/qof/gnc-datetime.hpp
new file mode 100644
index 0000000..b145357
--- /dev/null
+++ b/src/libqof/qof/gnc-datetime.hpp
@@ -0,0 +1,97 @@
+/********************************************************************\
+ * gnc-datetime.cpp -- Date and Time classes for GnuCash            *
+ *                                                                  *
+ * Copyright 2015 John Ralls <jralls at ceridwen.us>                   *
+ *                                                                  *
+ * This program is free software; you can redistribute it and/or    *
+ * modify it under the terms of the GNU General Public License as   *
+ * published by the Free Software Foundation; either version 2 of   *
+ * the License, or (at your option) any later version.              *
+ *                                                                  *
+ * This program 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 General Public License for more details.                     *
+ *                                                                  *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact:                        *
+ *                                                                  *
+ * Free Software Foundation           Voice:  +1-617-542-5942       *
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
+ *                                                                  *
+\********************************************************************/
+
+#ifndef __GNC_DATETIME_HPP__
+#define  __GNC_DATETIME_HPP__
+
+#include <cstdint>
+#include <memory>
+
+class GncDateImpl;
+class GncDateTimeImpl;
+using time64 = int64_t;
+
+class GncDate
+{
+public:
+/** Construct a GncDate representing the current day.
+ */
+    GncDate();;
+/** Construct a GncDate representing the given year, month, and day in
+ * the proleptic Gregorian calendar.
+ *
+ * Years are constrained to be from 1400 - 9999 CE inclusive. Dates
+ * will be normalized if the day or month values are outside of the
+ * normal ranges. e.g. 1994, -3, 47 will be normalized to 1993-10-17.
+ *
+ * @param year: The year in the Common Era.
+ * @param month: The month, where 1 is January and 12 is December.
+ * @param day: The day of the month, beginning with 1.
+ * @exception std::invalid_argument if the calculated year is outside
+ * of the constrained range.
+ */
+    GncDate(int year, int month, int day);
+    ~GncDate();
+
+    bool isnull (void) { return m_impl == nullptr; }
+
+private:
+	std::unique_ptr<GncDateImpl> m_impl;
+};
+
+/** GnuCash DateTime class
+ *
+ * Represents local time in the current timezone.
+ * As with GncDate, the represented time is limited to the period
+ * between 1400 and 9999 CE.
+ *
+ * Be careful when using times: A particular time is represented
+ * differently depending on the timezone, which can shif the displayed
+ * date. Accounting is generally not sensitive to the time of day, but
+ * is sensitive to the recorded day. Since GncDates are not timezone
+ * dependent they should be preferred for accounting entries.
+ */
+
+class GncDateTime
+{
+public:
+/** Construct a GncDateTime representing the current time in the
+ * current timezone.
+ */
+    GncDateTime();
+/** Construct a GncDateTime in the current timezone representing the
+ * timestamp as seconds from the POSIX epoch (1970-01-01T00:00:00UTC).
+ * @param time: Seconds from the POSIX epoch.
+ * @exception std::invalid_argument if the year is outside the constraints.
+ */
+    GncDateTime(time64 time);
+    ~GncDateTime();
+
+    bool isnull (void) { return m_impl == nullptr; }
+
+private:
+    std::unique_ptr<GncDateTimeImpl> m_impl;
+};
+
+#endif // __GNC_DATETIME_HPP__
diff --git a/src/libqof/qof/test/Makefile.am b/src/libqof/qof/test/Makefile.am
index 15ed8fc..84dfa86 100644
--- a/src/libqof/qof/test/Makefile.am
+++ b/src/libqof/qof/test/Makefile.am
@@ -86,6 +86,23 @@ nodist_test_gnc_timezone_SOURCES = \
 test_gnc_timezone_LDADD += $(top_builddir)/src/test-core/libgtest.a
 endif
 check_PROGRAMS += test-gnc-timezone
+
+test_gnc_datetime_SOURCES = \
+	$(top_srcdir)/$(MODULEPATH)/gnc-datetime.cpp \
+	$(top_srcdir)/$(MODULEPATH)/gnc-timezone.cpp \
+	gtest-gnc-datetime.cpp
+test_gnc_datetime_CPPFLAGS =\
+	-I$(GTEST_HEADERS) \
+	-I$(top_srcdir)/src \
+	$(BOOST_CPPFLAGS)
+test_gnc_datetime_LDADD = $(GTEST_LIBS)
+if !GOOGLE_TEST_LIBS
+nodist_test_gnc_datetime_SOURCES = \
+	$(GTEST_SRC)/src/gtest_main.cc
+test_gnc_datetime_LDADD += $(top_builddir)/src/test-core/libgtest.a
+endif
+check_PROGRAMS += test-gnc-datetime
+
 endif
 
 test_qofdir = ${GNC_LIBEXECDIR}/${MODULEPATH}/test
diff --git a/src/libqof/qof/test/gtest-gnc-datetime.cpp b/src/libqof/qof/test/gtest-gnc-datetime.cpp
new file mode 100644
index 0000000..4a3d288
--- /dev/null
+++ b/src/libqof/qof/test/gtest-gnc-datetime.cpp
@@ -0,0 +1,51 @@
+/********************************************************************\
+ * test-gnc-datetime.cpp -- Unit tests for GncDate and GncDateTime  *
+ *                                                                  *
+ * Copyright 2015 John Ralls <jralls at ceridwen.us>                   *
+ *                                                                  *
+ * This program is free software; you can redistribute it and/or    *
+ * modify it under the terms of the GNU General Public License as   *
+ * published by the Free Software Foundation; either version 2 of   *
+ * the License, or (at your option) any later version.              *
+ *                                                                  *
+ * This program 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 General Public License for more details.                     *
+ *                                                                  *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact:                        *
+ *                                                                  *
+ * Free Software Foundation           Voice:  +1-617-542-5942       *
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
+ *                                                                  *
+\********************************************************************/
+
+#include "../gnc-datetime.hpp"
+#include <gtest/gtest.h>
+
+TEST(gnc_date_constructors, test_default_constructor)
+{
+    GncDate date;
+    EXPECT_FALSE(date.isnull());
+}
+
+TEST(gnc_date_constructors, test_ymd_constructor)
+{
+    GncDate date(2045, 11, 13);
+    EXPECT_FALSE(date.isnull());
+}
+
+TEST(gnc_datetime_constructors, test_default_constructor)
+{
+    GncDateTime atime;
+    EXPECT_FALSE(atime.isnull());
+}
+
+TEST(gnc_datetime_constructors, test_time64_constructor)
+{
+    const time64 time = 2394187200; //2045-11-13 12:00:00 Z
+    GncDateTime atime(time);
+    EXPECT_FALSE(atime.isnull());
+}

commit 09356976cc7929fa9e2504dbbef69e0fc7d81e55
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Mar 23 17:04:26 2015 +0900

    Fix test-aqb timestamp so that it's 29 August in most timezones.

diff --git a/src/import-export/aqb/test/file-book-hbcislot.gnucash b/src/import-export/aqb/test/file-book-hbcislot.gnucash
index e4b6c00..41d0f65 100644
--- a/src/import-export/aqb/test/file-book-hbcislot.gnucash
+++ b/src/import-export/aqb/test/file-book-hbcislot.gnucash
@@ -109,7 +109,7 @@
         <slot>
           <slot:key>trans-retrieval</slot:key>
           <slot:value type="timespec">
-            <ts:date>2014-08-29 20:47:36 +0200</ts:date>
+            <ts:date>2014-08-29 13:47:36 +0200</ts:date>
           </slot:value>
         </slot>
       </slot:value>

commit d0ae8c370ea94133537403d036d07bbe2ae9a534
Author: John Ralls <john at aeolus.local>
Date:   Mon Mar 23 11:35:05 2015 +0900

    Fix stray if and tab-indentation.

diff --git a/src/libqof/qof/test/test-gnc-date.c b/src/libqof/qof/test/test-gnc-date.c
index 3f1a7c4..93f9943 100644
--- a/src/libqof/qof/test/test-gnc-date.c
+++ b/src/libqof/qof/test/test-gnc-date.c
@@ -1,6 +1,6 @@
 /********************************************************************
- * utest-gnc-date.c: GLib g_test test suite for gnc-date.c.	    *
- * Copyright 2012 John Ralls <jralls at ceridwen.us>		    *
+ * utest-gnc-date.c: GLib g_test test suite for gnc-date.c.         *
+ * Copyright 2012 John Ralls <jralls at ceridwen.us>                   *
  *                                                                  *
  * This program is free software; you can redistribute it and/or    *
  * modify it under the terms of the GNU General Public License as   *
@@ -144,20 +144,19 @@ test_gnc_localtime (void)
                       1364160236LL};
     guint ind;
     if (sizeof(time_t) < sizeof(time64))
-	secs[0] = -432761LL;
+        secs[0] = -432761LL;
     for (ind = 0; ind < G_N_ELEMENTS (secs); ind++)
     {
-	if (sizeof(time_t) == sizeof())
         struct tm* time = gnc_localtime (&secs[ind]);
-	time_t tsecs;
-	struct tm* ans;
+        time_t tsecs;
+        struct tm* ans;
         if (secs[ind] > max_secs)
         {
             g_assert (time == NULL);
             continue;
         }
-	tsecs = (time_t)(secs[ind]);
-	ans = localtime(&tsecs);
+        tsecs = (time_t)(secs[ind]);
+        ans = localtime(&tsecs);
         g_assert_cmpint (time->tm_year, ==, ans->tm_year);
         g_assert_cmpint (time->tm_mon, ==, ans->tm_mon);
         g_assert_cmpint (time->tm_mday, ==, ans->tm_mday);
@@ -166,7 +165,7 @@ test_gnc_localtime (void)
         g_assert_cmpint (time->tm_sec, ==, ans->tm_sec);
         g_assert_cmpint (time->tm_wday, ==, ans->tm_wday);
         g_assert_cmpint (time->tm_yday, ==, ans->tm_yday);
-	g_assert_cmpint (time->tm_isdst, ==, ans->tm_isdst);
+        g_assert_cmpint (time->tm_isdst, ==, ans->tm_isdst);
 #ifdef HAVE_STRUCT_TM_GMTOFF
         g_assert_cmpint (time->tm_gmtoff, ==, ans->tm_gmtoff);
 #endif
@@ -315,11 +314,11 @@ test_gnc_ctime (void)
     guint ind;
     for (ind = 0; ind < G_N_ELEMENTS (secs); ind++)
     {
-	 time_t time;
-	 char *datestr;
-	if (secs[ind] < INT32_MIN)
-	    continue;
-	time = (time_t)secs[ind];
+         time_t time;
+         char *datestr;
+        if (secs[ind] < INT32_MIN)
+            continue;
+        time = (time_t)secs[ind];
         datestr = gnc_ctime (&secs[ind]);
         g_assert_cmpstr (datestr, ==, strtok(ctime(&time), "\n"));
         g_free (datestr);
@@ -451,10 +450,10 @@ test_gnc_setlocale (int category, gchar *locale)
             return;
     }
     g_fprintf (stderr, "There are some differences between distros in the way they name"
-	      "locales, and this can cause trouble with the locale-based"
-	      "formatting. If you get the assert in this function, run locale -a"
-	      "and make sure that en_US, en_GB, and fr_FR are installed and that"
-	      "if a suffix is needed it's in the suffixes array.");
+              "locales, and this can cause trouble with the locale-based"
+              "formatting. If you get the assert in this function, run locale -a"
+              "and make sure that en_US, en_GB, and fr_FR are installed and that"
+              "if a suffix is needed it's in the suffixes array.");
     g_assert_not_reached ();
 }
 /* timespec_normalize
@@ -695,7 +694,7 @@ test_timespecCanonicalDayTime (void)
     g_assert_cmpint (na.tv_sec, ==, ra.tv_sec);
     g_assert_cmpint (nb.tv_sec, ==, rb.tv_sec);
     if (sizeof(time_t) >= sizeof(time64))
-	g_assert_cmpint (nc.tv_sec, ==, rc.tv_sec);
+        g_assert_cmpint (nc.tv_sec, ==, rc.tv_sec);
 }
 
 /* gnc_date_get_last_mday
@@ -954,7 +953,7 @@ test_qof_print_date_dmy_buff (void)
         gchar t_buff[MAX_DATE_LENGTH];                                  \
         struct tm *ltime = gnc_localtime ((time64 *)(&time));           \
         strftime (t_buff, sizeof (t_buff), GNC_D_FMT, ltime);           \
-	gnc_tm_free (ltime);                                            \
+        gnc_tm_free (ltime);                                            \
         g_assert_cmpstr (datestr, ==, t_buff);                          \
     }
 
@@ -1215,14 +1214,14 @@ test_qof_print_gdate (void)
 #define test_assert_qof_print_date(time, datestr)  \
     {                                              \
         gchar *buf = qof_print_date (time);        \
-	g_assert_cmpstr (buf, ==, datestr);	   \
+        g_assert_cmpstr (buf, ==, datestr);        \
         g_free (buf);                              \
     }
 
 #define test_assert_qof_print_date_outside_range(time, datestr)  \
     {                                              \
         gchar *buf = qof_print_date (time);        \
-	g_assert_cmpstr (buf, ==, datestr);	   \
+        g_assert_cmpstr (buf, ==, datestr);        \
         g_free (buf);                              \
     }
 
@@ -1765,16 +1764,16 @@ test_gnc_dmy2timespec (FixtureB *f, gconstpointer pData)
     for (int i = 0; i < sizeof(f->test)/sizeof(TimeMap); ++i)
     {
 #ifdef HAVE_STRUCT_TM_GMTOFF
-	struct tm tm = {0, 0, 0, f->test[i].day, f->test[i].mon - 1,
-			f->test[i].yr - 1900, 0, 0, -1, 0, NULL};
+        struct tm tm = {0, 0, 0, f->test[i].day, f->test[i].mon - 1,
+                        f->test[i].yr - 1900, 0, 0, -1, 0, NULL};
 #else
-	struct tm tm = {0, 0, 0, f->test[i].day, f->test[i].mon - 1,
-			f->test[i].yr - 1900, 0, 0, -1};
+        struct tm tm = {0, 0, 0, f->test[i].day, f->test[i].mon - 1,
+                        f->test[i].yr - 1900, 0, 0, -1};
 #endif
-	Timespec r_t = gnc_dmy2timespec (f->test[i].day, f->test[i].mon,
-					 f->test[i].yr);
-	int offset = gnc_mktime(&tm) - gnc_timegm(&tm);
-	g_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs + offset);
+        Timespec r_t = gnc_dmy2timespec (f->test[i].day, f->test[i].mon,
+                                         f->test[i].yr);
+        int offset = gnc_mktime(&tm) - gnc_timegm(&tm);
+        g_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs + offset);
     }
 }
 /* gnc_dmy2timespec_end
@@ -1787,16 +1786,16 @@ test_gnc_dmy2timespec_end (FixtureB *f, gconstpointer pData)
     for (int i = 0; i < sizeof(f->test)/sizeof(TimeMap); ++i)
     {
 #ifdef HAVE_STRUCT_TM_GMTOFF
-	struct tm tm = {59, 59, 23, f->test[i].day, f->test[i].mon - 1,
-			f->test[i].yr - 1900, 0, 0, -1, 0, NULL};
+        struct tm tm = {59, 59, 23, f->test[i].day, f->test[i].mon - 1,
+                        f->test[i].yr - 1900, 0, 0, -1, 0, NULL};
 #else
-	struct tm tm = {59, 59, 23, f->test[i].day, f->test[i].mon - 1,
-			f->test[i].yr - 1900, 0, 0, -1};
+        struct tm tm = {59, 59, 23, f->test[i].day, f->test[i].mon - 1,
+                        f->test[i].yr - 1900, 0, 0, -1};
 #endif
-	Timespec r_t = gnc_dmy2timespec_end (f->test[i].day, f->test[i].mon,
-					     f->test[i].yr);
-	int offset = gnc_mktime(&tm) - gnc_timegm(&tm);
-	g_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs + offset);
+        Timespec r_t = gnc_dmy2timespec_end (f->test[i].day, f->test[i].mon,
+                                             f->test[i].yr);
+        int offset = gnc_mktime(&tm) - gnc_timegm(&tm);
+        g_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs + offset);
     }
 }
 
@@ -1847,37 +1846,37 @@ test_timespec_to_gdate (FixtureA *f, gconstpointer pData)
     gnc_localtime_r(&f->ts0.tv_sec, &tm);
     g_date_set_dmy (&date2, tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
     g_assert_cmpint (g_date_get_julian (&date1), ==,
-		     g_date_get_julian (&date2));
+                     g_date_get_julian (&date2));
 
     date1 = timespec_to_gdate (f->ts1);
     gnc_localtime_r(&f->ts1.tv_sec, &tm);
     g_date_set_dmy (&date2, tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
     g_assert_cmpint (g_date_get_julian (&date1), ==,
-		     g_date_get_julian (&date2));
+                     g_date_get_julian (&date2));
 
     date1 = timespec_to_gdate (f->ts2);
     gnc_localtime_r(&f->ts2.tv_sec, &tm);
     g_date_set_dmy (&date2, tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
     g_assert_cmpint (g_date_get_julian (&date1), ==,
-		     g_date_get_julian (&date2));
+                     g_date_get_julian (&date2));
 
     date1 = timespec_to_gdate (f->ts3);
     gnc_localtime_r(&f->ts3.tv_sec, &tm);
     g_date_set_dmy (&date2, tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
     g_assert_cmpint (g_date_get_julian (&date1), ==,
-		     g_date_get_julian (&date2));
+                     g_date_get_julian (&date2));
 
     date1 = timespec_to_gdate (f->ts4);
     gnc_localtime_r(&f->ts4.tv_sec, &tm);
     g_date_set_dmy (&date2, tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
     g_assert_cmpint (g_date_get_julian (&date1), ==,
-		     g_date_get_julian (&date2));
+                     g_date_get_julian (&date2));
 
     date1 = timespec_to_gdate (f->ts5);
     gnc_localtime_r(&f->ts5.tv_sec, &tm);
     g_date_set_dmy (&date2, tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
     g_assert_cmpint (g_date_get_julian (&date1), ==,
-		     g_date_get_julian (&date2));
+                     g_date_get_julian (&date2));
 }
 
 /* gdate_to_timespec
@@ -1889,19 +1888,19 @@ test_gdate_to_timespec (FixtureB *f, gconstpointer pData)
     for (int i = 0; i < sizeof(f->test)/sizeof(TimeMap); ++i)
     {
 #ifdef HAVE_STRUCT_TM_GMTOFF
-	struct tm tm = {0, 0, 0, f->test[i].day, f->test[i].mon - 1,
-			f->test[i].yr - 1900, 0, 0, -1, 0, NULL};
+        struct tm tm = {0, 0, 0, f->test[i].day, f->test[i].mon - 1,
+                        f->test[i].yr - 1900, 0, 0, -1, 0, NULL};
 #else
-	struct tm tm = {0, 0, 0, f->test[i].day, f->test[i].mon - 1,
-			f->test[i].yr - 1900, 0, 0, -1};
+        struct tm tm = {0, 0, 0, f->test[i].day, f->test[i].mon - 1,
+                        f->test[i].yr - 1900, 0, 0, -1};
 #endif
-	GDate gd;
-	Timespec r_t;
-	int offset = gnc_mktime(&tm) - gnc_timegm(&tm);
-	g_date_clear(&gd, 1);
-	g_date_set_dmy(&gd, f->test[i].day, f->test[i].mon, f->test[i].yr);
-	r_t = gdate_to_timespec(gd);
-	g_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs + offset);
+        GDate gd;
+        Timespec r_t;
+        int offset = gnc_mktime(&tm) - gnc_timegm(&tm);
+        g_date_clear(&gd, 1);
+        g_date_set_dmy(&gd, f->test[i].day, f->test[i].mon, f->test[i].yr);
+        r_t = gdate_to_timespec(gd);
+        g_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs + offset);
     }
 }
 /* gnc_tm_get_day_start

commit d0b916c6f96882fe9508041c92f8d546559d9df5
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Mar 2 08:27:04 2015 -0800

    Fix offset calculations for TZif2 files.

diff --git a/src/libqof/qof/Makefile.am b/src/libqof/qof/Makefile.am
index 7744427..bae92cc 100644
--- a/src/libqof/qof/Makefile.am
+++ b/src/libqof/qof/Makefile.am
@@ -11,6 +11,7 @@ libgnc_qof_la_LDFLAGS= \
 libgnc_qof_common_libs =  \
   $(GLIB_LIBS) \
   $(REGEX_LIBS) \
+  -lboost_date_time \
   $(top_builddir)/lib/libc/libc-missing.la
 
 libgnc_qof_la_LIBADD = $(libgnc_qof_common_libs)
diff --git a/src/libqof/qof/gnc-timezone.cpp b/src/libqof/qof/gnc-timezone.cpp
index 3797671..693c321 100644
--- a/src/libqof/qof/gnc-timezone.cpp
+++ b/src/libqof/qof/gnc-timezone.cpp
@@ -357,6 +357,7 @@ namespace IANAParser
     {
 	unsigned int fb_index = 0;
 	TZHead tzh = *reinterpret_cast<TZHead*>(&fileblock[fb_index]);
+	static constexpr int ttinfo_size = 6; //struct TTInfo gets padded
 	last_year = 2037; //Constrained by 32-bit time_t.
 
 	auto time_count = *(endian_swap(reinterpret_cast<uint32_t*>(tzh.timecnt)));
@@ -368,12 +369,12 @@ namespace IANAParser
 	if (tzh.version == '2' && sizeof(time_t) == sizeof(int64_t))
 	{
 	    fb_index = (sizeof(tzh) +
-			sizeof(time_t) + sizeof(uint8_t) * time_count +
-			sizeof(TTInfo) * type_count +
+			(sizeof(uint32_t) + sizeof(uint8_t)) * time_count +
+			ttinfo_size * type_count +
 			sizeof(char) * char_count +
 			sizeof(uint8_t) * isgmt_count +
 			sizeof(uint8_t) * isstd_count +
-			2 * sizeof(time_t) * leap_count);
+			2 * sizeof(uint32_t) * leap_count);
 
 	    //This might change at some point in the probably very
 	    //distant future.
@@ -387,9 +388,6 @@ namespace IANAParser
 	    leap_count = *(endian_swap(reinterpret_cast<uint32_t*>(tzh.leapcnt)));
 	}
 	fb_index += sizeof(tzh);
-	
-	transitions.reserve(time_count);
-	tzinfo.reserve(type_count);
 	auto start_index = fb_index;
 	auto info_index_zero = start_index + time_count * sizeof(time_t);
 	for(uint32_t index = 0; index < time_count; ++index)
diff --git a/src/libqof/qof/test/test-gnc-date.c b/src/libqof/qof/test/test-gnc-date.c
index 170339b..3f1a7c4 100644
--- a/src/libqof/qof/test/test-gnc-date.c
+++ b/src/libqof/qof/test/test-gnc-date.c
@@ -54,7 +54,7 @@ extern "C"
 
 static const gchar *suitename = "/qof/gnc-date";
 static const time64 secs_per_year = INT64_C(3600) * (INT64_C(24) * INT64_C(365) + 6);
-static const time64 max_secs = secs_per_year * (INT64_C(9999) - INT64_C(1970));
+static const time64 max_secs = (INT64_C(3600) * (INT64_C(24) * INT64_C(365) + 6)) * (INT64_C(9999) - INT64_C(1970));
 
 typedef struct
 {
@@ -147,14 +147,17 @@ test_gnc_localtime (void)
 	secs[0] = -432761LL;
     for (ind = 0; ind < G_N_ELEMENTS (secs); ind++)
     {
+	if (sizeof(time_t) == sizeof())
         struct tm* time = gnc_localtime (&secs[ind]);
+	time_t tsecs;
+	struct tm* ans;
         if (secs[ind] > max_secs)
         {
             g_assert (time == NULL);
             continue;
         }
-	time_t tsecs = (time_t)(secs[ind]);
-	struct tm* ans = localtime(&tsecs);
+	tsecs = (time_t)(secs[ind]);
+	ans = localtime(&tsecs);
         g_assert_cmpint (time->tm_year, ==, ans->tm_year);
         g_assert_cmpint (time->tm_mon, ==, ans->tm_mon);
         g_assert_cmpint (time->tm_mday, ==, ans->tm_mday);
@@ -312,10 +315,12 @@ test_gnc_ctime (void)
     guint ind;
     for (ind = 0; ind < G_N_ELEMENTS (secs); ind++)
     {
+	 time_t time;
+	 char *datestr;
 	if (secs[ind] < INT32_MIN)
 	    continue;
-	time_t time = (time_t)secs[ind];
-        char* datestr = gnc_ctime (&secs[ind]);
+	time = (time_t)secs[ind];
+        datestr = gnc_ctime (&secs[ind]);
         g_assert_cmpstr (datestr, ==, strtok(ctime(&time), "\n"));
         g_free (datestr);
     }
@@ -1375,6 +1380,7 @@ test_qof_scan_date (void)
     int day = 0, mo = 0, yr = 0;
     gint year, month;
     time64 now = gnc_time(NULL);
+    gchar buff[MAX_DATE_LENGTH];
     struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0
 #ifndef G_OS_WIN32
         , 0, 0
@@ -1383,7 +1389,6 @@ test_qof_scan_date (void)
     gnc_localtime_r(&now, &tm);
     year = tm.tm_year + 1900;
     month = tm.tm_mon + 1;
-    gchar buff[MAX_DATE_LENGTH];
 
     g_assert (!qof_scan_date (NULL, &day, &mo, &yr));
     g_assert_cmpint (day, ==, 0);

commit 5a378e1e91a1600bfb217e1dc8f222dc8cac7b9e
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Feb 28 15:00:59 2015 -0800

    Fix GCC type-deduction failure.

diff --git a/src/libqof/qof/gnc-timezone.cpp b/src/libqof/qof/gnc-timezone.cpp
index 3f3d638..3797671 100644
--- a/src/libqof/qof/gnc-timezone.cpp
+++ b/src/libqof/qof/gnc-timezone.cpp
@@ -392,7 +392,7 @@ namespace IANAParser
 	tzinfo.reserve(type_count);
 	auto start_index = fb_index;
 	auto info_index_zero = start_index + time_count * sizeof(time_t);
-	for(auto index = 0; index < time_count; ++index)
+	for(uint32_t index = 0; index < time_count; ++index)
 	{
 	    fb_index = start_index + index * sizeof(time_t);
 	    auto info_index = info_index_zero + index;
@@ -408,7 +408,7 @@ namespace IANAParser
 	auto abbrev = start_index + type_count * tzinfo_size;
 	auto std_dist = abbrev + char_count;
 	auto gmt_dist = std_dist + type_count;
-	for(auto index = 0; index < type_count; ++index)
+	for(uint32_t index = 0; index < type_count; ++index)
 	{
 	    fb_index = start_index + index * tzinfo_size;
 	    TTInfo info = *reinterpret_cast<TTInfo*>(&fileblock[fb_index]);

commit 197d43f4a16261f23f96f7e63b5675e83ca9c818
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Feb 28 14:30:28 2015 -0800

    Rewrite test-gnc-date.c to not use GDateTime for reference.

diff --git a/src/libqof/qof/test/test-gnc-date.c b/src/libqof/qof/test/test-gnc-date.c
index 3582e18..170339b 100644
--- a/src/libqof/qof/test/test-gnc-date.c
+++ b/src/libqof/qof/test/test-gnc-date.c
@@ -27,7 +27,9 @@ extern "C"
 #endif
 
 #include <config.h>
+#include "../../../platform.h"
 #include <string.h>
+#include <sys/time.h>
 #include <glib.h>
 #include <unittest-support.h>
 /* Add specific headers for this class */
@@ -35,11 +37,11 @@ extern "C"
 #ifdef __cplusplus
 }
 #endif
-
 #include "../gnc-date.h"
 #include "../gnc-date-p.h"
 #include <locale.h>
 #include <glib/gprintf.h>
+#include <inttypes.h>
 #ifndef HAVE_STRPTIME
 #  include "strptime.h"
 #endif
@@ -51,6 +53,84 @@ extern "C"
 #endif
 
 static const gchar *suitename = "/qof/gnc-date";
+static const time64 secs_per_year = INT64_C(3600) * (INT64_C(24) * INT64_C(365) + 6);
+static const time64 max_secs = secs_per_year * (INT64_C(9999) - INT64_C(1970));
+
+typedef struct
+{
+    short hours;
+    short minutes;
+} TZOffset;
+
+typedef struct
+{
+    TZOffset off_zulu;
+    TZOffset off_05w;
+    TZOffset off_0840e;
+    Timespec ts0;
+    Timespec ts1;
+    Timespec ts2;
+    Timespec ts3;
+    Timespec ts4;
+    Timespec ts5;
+} FixtureA;
+
+static int
+offset_secs (TZOffset tz)
+{
+    return 3600 * tz.hours + 60 * tz.minutes;
+}
+
+static char*
+offset_string (TZOffset tz)
+{
+    return g_strdup_printf("%+02d%02d", tz.hours, tz.minutes);
+}
+
+static void setup (FixtureA *f, gconstpointer pData)
+{
+    f->ts0 = (Timespec){gnc_time(NULL), 0};
+    f->off_zulu = (TZOffset){0, 0};
+    f->off_05w = (TZOffset){-5, 0};
+    f->off_0840e = (TZOffset){8, 40};
+    f->ts1 = (Timespec){607009407, 345678000}; //1989-3-27 13:43:27.345678 Z
+    f->ts2 = (Timespec){1604748079, 0}; //2020-11-7 06:21:19 -05:00
+    f->ts3 = (Timespec){1341398864, 0}; //2012-07-04 19:27:44 +08:40
+    f->ts4 = (Timespec){-261104801, 0}; //1961-09-22 17:53:19 -05:00
+    f->ts5 = (Timespec){2873938879LL, 0}; //2061-01-25 23:21:19 -05:00
+}
+
+typedef struct
+{
+    int yr;
+    int mon;
+    int day;
+    time64 secs;
+} TimeMap;
+
+typedef struct
+{
+    TimeMap test[4];
+} FixtureB;
+
+static void
+setup_begin(FixtureB *f, gconstpointer pData)
+{
+    f->test[0] = (TimeMap){1999, 7, 21, INT64_C(932515200)};
+    f->test[1] = (TimeMap){1918, 3, 31, INT64_C(-1633305600)};
+    f->test[2] = (TimeMap){1918, 4, 1, INT64_C(-1633219200)};
+    f->test[3] = (TimeMap){2057, 11, 20, INT64_C(2773440000)};
+}
+
+static void
+setup_end(FixtureB *f, gconstpointer pData)
+{
+    f->test[0] = (TimeMap){1999, 7, 21, INT64_C(932601599)};
+    f->test[1] = (TimeMap){1918, 3, 31, INT64_C(-1633219201)};
+    f->test[2] = (TimeMap){1918, 4, 1, INT64_C(-1633132801)};
+    f->test[3] = (TimeMap){2057, 11, 20, INT64_C(2773526399)};
+}
+
 void test_suite_gnc_date ( void );
 static GTimeZone *tz;
 /* gnc_localtime just creates a tm on the heap and calls
@@ -59,41 +139,34 @@ static GTimeZone *tz;
 static void
 test_gnc_localtime (void)
 {
-    time64 secs[6] = {-15767956734LL, -1123692LL, 432761LL,
+    time64 secs[] = {-15767956734LL, -1123692LL, 432761LL,
                       723349832LL, 887326459367LL,
-                      1364160236LL // This is "Sunday 2013-03-24" (to verify the Sunday
-                      // difference between g_date_time and tm->tm_wday)
-                     };
+                      1364160236LL};
     guint ind;
+    if (sizeof(time_t) < sizeof(time64))
+	secs[0] = -432761LL;
     for (ind = 0; ind < G_N_ELEMENTS (secs); ind++)
     {
         struct tm* time = gnc_localtime (&secs[ind]);
-        GDateTime *gdt = g_date_time_new_from_unix_local (secs[ind]);
-        if (gdt == NULL)
+        if (secs[ind] > max_secs)
         {
             g_assert (time == NULL);
             continue;
         }
-        g_assert_cmpint (time->tm_year + 1900, ==, g_date_time_get_year (gdt));
-        g_assert_cmpint (time->tm_mon + 1, ==, g_date_time_get_month (gdt));
-        g_assert_cmpint (time->tm_mday, ==, g_date_time_get_day_of_month (gdt));
-        g_assert_cmpint (time->tm_hour, ==, g_date_time_get_hour (gdt));
-        g_assert_cmpint (time->tm_min, ==, g_date_time_get_minute (gdt));
-        g_assert_cmpint (time->tm_sec, ==, g_date_time_get_second (gdt));
-        // Watch out: struct tm has wday=0..6 with Sunday=0, but GDateTime has wday=1..7 with Sunday=7.
-        g_assert_cmpint (time->tm_wday, ==, (g_date_time_get_day_of_week (gdt) % 7));
-	//tm_yday is 0-based, g_date_time_get_day_of_year is 1-based.
-        g_assert_cmpint (time->tm_yday, ==,
-			 g_date_time_get_day_of_year (gdt) - 1);
-        if (g_date_time_is_daylight_savings (gdt))
-            g_assert_cmpint (time->tm_isdst, ==, 1);
-        else
-            g_assert_cmpint (time->tm_isdst, ==, 0);
+	time_t tsecs = (time_t)(secs[ind]);
+	struct tm* ans = localtime(&tsecs);
+        g_assert_cmpint (time->tm_year, ==, ans->tm_year);
+        g_assert_cmpint (time->tm_mon, ==, ans->tm_mon);
+        g_assert_cmpint (time->tm_mday, ==, ans->tm_mday);
+        g_assert_cmpint (time->tm_hour, ==, ans->tm_hour);
+        g_assert_cmpint (time->tm_min, ==, ans->tm_min);
+        g_assert_cmpint (time->tm_sec, ==, ans->tm_sec);
+        g_assert_cmpint (time->tm_wday, ==, ans->tm_wday);
+        g_assert_cmpint (time->tm_yday, ==, ans->tm_yday);
+	g_assert_cmpint (time->tm_isdst, ==, ans->tm_isdst);
 #ifdef HAVE_STRUCT_TM_GMTOFF
-        g_assert_cmpint (time->tm_gmtoff, ==,
-                         g_date_time_get_utc_offset (gdt) / G_TIME_SPAN_SECOND);
+        g_assert_cmpint (time->tm_gmtoff, ==, ans->tm_gmtoff);
 #endif
-        g_date_time_unref (gdt);
         gnc_tm_free (time);
     }
 }
@@ -126,8 +199,7 @@ test_gnc_gmtime (void)
     for (ind = 0; ind < G_N_ELEMENTS (secs); ind++)
     {
         struct tm* time = gnc_gmtime (&secs[ind]);
-        GDateTime *gdt = g_date_time_new_from_unix_utc (secs[ind]);
-        if (gdt == NULL)
+        if ((secs[ind] > max_secs))
         {
             g_assert (time == NULL);
             continue;
@@ -144,7 +216,6 @@ test_gnc_gmtime (void)
 #ifdef HAVE_STRUCT_TM_GMTOFF
         g_assert_cmpint (time->tm_gmtoff, ==, 0);
 #endif
-        g_date_time_unref (gdt);
         gnc_tm_free (time);
     }
 }
@@ -172,20 +243,13 @@ test_gnc_mktime (void)
 #endif
     };
     guint ind;
+    int offset = timegm(&time[4]) - mktime(&time[4]);
 
     for (ind = 0; ind < G_N_ELEMENTS (time); ind++)
     {
         time64 secs = gnc_mktime (&time[ind]);
-        GDateTime *gdt = g_date_time_new_local (time[ind].tm_year + 1900,
-                                          time[ind].tm_mon + 1,
-                                          time[ind].tm_mday,
-                                          time[ind].tm_hour,
-                                          time[ind].tm_min,
-                                          (gdouble)time[ind].tm_sec);
-        time64 offset = g_date_time_get_utc_offset (gdt) / G_TIME_SPAN_SECOND;
         g_assert_cmpint (secs, ==, ans[ind] - offset);
 
-        g_date_time_unref (gdt);
     }
 }
 
@@ -224,16 +288,11 @@ test_gnc_mktime_normalization (void)
 #endif
     };
     guint ind;
+    int offset = timegm(&normal_time) - mktime(&normal_time);
     for (ind = 0; ind < G_N_ELEMENTS (time); ind++)
     {
         time64 secs = gnc_mktime (&time[ind]);
-        GDateTime *gdt = g_date_time_new_local (time[ind].tm_year + 1900,
-                                          time[ind].tm_mon + 1,
-                                          time[ind].tm_mday,
-                                          time[ind].tm_hour,
-                                          time[ind].tm_min,
-                                          (gdouble)time[ind].tm_sec);
-        time64 offset = g_date_time_get_utc_offset (gdt) / G_TIME_SPAN_SECOND;
+
         g_assert_cmpfloat (time[ind].tm_sec, ==, normal_time.tm_sec);
         g_assert_cmpint (time[ind].tm_min, ==, normal_time.tm_min);
         g_assert_cmpint (time[ind].tm_hour, ==, normal_time.tm_hour);
@@ -241,8 +300,6 @@ test_gnc_mktime_normalization (void)
         g_assert_cmpint (time[ind].tm_mon, ==, normal_time.tm_mon);
         g_assert_cmpint (time[ind].tm_year, ==, normal_time.tm_year);
         g_assert_cmpint (secs, ==, ans - offset);
-
-        g_date_time_unref (gdt);
     }
 }
 
@@ -255,11 +312,11 @@ test_gnc_ctime (void)
     guint ind;
     for (ind = 0; ind < G_N_ELEMENTS (secs); ind++)
     {
-        GDateTime *gdt = g_date_time_new_from_unix_local (secs[ind]);
-        gchar* datestr = gnc_ctime (&secs[ind]);
-        g_assert_cmpstr (datestr, ==,
-                         g_date_time_format (gdt, "%a %b %e %H:%M:%S %Y"));
-        g_date_time_unref (gdt);
+	if (secs[ind] < INT32_MIN)
+	    continue;
+	time_t time = (time_t)secs[ind];
+        char* datestr = gnc_ctime (&secs[ind]);
+        g_assert_cmpstr (datestr, ==, strtok(ctime(&time), "\n"));
         g_free (datestr);
     }
 }
@@ -268,12 +325,9 @@ static void
 test_gnc_time (void)
 {
     time64 secs1, secs2;
-    GDateTime *gdt;
     secs1 = gnc_time (&secs2);
-    gdt = g_date_time_new_now_local ();
     g_assert_cmpint (secs1, ==, secs2);
-    g_assert_cmpint (secs1, ==, g_date_time_to_unix (gdt));
-    g_date_time_unref (gdt);
+    g_assert_cmpint (secs1, ==, time(0));
 }
 
 /* gnc_difftime and gnc_tm_free are just too simple to bother testing. */
@@ -597,16 +651,13 @@ timespecCanonicalDayTime(Timespec t)// C: 12 in 5 SCM: 19 in 10 Local: 0:0:0
 static Timespec
 compute_noon_of_day (Timespec *ts)
 {
-    GDateTime *g = g_date_time_new_from_unix_local (ts->tv_sec);
-    gint yr = g_date_time_get_year (g);
-    gint mo = g_date_time_get_month (g);
-    gint da = g_date_time_get_day_of_month (g);
-    Timespec nt = {0, 0 };
-
-    g_date_time_unref (g);
-    g = g_date_time_new_local (yr, mo, da, 12, 0, 0.0);
-    nt.tv_sec = g_date_time_to_unix (g);
-    g_date_time_unref (g);
+    Timespec nt = {0, 0};
+    time_t secs = (time_t)ts->tv_sec;
+    struct tm *time = localtime(&secs);
+    time->tm_hour = 12;
+    time->tm_min = 0;
+    time->tm_sec = 0;
+    nt.tv_sec = mktime(time);
     return nt;
 }
 
@@ -638,9 +689,8 @@ test_timespecCanonicalDayTime (void)
     g_assert_cmpint (n0.tv_sec, ==, r0.tv_sec);
     g_assert_cmpint (na.tv_sec, ==, ra.tv_sec);
     g_assert_cmpint (nb.tv_sec, ==, rb.tv_sec);
-//GDateTime gets DST wrong here: The DST changes on the second Sunday
-//of March, which this is; Our time-zone sets DST, but GDateTime's doesn't.
-    g_assert_cmpint (nc.tv_sec, ==, rc.tv_sec + 3600);
+    if (sizeof(time_t) >= sizeof(time64))
+	g_assert_cmpint (nc.tv_sec, ==, rc.tv_sec);
 }
 
 /* gnc_date_get_last_mday
@@ -913,13 +963,10 @@ test_qof_print_date_buff (void)
 {
     gchar buff[MAX_DATE_LENGTH];
     gchar *locale = g_strdup (setlocale (LC_TIME, NULL));
-    GDateTime *gd1 = g_date_time_new_local (1974, 11, 23, 12, 0, 0.0);
-    GDateTime *gd2 = g_date_time_new_local (1961, 2, 2, 12, 0, 0.0);
-    GDateTime *gd3 = g_date_time_new_local (2045, 6, 16, 12, 0, 0.0);
 
-    time64 tm1 = g_date_time_to_unix (gd1);
-    time64 tm2 = g_date_time_to_unix (gd2);
-    time64 tm3 = g_date_time_to_unix (gd3);
+    time64 tm1 = 154440000; //1974-11-23 12:00:00
+    time64 tm2 = -281188800; //1961-02-02 12:00:00
+    time64 tm3 = 2381227200LL; //2045-06-16 12:00:00
 
     qof_date_format_set (QOF_DATE_FORMAT_UK);
     memset ((gpointer)buff, 0, sizeof (buff));
@@ -986,50 +1033,47 @@ test_qof_print_date_buff (void)
     memset ((gpointer)buff, 0, sizeof (buff));
     g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm1),
                      ==, strlen (buff));
-    g_assert_cmpstr (buff, ==, g_date_time_format (gd1, GNC_D_FMT));
+    g_assert_cmpstr (buff, ==, "11/23/1974");
     memset ((gpointer)buff, 0, sizeof (buff));
     g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm2),
                      ==, strlen (buff));
-    g_assert_cmpstr (buff, ==, g_date_time_format (gd2, GNC_D_FMT));
+    g_assert_cmpstr (buff, ==, "02/02/1961");
 
     memset ((gpointer)buff, 0, sizeof (buff));
     g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm3),
                      ==, strlen (buff));
-    g_assert_cmpstr (buff, ==, g_date_time_format (gd3, GNC_D_FMT));
+    g_assert_cmpstr (buff, ==, "06/16/2045");
 
     test_gnc_setlocale (LC_TIME, "en_GB");
     memset ((gpointer)buff, 0, sizeof (buff));
     g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm1),
                      ==, strlen (buff));
-    g_assert_cmpstr (buff, ==, g_date_time_format (gd1, GNC_D_FMT));
+    g_assert_cmpstr (buff, ==, "23/11/1974");
     memset ((gpointer)buff, 0, sizeof (buff));
     g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm2),
                      ==, strlen (buff));
-    g_assert_cmpstr (buff, ==, g_date_time_format (gd2, GNC_D_FMT));
+    g_assert_cmpstr (buff, ==, "02/02/1961");
     memset ((gpointer)buff, 0, sizeof (buff));
     g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm3),
                      ==, strlen (buff));
-    g_assert_cmpstr (buff, ==, g_date_time_format (gd3, GNC_D_FMT));
+    g_assert_cmpstr (buff, ==, "16/06/2045");
 
     test_gnc_setlocale (LC_TIME, "fr_FR");
     memset ((gpointer)buff, 0, sizeof (buff));
     g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm1),
                      ==, strlen (buff));
-    g_assert_cmpstr (buff, ==, g_date_time_format (gd1, GNC_D_FMT));
+    g_assert_cmpstr (buff, ==, "23.11.1974");
     memset ((gpointer)buff, 0, sizeof (buff));
     g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm2),
                      ==, strlen (buff));
-    g_assert_cmpstr (buff, ==, g_date_time_format (gd2, GNC_D_FMT));
+    g_assert_cmpstr (buff, ==, "02.02.1961");
     memset ((gpointer)buff, 0, sizeof (buff));
     g_assert_cmpint (qof_print_date_buff (buff, sizeof (buff), tm3),
                      ==, strlen (buff));
-    g_assert_cmpstr (buff, ==, g_date_time_format (gd3, GNC_D_FMT));
+    g_assert_cmpstr (buff, ==, "16.06.2045");
 
     setlocale (LC_TIME, locale);
     g_free (locale);
-    g_date_time_unref (gd1);
-    g_date_time_unref (gd2);
-    g_date_time_unref (gd3);
 }
 /* qof_print_gdate
 size_t
@@ -1192,13 +1236,10 @@ static void
 test_qof_print_date (void)
 {
     gchar *locale = g_strdup (setlocale (LC_TIME, NULL));
-    GDateTime *gd1 = g_date_time_new_local (1974, 11, 23, 12, 0, 0.0);
-    GDateTime *gd2 = g_date_time_new_local (1961, 2, 2, 12, 0, 0.0);
-    GDateTime *gd3 = g_date_time_new_local (2045, 6, 16, 12, 0, 0.0);
 
-    time64 tm1 = g_date_time_to_unix (gd1);
-    time64 tm2 = g_date_time_to_unix (gd2);
-    time64 tm3 = g_date_time_to_unix (gd3);
+    time64 tm1 = 154440000; //1974-11-23 12:00:00
+    time64 tm2 = -281188800; //1961-02-02 12:00:00
+    time64 tm3 = 2381227200LL; //2045-06-16 12:00:00
 
     qof_date_format_set (QOF_DATE_FORMAT_UK);
     test_assert_qof_print_date (tm1, "23/11/1974");
@@ -1222,34 +1263,22 @@ test_qof_print_date (void)
 
     qof_date_format_set (QOF_DATE_FORMAT_LOCALE);
     test_gnc_setlocale (LC_TIME, "en_US");
-    test_assert_qof_print_date (tm1,
-                                g_date_time_format (gd1, GNC_D_FMT));
-    test_assert_qof_print_date_outside_range (tm2,
-            g_date_time_format (gd2, GNC_D_FMT));
-    test_assert_qof_print_date_outside_range (tm3,
-            g_date_time_format (gd3, GNC_D_FMT));
+    test_assert_qof_print_date (tm1,"11/23/1974");
+    test_assert_qof_print_date_outside_range (tm2, "02/02/1961");
+    test_assert_qof_print_date_outside_range (tm3, "06/16/2045");
 
     test_gnc_setlocale (LC_TIME, "en_GB");
-    test_assert_qof_print_date (tm1,
-                                g_date_time_format (gd1, GNC_D_FMT));
-    test_assert_qof_print_date_outside_range (tm2,
-            g_date_time_format (gd2, GNC_D_FMT));
-    test_assert_qof_print_date_outside_range (tm3,
-            g_date_time_format (gd3, GNC_D_FMT));
+    test_assert_qof_print_date (tm1, "23/11/1974");
+    test_assert_qof_print_date_outside_range (tm2, "02/02/1961");
+    test_assert_qof_print_date_outside_range (tm3, "16/06/2045");
 
     test_gnc_setlocale (LC_TIME, "fr_FR");
-    test_assert_qof_print_date (tm1,
-                                g_date_time_format (gd1, GNC_D_FMT));
-    test_assert_qof_print_date_outside_range (tm2,
-            g_date_time_format (gd2, GNC_D_FMT));
-    test_assert_qof_print_date_outside_range (tm3,
-            g_date_time_format (gd3, GNC_D_FMT));
+    test_assert_qof_print_date (tm1, "23.11.1974");
+    test_assert_qof_print_date_outside_range (tm2, "02.02.1961");
+    test_assert_qof_print_date_outside_range (tm3, "16.06.2045");
 
     setlocale (LC_TIME, locale);
     g_free (locale);
-    g_date_time_unref (gd1);
-    g_date_time_unref (gd2);
-    g_date_time_unref (gd3);
 }
 /* gnc_print_date
 const char *
@@ -1344,16 +1373,17 @@ test_qof_scan_date (void)
 {
     gchar *locale = g_strdup (setlocale (LC_TIME, NULL));
     int day = 0, mo = 0, yr = 0;
-    GDateTime *gdt = g_date_time_new_now_local ();
-    gint year = g_date_time_get_year (gdt);
-    gint month = g_date_time_get_month (gdt);
+    gint year, month;
+    time64 now = gnc_time(NULL);
     struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0
 #ifndef G_OS_WIN32
         , 0, 0
 #endif
     };
+    gnc_localtime_r(&now, &tm);
+    year = tm.tm_year + 1900;
+    month = tm.tm_mon + 1;
     gchar buff[MAX_DATE_LENGTH];
-    g_date_time_unref (gdt);
 
     g_assert (!qof_scan_date (NULL, &day, &mo, &yr));
     g_assert_cmpint (day, ==, 0);
@@ -1519,19 +1549,18 @@ gnc_date_timestamp (void)// C: 2 in 2  Local: 0:0:0
 static void
 test_gnc_date_timestamp (void)
 {
-    GDateTime *gdt = g_date_time_new_now_local ();
+    time64 now = gnc_time(NULL);
     gchar *timestr = gnc_date_timestamp ();
-    struct tm tm;
-
-    g_assert (strptime (timestr, "%Y%m%d%H%M%S", &tm));
-    g_assert_cmpint (g_date_time_get_year (gdt), ==, tm.tm_year + 1900);
-    g_assert_cmpint (g_date_time_get_month (gdt), ==, tm.tm_mon + 1);
-    g_assert_cmpint (g_date_time_get_day_of_month (gdt), ==, tm.tm_mday);
-    g_assert_cmpint (g_date_time_get_hour (gdt), ==, tm.tm_hour);
-    g_assert_cmpint (g_date_time_get_minute (gdt), ==, tm.tm_min);
-    g_assert_cmpint (g_date_time_get_second (gdt), ==, tm.tm_sec);
+    struct tm tm0, tm1;
+    gnc_localtime_r(&now, &tm0);
+    g_assert (strptime (timestr, "%Y%m%d%H%M%S", &tm1));
+    g_assert_cmpint (tm0.tm_year, ==, tm1.tm_year);
+    g_assert_cmpint (tm0.tm_mon, ==, tm1.tm_mon);
+    g_assert_cmpint (tm0.tm_mday, ==, tm1.tm_mday);
+    g_assert_cmpint (tm0.tm_hour, ==, tm1.tm_hour);
+    g_assert_cmpint (tm0.tm_min, ==, tm1.tm_min);
+    g_assert_cmpint (tm0.tm_sec, ==, tm1.tm_sec);
 
-    g_date_time_unref (gdt);
     g_free (timestr);
 }
 /* gnc_iso8601_to_timespec_gmt
@@ -1545,17 +1574,8 @@ get_nanoseconds (GDateTime *gdt)
 }
 
 static void
-test_gnc_iso8601_to_timespec_gmt (void)
+test_gnc_iso8601_to_timespec_gmt (FixtureA *f, gconstpointer pData)
 {
-    GTimeZone *zulu = g_time_zone_new ("Z");
-    GTimeZone *tz05 = g_time_zone_new ("-05");
-    GTimeZone *tz0840 = g_time_zone_new ("+08:40");
-    GDateTime *gdt1 = g_date_time_new (zulu, 1989, 3, 27, 13, 43, 27.345678);
-    GDateTime *gdt2 = g_date_time_new (tz05, 2020, 11, 7, 6, 21, 19.0);
-    GDateTime *gdt3 = g_date_time_new (tz0840, 2012, 7, 4, 19, 27, 44.0);
-    GDateTime *gdt4 = g_date_time_new (tz05, 1961, 9, 22, 17, 53, 19.0);
-    GDateTime *gdt5 = g_date_time_new (tz05, 2061, 1, 25, 23, 21, 19.0);
-
     Timespec t;
 
     t = gnc_iso8601_to_timespec_gmt (NULL);
@@ -1567,44 +1587,34 @@ test_gnc_iso8601_to_timespec_gmt (void)
     g_assert_cmpint (t.tv_nsec, ==, 0);
 
     t = gnc_iso8601_to_timespec_gmt ("1989-03-27 13:43:27.345678");
-    g_assert_cmpint (t.tv_sec, ==, g_date_time_to_unix (gdt1));
+    g_assert_cmpint (t.tv_sec, ==, f->ts1.tv_sec);
     /* MinGW has some precision issues in the last microsecond digit */
 #ifdef G_OS_WIN32
-    g_assert_cmpint (t.tv_nsec - 2000, <=, get_nanoseconds (gdt1));
-    g_assert_cmpint (t.tv_nsec + 2000, >=, get_nanoseconds (gdt1));
+    g_assert_cmpint (t.tv_nsec - 2000, <=, f->ts1.tv_nsec);
+    g_assert_cmpint (t.tv_nsec + 2000, >=, f->ts1.tv_nsec);
 #else
-    g_assert_cmpint (t.tv_nsec, ==, get_nanoseconds (gdt1));
+    g_assert_cmpint (t.tv_nsec, ==, f->ts1.tv_nsec);
 #endif
     t = gnc_iso8601_to_timespec_gmt ("2020-11-7 06:21:19 -05");
-    g_assert_cmpint (t.tv_sec, ==, g_date_time_to_unix (gdt2));
-    g_assert_cmpint (t.tv_nsec, ==, get_nanoseconds (gdt2));
+    g_assert_cmpint (t.tv_sec, ==, f->ts2.tv_sec);
+    g_assert_cmpint (t.tv_nsec, ==, f->ts2.tv_nsec);
 
     t = gnc_iso8601_to_timespec_gmt ("2012-07-04 19:27:44.0+08:40");
-    g_assert_cmpint (t.tv_sec, ==, g_date_time_to_unix (gdt3));
-    g_assert_cmpint (t.tv_nsec, ==, get_nanoseconds (gdt3));
+    g_assert_cmpint (t.tv_sec, ==, f->ts3.tv_sec);
+    g_assert_cmpint (t.tv_nsec, ==, f->ts3.tv_nsec);
 
     t = gnc_iso8601_to_timespec_gmt ("1961-09-22 17:53:19 -05");
-    g_assert_cmpint (t.tv_sec, ==, g_date_time_to_unix (gdt4));
-    g_assert_cmpint (t.tv_nsec, ==, get_nanoseconds (gdt4));
+    g_assert_cmpint (t.tv_sec, ==, f->ts4.tv_sec);
+    g_assert_cmpint (t.tv_nsec, ==, f->ts4.tv_nsec);
 
     t = gnc_iso8601_to_timespec_gmt ("2061-01-25 23:21:19.0 -05:00");
-    g_assert_cmpint (t.tv_sec, ==, g_date_time_to_unix (gdt5));
-    g_assert_cmpint (t.tv_nsec, ==, get_nanoseconds (gdt5));
-
-    g_date_time_unref (gdt1);
-    g_date_time_unref (gdt2);
-    g_date_time_unref (gdt3);
-    g_date_time_unref (gdt4);
-    g_date_time_unref (gdt5);
-    g_time_zone_unref (zulu);
-    g_time_zone_unref (tz05);
-    g_time_zone_unref (tz0840);
+    g_assert_cmpint (t.tv_sec, ==, f->ts5.tv_sec);
+    g_assert_cmpint (t.tv_nsec, ==, f->ts5.tv_nsec);
 }
 /* gnc_timespec_to_iso8601_buff
 char *
 gnc_timespec_to_iso8601_buff (Timespec ts, char * buff)// C: 18 in 7  Local: 0:0:0
 */
-#define ISO8601_SIZE MAX_DATE_LENGTH + 4
 static Timespec
 g_date_time_to_timespec (GDateTime *gdt)
 {
@@ -1614,42 +1624,32 @@ g_date_time_to_timespec (GDateTime *gdt)
     return t;
 }
 
+#define ISO8601_SIZE MAX_DATE_LENGTH + 4
 static gchar*
-format_timestring (GDateTime *gdt)
+format_timestring (Timespec ts, TZOffset tz)
 {
   static const unsigned tzlen = MAX_DATE_LENGTH - 26;
-    gchar *fmt = "%Y-%m-%d %H:%M";
-    GDateTime *ngdt = g_date_time_to_local (gdt);
-    gchar *date_base = g_date_time_format (ngdt, fmt);
-    gchar buf[tzlen], *retval;
-#ifdef G_OS_WIN32
-    gchar *tz = g_date_time_format (ngdt, "%Z");
+    char *fmt = "%Y-%m-%d %H:%M:%S";
+    struct tm tm;
+    char buf[MAX_DATE_LENGTH], *retval;
+    char tzbuf[tzlen];
+    memset(tzbuf, 0, sizeof(tzbuf));
+    gnc_localtime_r(&ts.tv_sec, &tm);
+#if PLATFORM(WINDOWS)
+    strftime(tzbuf, sizeof(tzbuf), "%Z", &tm);
 #else
-    gchar *tz = g_date_time_format (ngdt, "%z");
+    strftime(tzbuf, sizeof(tzbuf), "%z", &tm);
 #endif
-    memset (buf, 0, tzlen);
-    g_snprintf (buf, tzlen, "%s", tz);
-    retval = g_strdup_printf ("%s:%02d.%06d %s", date_base,
-                                     g_date_time_get_second (ngdt),
-                                     g_date_time_get_microsecond (ngdt), buf);
-    g_date_time_unref (ngdt);
-    g_free (date_base);
-    g_free (tz);
+    memset (buf, 0, sizeof(buf));
+    strftime(buf, sizeof(buf), fmt, &tm);
+    retval = g_strdup_printf ("%s.%06ld %s", buf, ts.tv_nsec / 1000, tzbuf);
+
     return retval;
 }
 
 static void
-test_gnc_timespec_to_iso8601_buff (void)
-{
-    GTimeZone *zulu = g_time_zone_new ("Z");
-    GTimeZone *tz05 = g_time_zone_new ("-05");
-    GTimeZone *tz0840 = g_time_zone_new ("+08:40");
-    GDateTime *gdt0 = g_date_time_new_from_unix_utc (0);
-    GDateTime *gdt1 = g_date_time_new (zulu, 1989, 3, 27, 13, 43, 27.0);
-    GDateTime *gdt2 = g_date_time_new (tz05, 2020, 11, 7, 6, 21, 19.0);
-    GDateTime *gdt3 = g_date_time_new (tz0840, 2012, 7, 4, 19, 27, 44.0);
-    GDateTime *gdt4 = g_date_time_new (tz05, 1961, 9, 22, 17, 53, 19.0);
-    GDateTime *gdt5 = g_date_time_new (tz05, 2061, 1, 25, 23, 21, 19.0);
+test_gnc_timespec_to_iso8601_buff (FixtureA *f, gconstpointer pData)
+{
 
     gchar buff[ISO8601_SIZE];
     gchar *time_str;
@@ -1661,138 +1661,85 @@ test_gnc_timespec_to_iso8601_buff (void)
     end = gnc_timespec_to_iso8601_buff (t, NULL);
     g_assert (end == NULL);
 
-    end = gnc_timespec_to_iso8601_buff (t, buff);
+    end = gnc_timespec_to_iso8601_buff (f->ts0, buff);
     g_assert_cmpint (end - buff, ==, strlen (buff));
-    time_str = format_timestring (gdt0);
+    time_str = format_timestring (f->ts0, f->off_zulu);
     g_assert_cmpstr (buff, ==, time_str);
     g_free (time_str);
 
-    t = g_date_time_to_timespec (gdt1);
-    end = gnc_timespec_to_iso8601_buff (t, buff);
-    time_str = format_timestring (gdt1);
+    end = gnc_timespec_to_iso8601_buff (f->ts1, buff);
+    time_str = format_timestring (f->ts1, f->off_zulu);
     g_assert_cmpstr (buff, ==, time_str);
     g_free (time_str);
 
 
-    t = g_date_time_to_timespec (gdt2);
-    end = gnc_timespec_to_iso8601_buff (t, buff);
-    time_str = format_timestring (gdt2);
+    end = gnc_timespec_to_iso8601_buff (f->ts2, buff);
+    time_str = format_timestring (f->ts2, f->off_05w);
     g_assert_cmpstr (buff, ==, time_str);
     g_free (time_str);
 
-    t = g_date_time_to_timespec (gdt3);
-    end = gnc_timespec_to_iso8601_buff (t, buff);
-    time_str = format_timestring (gdt3);
+    end = gnc_timespec_to_iso8601_buff (f->ts3, buff);
+    time_str = format_timestring (f->ts3, f->off_0840e);
     g_assert_cmpstr (buff, ==, time_str);
     g_free (time_str);
 
-    t = g_date_time_to_timespec (gdt4);
-    end = gnc_timespec_to_iso8601_buff (t, buff);
-    time_str = format_timestring (gdt4);
+    end = gnc_timespec_to_iso8601_buff (f->ts4, buff);
+    time_str = format_timestring (f->ts4, f->off_05w);
     g_assert_cmpstr (buff, ==, time_str);
     g_free (time_str);
 
-    t = g_date_time_to_timespec (gdt5);
-    end = gnc_timespec_to_iso8601_buff (t, buff);
-    time_str = format_timestring (gdt5);
+    end = gnc_timespec_to_iso8601_buff (f->ts5, buff);
+    time_str = format_timestring (f->ts5, f->off_05w);
     g_assert_cmpstr (buff, ==, time_str);
     g_free (time_str);
-
-    g_date_time_unref (gdt0);
-    g_date_time_unref (gdt1);
-    g_date_time_unref (gdt2);
-    g_date_time_unref (gdt3);
-    g_date_time_unref (gdt4);
-    g_date_time_unref (gdt5);
-    g_time_zone_unref (zulu);
-    g_time_zone_unref (tz05);
-    g_time_zone_unref (tz0840);
 }
 /* gnc_timespec2dmy
 void
 gnc_timespec2dmy (Timespec t, int *day, int *month, int *year)// C: 1  Local: 0:0:0
 */
 static void
-test_gnc_timespec2dmy (void)
-{
-    GTimeZone *zulu = g_time_zone_new ("Z");
-    GTimeZone *tz05 = g_time_zone_new ("-05");
-    GTimeZone *tz0840 = g_time_zone_new ("+08:40");
-    GDateTime *gdt0 = g_date_time_new_from_unix_utc (0);
-    GDateTime *gdt1 = g_date_time_new (zulu, 1989, 3, 27, 13, 43, 27.345678);
-    GDateTime *gdt2 = g_date_time_new (tz05, 2020, 11, 7, 6, 21, 19.0);
-    GDateTime *gdt3 = g_date_time_new (tz0840, 2012, 7, 4, 19, 27, 44.0);
-    GDateTime *gdt4 = g_date_time_new (tz05, 1961, 9, 22, 17, 53, 19.0);
-    GDateTime *gdt5 = g_date_time_new (tz05, 2061, 1, 25, 23, 21, 19.0);
-    GDateTime *gdt_local;
-
+test_gnc_timespec2dmy (FixtureA *f, gconstpointer pData)
+{
+    struct tm tm;
     int day, r_day, mo, r_mo, yr, r_yr;
-    Timespec t;
 
-    t = g_date_time_to_timespec (gdt0);
-    gnc_timespec2dmy (t, &r_day, &r_mo, &r_yr);
-    gdt_local = g_date_time_to_local (gdt0);
-    g_date_time_get_ymd (gdt_local, &yr, &mo, &day);
-    g_date_time_unref (gdt_local);
-    g_assert_cmpint (r_day, ==, day);
-    g_assert_cmpint (r_mo, ==, mo);
-    g_assert_cmpint (r_yr, ==, yr);
-
-    t = g_date_time_to_timespec (gdt1);
-    gnc_timespec2dmy (t, &r_day, &r_mo, &r_yr);
-    gdt_local = g_date_time_to_local (gdt1);
-    g_date_time_get_ymd (gdt_local, &yr, &mo, &day);
-    g_date_time_unref (gdt_local);
-    g_assert_cmpint (r_day, ==, day);
-    g_assert_cmpint (r_mo, ==, mo);
-    g_assert_cmpint (r_yr, ==, yr);
-
-    t = g_date_time_to_timespec (gdt2);
-    gnc_timespec2dmy (t, &r_day, &r_mo, &r_yr);
-    gdt_local = g_date_time_to_local (gdt2);
-    g_date_time_get_ymd (gdt_local, &yr, &mo, &day);
-    g_date_time_unref (gdt_local);
-    g_assert_cmpint (r_day, ==, day);
-    g_assert_cmpint (r_mo, ==, mo);
-    g_assert_cmpint (r_yr, ==, yr);
-
-    t = g_date_time_to_timespec (gdt3);
-    gnc_timespec2dmy (t, &r_day, &r_mo, &r_yr);
-    gdt_local = g_date_time_to_local (gdt3);
-    g_date_time_get_ymd (gdt_local, &yr, &mo, &day);
-    g_date_time_unref (gdt_local);
-    g_assert_cmpint (r_day, ==, day);
-    g_assert_cmpint (r_mo, ==, mo);
-    g_assert_cmpint (r_yr, ==, yr);
-
-    t = g_date_time_to_timespec (gdt4);
-    gnc_timespec2dmy (t, &r_day, &r_mo, &r_yr);
-    gdt_local = g_date_time_to_local (gdt4);
-    g_date_time_get_ymd (gdt_local, &yr, &mo, &day);
-    g_date_time_unref (gdt_local);
-    g_assert_cmpint (r_day, ==, day);
-    g_assert_cmpint (r_mo, ==, mo);
-    g_assert_cmpint (r_yr, ==, yr);
-
-    t = g_date_time_to_timespec (gdt5);
-    gnc_timespec2dmy (t, &r_day, &r_mo, &r_yr);
-    gdt_local = g_date_time_to_local (gdt5);
-    g_date_time_get_ymd (gdt_local, &yr, &mo, &day);
-    g_date_time_unref (gdt_local);
-    /* 2038 Bug */
-    g_assert_cmpint (r_day, ==, day);
-    g_assert_cmpint (r_mo, ==, mo);
-    g_assert_cmpint (r_yr, ==, yr);
-
-    g_date_time_unref (gdt0);
-    g_date_time_unref (gdt1);
-    g_date_time_unref (gdt2);
-    g_date_time_unref (gdt3);
-    g_date_time_unref (gdt4);
-    g_date_time_unref (gdt5);
-    g_time_zone_unref (zulu);
-    g_time_zone_unref (tz05);
-    g_time_zone_unref (tz0840);
+
+    gnc_timespec2dmy (f->ts0, &r_day, &r_mo, &r_yr);
+    gnc_localtime_r (&f->ts0.tv_sec, &tm);
+    g_assert_cmpint (r_day, ==, tm.tm_mday);
+    g_assert_cmpint (r_mo, ==, tm.tm_mon + 1);
+    g_assert_cmpint (r_yr, ==, tm.tm_year + 1900);
+
+    gnc_timespec2dmy (f->ts1, &r_day, &r_mo, &r_yr);
+    gnc_localtime_r (&f->ts1.tv_sec, &tm);
+    g_assert_cmpint (r_day, ==, tm.tm_mday);
+    g_assert_cmpint (r_mo, ==, tm.tm_mon + 1);
+    g_assert_cmpint (r_yr, ==, tm.tm_year + 1900);
+
+    gnc_timespec2dmy (f->ts2, &r_day, &r_mo, &r_yr);
+    gnc_localtime_r (&f->ts2.tv_sec, &tm);
+    g_assert_cmpint (r_day, ==, tm.tm_mday);
+    g_assert_cmpint (r_mo, ==, tm.tm_mon + 1);
+    g_assert_cmpint (r_yr, ==, tm.tm_year + 1900);
+
+    gnc_timespec2dmy (f->ts3, &r_day, &r_mo, &r_yr);
+    gnc_localtime_r (&f->ts3.tv_sec, &tm);
+    g_assert_cmpint (r_day, ==, tm.tm_mday);
+    g_assert_cmpint (r_mo, ==, tm.tm_mon + 1);
+    g_assert_cmpint (r_yr, ==, tm.tm_year + 1900);
+
+    gnc_timespec2dmy (f->ts4, &r_day, &r_mo, &r_yr);
+    gnc_localtime_r (&f->ts4.tv_sec, &tm);
+    g_assert_cmpint (r_day, ==, tm.tm_mday);
+    g_assert_cmpint (r_mo, ==, tm.tm_mon + 1);
+    g_assert_cmpint (r_yr, ==, tm.tm_year + 1900);
+
+    gnc_timespec2dmy (f->ts5, &r_day, &r_mo, &r_yr);
+    gnc_localtime_r (&f->ts5.tv_sec, &tm);
+    g_assert_cmpint (r_day, ==, tm.tm_mday);
+    g_assert_cmpint (r_mo, ==, tm.tm_mon + 1);
+    g_assert_cmpint (r_yr, ==, tm.tm_year + 1900);
+
 }
 /* gnc_dmy2timespec_internal
 static Timespec
@@ -1807,89 +1754,47 @@ Timespec
 gnc_dmy2timespec (int day, int month, int year)// C: 8 in 5  Local: 1:0:0
 */
 static void
-test_gnc_dmy2timespec (void)
-{
-    GDateTime *gdt1 = g_date_time_new_local (1999, 7, 21, 0, 0, 0);
-    GDateTime *gdt2 = g_date_time_new_local (1918, 3, 31, 0, 0, 0);
-    GDateTime *gdt3 = g_date_time_new_local (1918, 4, 1, 0, 0, 0);
-    GDateTime *gdt4 = g_date_time_new_local (2057, 11, 20, 0, 0, 0);
-
-    gint day, mon, yr;
-    Timespec t, r_t;
-
-    t = g_date_time_to_timespec (gdt1);
-    g_date_time_get_ymd (gdt1, &yr, &mon, &day);
-    r_t = gnc_dmy2timespec (day, mon, yr);
-    g_assert_cmpint (r_t.tv_sec, ==, t.tv_sec);
-    g_assert_cmpint (r_t.tv_nsec, ==, t.tv_nsec);
-
-    t = g_date_time_to_timespec (gdt2);
-    g_date_time_get_ymd (gdt2, &yr, &mon, &day);
-    r_t = gnc_dmy2timespec (day, mon, yr);
-    g_assert_cmpint (r_t.tv_sec, ==, t.tv_sec);
-    g_assert_cmpint (r_t.tv_nsec, ==, t.tv_nsec);
-
-    t = g_date_time_to_timespec (gdt3);
-    g_date_time_get_ymd (gdt3, &yr, &mon, &day);
-    r_t = gnc_dmy2timespec (day, mon, yr);
-    g_assert_cmpint (r_t.tv_sec, ==, t.tv_sec);
-    g_assert_cmpint (r_t.tv_nsec, ==, t.tv_nsec);
-
-    t = g_date_time_to_timespec (gdt4);
-    g_date_time_get_ymd (gdt4, &yr, &mon, &day);
-    r_t = gnc_dmy2timespec (day, mon, yr);
-    g_assert_cmpint (r_t.tv_sec, ==, t.tv_sec);
-    g_assert_cmpint (r_t.tv_nsec, ==, t.tv_nsec);
-
-    g_date_time_unref (gdt1);
-    g_date_time_unref (gdt2);
-    g_date_time_unref (gdt3);
-    g_date_time_unref (gdt4);
+test_gnc_dmy2timespec (FixtureB *f, gconstpointer pData)
+{
+
+    for (int i = 0; i < sizeof(f->test)/sizeof(TimeMap); ++i)
+    {
+#ifdef HAVE_STRUCT_TM_GMTOFF
+	struct tm tm = {0, 0, 0, f->test[i].day, f->test[i].mon - 1,
+			f->test[i].yr - 1900, 0, 0, -1, 0, NULL};
+#else
+	struct tm tm = {0, 0, 0, f->test[i].day, f->test[i].mon - 1,
+			f->test[i].yr - 1900, 0, 0, -1};
+#endif
+	Timespec r_t = gnc_dmy2timespec (f->test[i].day, f->test[i].mon,
+					 f->test[i].yr);
+	int offset = gnc_mktime(&tm) - gnc_timegm(&tm);
+	g_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs + offset);
+    }
 }
 /* gnc_dmy2timespec_end
 Timespec
 gnc_dmy2timespec_end (int day, int month, int year)// C: 1  Local: 0:0:0
 */
 static void
-test_gnc_dmy2timespec_end (void)
-{
-    GDateTime *gdt1 = g_date_time_new_local (1999, 7, 21,23,59, 59);
-    GDateTime *gdt2 = g_date_time_new_local (1918, 3, 30, 23, 59, 59);
-    GDateTime *gdt3 = g_date_time_new_local (1918, 3, 31, 23, 59, 59);
-    GDateTime *gdt4 = g_date_time_new_local (2057, 11, 20, 23, 59, 59);
-
-    gint day, mon, yr;
-    Timespec t, r_t;
-
-    t = g_date_time_to_timespec (gdt1);
-    g_date_time_get_ymd (gdt1, &yr, &mon, &day);
-    r_t = gnc_dmy2timespec_end (day, mon, yr);
-    g_assert_cmpint (r_t.tv_sec, ==, t.tv_sec);
-    g_assert_cmpint (r_t.tv_nsec, ==, t.tv_nsec);
-
-    t = g_date_time_to_timespec (gdt2);
-    g_date_time_get_ymd (gdt2, &yr, &mon, &day);
-    r_t = gnc_dmy2timespec_end (day, mon, yr);
-    g_assert_cmpint (r_t.tv_sec, ==, t.tv_sec);
-    g_assert_cmpint (r_t.tv_nsec, ==, t.tv_nsec);
-
-    t = g_date_time_to_timespec (gdt3);
-    g_date_time_get_ymd (gdt3, &yr, &mon, &day);
-    r_t = gnc_dmy2timespec_end (day, mon, yr);
-    g_assert_cmpint (r_t.tv_sec, ==, t.tv_sec);
-    g_assert_cmpint (r_t.tv_nsec, ==, t.tv_nsec);
-
-    t = g_date_time_to_timespec (gdt4);
-    g_date_time_get_ymd (gdt4, &yr, &mon, &day);
-    r_t = gnc_dmy2timespec_end (day, mon, yr);
-    g_assert_cmpint (r_t.tv_sec, ==, t.tv_sec);
-    g_assert_cmpint (r_t.tv_nsec, ==, t.tv_nsec);
-
-    g_date_time_unref (gdt1);
-    g_date_time_unref (gdt2);
-    g_date_time_unref (gdt3);
-    g_date_time_unref (gdt4);
+test_gnc_dmy2timespec_end (FixtureB *f, gconstpointer pData)
+{
+    for (int i = 0; i < sizeof(f->test)/sizeof(TimeMap); ++i)
+    {
+#ifdef HAVE_STRUCT_TM_GMTOFF
+	struct tm tm = {59, 59, 23, f->test[i].day, f->test[i].mon - 1,
+			f->test[i].yr - 1900, 0, 0, -1, 0, NULL};
+#else
+	struct tm tm = {59, 59, 23, f->test[i].day, f->test[i].mon - 1,
+			f->test[i].yr - 1900, 0, 0, -1};
+#endif
+	Timespec r_t = gnc_dmy2timespec_end (f->test[i].day, f->test[i].mon,
+					     f->test[i].yr);
+	int offset = gnc_mktime(&tm) - gnc_timegm(&tm);
+	g_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs + offset);
+    }
 }
+
 /* gnc_timezone
 long int
 gnc_timezone (const struct tm *tm)// C: 5 in 2  Local: 2:0:0
@@ -1926,132 +1831,73 @@ test_timespecTotime64 (void)
 GDate timespec_to_gdate (Timespec ts)// C: 5 in 4  Local: 0:0:0
 */
 static void
-test_timespec_to_gdate (void)
-{
-    GTimeZone *zulu = g_time_zone_new ("Z");
-    GTimeZone *tz05 = g_time_zone_new ("-05");
-    GTimeZone *tz0840 = g_time_zone_new ("+08:40");
-    GDateTime *gdt0 = g_date_time_new_from_unix_utc (0);
-    GDateTime *gdt1 = g_date_time_new (zulu, 1989, 3, 27, 13, 43, 27.345678);
-    GDateTime *gdt2 = g_date_time_new (tz05, 2020, 11, 7, 6, 21, 19.0);
-    GDateTime *gdt3 = g_date_time_new (tz0840, 2012, 7, 4, 19, 27, 44.0);
-    GDateTime *gdt4 = g_date_time_new (tz05, 1961, 9, 22, 17, 53, 19.0);
-    GDateTime *gdt5 = g_date_time_new (tz05, 2061, 1, 25, 23, 21, 19.0);
-    GDateTime *gdt_local;
-
-    gint day, mon, yr;
+test_timespec_to_gdate (FixtureA *f, gconstpointer pData)
+{
     GDate date1, date2;
-    Timespec t;
+    struct tm tm;
 
     g_date_clear (&date2, 1);
 
-    t = g_date_time_to_timespec (gdt0);
-    date1 = timespec_to_gdate (t);
-    gdt_local = g_date_time_to_local (gdt0);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    g_date_time_unref (gdt_local);
-    g_date_set_dmy (&date2, day, mon, yr);
-    g_assert_cmpint (g_date_get_julian (&date1), ==, g_date_get_julian (&date2));
-
-    t = g_date_time_to_timespec (gdt1);
-    date1 = timespec_to_gdate (t);
-    gdt_local = g_date_time_to_local (gdt1);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    g_date_time_unref (gdt_local);
-    g_date_set_dmy (&date2, day, mon, yr);
-    g_assert_cmpint (g_date_get_julian (&date1), ==, g_date_get_julian (&date2));
-
-    t = g_date_time_to_timespec (gdt2);
-    date1 = timespec_to_gdate (t);
-    gdt_local = g_date_time_to_local (gdt2);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    g_date_time_unref (gdt_local);
-    g_date_set_dmy (&date2, day, mon, yr);
-    g_assert_cmpint (g_date_get_julian (&date1), ==, g_date_get_julian (&date2));
-
-    t = g_date_time_to_timespec (gdt3);
-    date1 = timespec_to_gdate (t);
-    gdt_local = g_date_time_to_local (gdt3);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    g_date_time_unref (gdt_local);
-    g_date_set_dmy (&date2, day, mon, yr);
-    g_assert_cmpint (g_date_get_julian (&date1), ==, g_date_get_julian (&date2));
-    t = g_date_time_to_timespec (gdt4);
-    date1 = timespec_to_gdate (t);
-    gdt_local = g_date_time_to_local (gdt4);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    g_date_time_unref (gdt_local);
-    g_date_set_dmy (&date2, day, mon, yr);
-    g_assert_cmpint (g_date_get_julian (&date1), ==, g_date_get_julian (&date2));
-
-    t = g_date_time_to_timespec (gdt5);
-    date1 = timespec_to_gdate (t);
-    gdt_local = g_date_time_to_local (gdt5);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    g_date_time_unref (gdt_local);
-    g_date_set_dmy (&date2, day, mon, yr);
-    g_assert_cmpint (g_date_get_julian (&date1),
-                     ==, g_date_get_julian (&date2));
-
-    g_date_time_unref (gdt0);
-    g_date_time_unref (gdt1);
-    g_date_time_unref (gdt2);
-    g_date_time_unref (gdt3);
-    g_date_time_unref (gdt4);
-    g_date_time_unref (gdt5);
-    g_time_zone_unref (zulu);
-    g_time_zone_unref (tz05);
-    g_time_zone_unref (tz0840);
+    date1 = timespec_to_gdate (f->ts0);
+    gnc_localtime_r(&f->ts0.tv_sec, &tm);
+    g_date_set_dmy (&date2, tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
+    g_assert_cmpint (g_date_get_julian (&date1), ==,
+		     g_date_get_julian (&date2));
+
+    date1 = timespec_to_gdate (f->ts1);
+    gnc_localtime_r(&f->ts1.tv_sec, &tm);
+    g_date_set_dmy (&date2, tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
+    g_assert_cmpint (g_date_get_julian (&date1), ==,
+		     g_date_get_julian (&date2));
+
+    date1 = timespec_to_gdate (f->ts2);
+    gnc_localtime_r(&f->ts2.tv_sec, &tm);
+    g_date_set_dmy (&date2, tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
+    g_assert_cmpint (g_date_get_julian (&date1), ==,
+		     g_date_get_julian (&date2));
+
+    date1 = timespec_to_gdate (f->ts3);
+    gnc_localtime_r(&f->ts3.tv_sec, &tm);
+    g_date_set_dmy (&date2, tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
+    g_assert_cmpint (g_date_get_julian (&date1), ==,
+		     g_date_get_julian (&date2));
+
+    date1 = timespec_to_gdate (f->ts4);
+    gnc_localtime_r(&f->ts4.tv_sec, &tm);
+    g_date_set_dmy (&date2, tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
+    g_assert_cmpint (g_date_get_julian (&date1), ==,
+		     g_date_get_julian (&date2));
+
+    date1 = timespec_to_gdate (f->ts5);
+    gnc_localtime_r(&f->ts5.tv_sec, &tm);
+    g_date_set_dmy (&date2, tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
+    g_assert_cmpint (g_date_get_julian (&date1), ==,
+		     g_date_get_julian (&date2));
 }
+
 /* gdate_to_timespec
 Timespec gdate_to_timespec (GDate d)// C: 7 in 6  Local: 0:0:0
 */
 static void
-test_gdate_to_timespec (void)
-{
-    GDateTime *gdt1 = g_date_time_new_local (1999, 7, 21, 0, 0, 0);
-    GDateTime *gdt2 = g_date_time_new_local (1918, 3, 31, 0, 0, 0);
-    GDateTime *gdt3 = g_date_time_new_local (1918, 4, 1, 0, 0, 0);
-    GDateTime *gdt4 = g_date_time_new_local (2057, 11, 20, 0, 0, 0);
-
-    gint day, mon, yr;
-    Timespec t, r_t;
-    GDate gd;
-
-    g_date_clear (&gd, 1);
-
-    t = g_date_time_to_timespec (gdt1);
-    g_date_time_get_ymd (gdt1, &yr, &mon, &day);
-    g_date_set_dmy (&gd, day, mon, yr);
-    r_t = gdate_to_timespec (gd);
-    g_assert_cmpint (r_t.tv_sec, ==, t.tv_sec);
-    g_assert_cmpint (r_t.tv_nsec, ==, t.tv_nsec);
-
-    t = g_date_time_to_timespec (gdt2);
-    g_date_time_get_ymd (gdt2, &yr, &mon, &day);
-    g_date_set_dmy (&gd, day, mon, yr);
-    r_t = gdate_to_timespec (gd);
-    g_assert_cmpint (r_t.tv_sec, ==, t.tv_sec);
-    g_assert_cmpint (r_t.tv_nsec, ==, t.tv_nsec);
-
-    t = g_date_time_to_timespec (gdt3);
-    g_date_time_get_ymd (gdt3, &yr, &mon, &day);
-    g_date_set_dmy (&gd, day, mon, yr);
-    r_t = gdate_to_timespec (gd);
-    g_assert_cmpint (r_t.tv_sec, ==, t.tv_sec);
-    g_assert_cmpint (r_t.tv_nsec, ==, t.tv_nsec);
-
-    t = g_date_time_to_timespec (gdt4);
-    g_date_time_get_ymd (gdt4, &yr, &mon, &day);
-    g_date_set_dmy (&gd, day, mon, yr);
-    r_t = gdate_to_timespec (gd);
-    g_assert_cmpint (r_t.tv_sec, ==, t.tv_sec);
-    g_assert_cmpint (r_t.tv_nsec, ==, t.tv_nsec);
-
-    g_date_time_unref (gdt1);
-    g_date_time_unref (gdt2);
-    g_date_time_unref (gdt3);
-    g_date_time_unref (gdt4);
+test_gdate_to_timespec (FixtureB *f, gconstpointer pData)
+{
+    for (int i = 0; i < sizeof(f->test)/sizeof(TimeMap); ++i)
+    {
+#ifdef HAVE_STRUCT_TM_GMTOFF
+	struct tm tm = {0, 0, 0, f->test[i].day, f->test[i].mon - 1,
+			f->test[i].yr - 1900, 0, 0, -1, 0, NULL};
+#else
+	struct tm tm = {0, 0, 0, f->test[i].day, f->test[i].mon - 1,
+			f->test[i].yr - 1900, 0, 0, -1};
+#endif
+	GDate gd;
+	Timespec r_t;
+	int offset = gnc_mktime(&tm) - gnc_timegm(&tm);
+	g_date_clear(&gd, 1);
+	g_date_set_dmy(&gd, f->test[i].day, f->test[i].mon, f->test[i].yr);
+	r_t = gdate_to_timespec(gd);
+	g_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs + offset);
+    }
 }
 /* gnc_tm_get_day_start
 static void
@@ -2073,160 +1919,112 @@ test_gnc_tm_get_day_end (void)
 time64
 gnc_time64_get_day_start (time64 time_val)// C: 8 in 7  Local: 0:0:0
 */
+
+static void
+tm_day_begin(struct tm *tm)
+{
+    tm->tm_hour = 0;
+    tm->tm_min = 0;
+    tm->tm_sec = 0;
+}
+
 static void
-test_gnc_time64_get_day_start (void)
-{
-    GTimeZone *zulu = g_time_zone_new ("Z");
-    GTimeZone *tz05 = g_time_zone_new ("-05");
-    GTimeZone *tz0840 = g_time_zone_new ("+08:40");
-    GDateTime *gdt0 = g_date_time_new_from_unix_utc (0);
-    GDateTime *gdt1 = g_date_time_new (zulu, 1989, 3, 27, 13, 43, 27.345678);
-    GDateTime *gdt2 = g_date_time_new (tz05, 2020, 11, 7, 6, 21, 19.0);
-    GDateTime *gdt3 = g_date_time_new (tz0840, 2012, 7, 4, 19, 27, 44.0);
-    GDateTime *gdt4 = g_date_time_new (tz05, 1961, 9, 22, 17, 53, 19.0);
-    GDateTime *gdt5 = g_date_time_new (tz05, 2061, 1, 25, 23, 21, 19.0);
-    GDateTime *gdt_local, *gdt_day_begin;
-
-    gint day, mon, yr;
-    time64 time, t_time, r_time;
-
-    gdt_local = g_date_time_to_local (gdt0);
-    time = g_date_time_to_unix (gdt0);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_begin = g_date_time_new_local (yr, mon, day, 0, 0, 0);
-    t_time = g_date_time_to_unix (gdt_day_begin);
-    r_time = gnc_time64_get_day_start (time);
-    /* This will work in the half of the world where localtime is later than UTC */
+test_gnc_time64_get_day_start (FixtureA *f, gconstpointer pData)
+{
+    struct tm tm;
+    time64 t_time, r_time;
+
+    gnc_localtime_r(&f->ts0.tv_sec, &tm);
+    tm_day_begin(&tm);
+    t_time = gnc_mktime(&tm);
+    r_time = gnc_time64_get_day_start (f->ts0.tv_sec);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = g_date_time_to_local (gdt1);
-    time = g_date_time_to_unix (gdt1);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_begin = g_date_time_new_local (yr, mon, day, 0, 0, 0);
-    t_time = g_date_time_to_unix (gdt_day_begin);
-    r_time = gnc_time64_get_day_start (time);
+    gnc_localtime_r(&f->ts1.tv_sec, &tm);
+    tm_day_begin(&tm);
+    t_time = gnc_mktime(&tm);
+    r_time = gnc_time64_get_day_start (f->ts1.tv_sec);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = g_date_time_to_local (gdt2);
-    time = g_date_time_to_unix (gdt2);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_begin = g_date_time_new_local (yr, mon, day, 0, 0, 0);
-    t_time = g_date_time_to_unix (gdt_day_begin);
-    r_time = gnc_time64_get_day_start (time);
+    gnc_localtime_r(&f->ts2.tv_sec, &tm);
+    tm_day_begin(&tm);
+    t_time = gnc_mktime(&tm);
+    r_time = gnc_time64_get_day_start (f->ts2.tv_sec);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = g_date_time_to_local (gdt3);
-    time = g_date_time_to_unix (gdt3);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_begin = g_date_time_new_local (yr, mon, day, 0, 0, 0);
-    t_time = g_date_time_to_unix (gdt_day_begin);
-    r_time = gnc_time64_get_day_start (time);
+    gnc_localtime_r(&f->ts3.tv_sec, &tm);
+    tm_day_begin(&tm);
+    t_time = gnc_mktime(&tm);
+    r_time = gnc_time64_get_day_start (f->ts3.tv_sec);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = g_date_time_to_local (gdt4);
-    time = g_date_time_to_unix (gdt4);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_begin = g_date_time_new_local (yr, mon, day, 0, 0, 0);
-    t_time = g_date_time_to_unix (gdt_day_begin);
-    r_time = gnc_time64_get_day_start (time);
+    gnc_localtime_r(&f->ts4.tv_sec, &tm);
+    tm_day_begin(&tm);
+    t_time = gnc_mktime(&tm);
+    r_time = gnc_time64_get_day_start (f->ts4.tv_sec);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = g_date_time_to_local (gdt5);
-    time = g_date_time_to_unix (gdt5);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_begin = g_date_time_new_local (yr, mon, day, 0, 0, 0);
-    t_time = g_date_time_to_unix (gdt_day_begin);
-    r_time = gnc_time64_get_day_start (time);
+    gnc_localtime_r(&f->ts5.tv_sec, &tm);
+    tm_day_begin(&tm);
+    t_time = gnc_mktime(&tm);
+    r_time = gnc_time64_get_day_start (f->ts5.tv_sec);
     g_assert_cmpint (t_time, ==, r_time);
 
-    g_date_time_unref (gdt0);
-    g_date_time_unref (gdt1);
-    g_date_time_unref (gdt2);
-    g_date_time_unref (gdt3);
-    g_date_time_unref (gdt4);
-    g_date_time_unref (gdt5);
-    g_time_zone_unref (zulu);
-    g_time_zone_unref (tz05);
-    g_time_zone_unref (tz0840);
-}
+ }
 /* gnc_time64_get_day_end
 time64
 gnc_time64_get_day_end (time64 time_val)// C: 12 in 8  Local: 0:0:0
 */
 static void
-test_gnc_time64_get_day_end (void)
-{
-    GTimeZone *zulu = g_time_zone_new ("Z");
-    GTimeZone *tz05 = g_time_zone_new ("-05");
-    GTimeZone *tz0840 = g_time_zone_new ("+08:40");
-    GDateTime *gdt0 = g_date_time_new_from_unix_utc (0);
-    GDateTime *gdt1 = g_date_time_new (zulu, 1989, 3, 27, 13, 43, 27.345678);
-    GDateTime *gdt2 = g_date_time_new (tz05, 2020, 11, 7, 6, 21, 19.0);
-    GDateTime *gdt3 = g_date_time_new (tz0840, 2012, 7, 4, 19, 27, 44.0);
-    GDateTime *gdt4 = g_date_time_new (tz05, 1961, 9, 22, 17, 53, 19.0);
-    GDateTime *gdt5 = g_date_time_new (tz05, 2061, 1, 25, 23, 21, 19.0);
-    GDateTime *gdt_local, *gdt_day_end;
-
-    gint day, mon, yr;
-    time64 time, t_time, r_time;
-
-    gdt_local = g_date_time_to_local (gdt0);
-    time = g_date_time_to_unix (gdt0);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_end = g_date_time_new_local (yr, mon, day, 23, 59, 59);
-    t_time = g_date_time_to_unix (gdt_day_end);
-    r_time = gnc_time64_get_day_end (time);
+tm_day_end(struct tm *tm)
+{
+    tm->tm_hour = 23;
+    tm->tm_min = 59;
+    tm->tm_sec = 59;
+}
+
+static void
+test_gnc_time64_get_day_end (FixtureA *f, gconstpointer pData)
+{
+    struct tm tm;
+    time64 t_time, r_time;
+
+    gnc_localtime_r(&f->ts0.tv_sec, &tm);
+    tm_day_end(&tm);
+    t_time = gnc_mktime(&tm);
+    r_time = gnc_time64_get_day_end (f->ts0.tv_sec);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = g_date_time_to_local (gdt1);
-    time = g_date_time_to_unix (gdt1);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_end = g_date_time_new_local (yr, mon, day, 23, 59, 59);
-    t_time = g_date_time_to_unix (gdt_day_end);
-    r_time = gnc_time64_get_day_end (time);
+    gnc_localtime_r(&f->ts1.tv_sec, &tm);
+    tm_day_end(&tm);
+    t_time = gnc_mktime(&tm);
+    r_time = gnc_time64_get_day_end (f->ts1.tv_sec);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = g_date_time_to_local (gdt2);
-    time = g_date_time_to_unix (gdt2);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_end = g_date_time_new_local (yr, mon, day, 23, 59, 59);
-    t_time = g_date_time_to_unix (gdt_day_end);
-    r_time = gnc_time64_get_day_end (time);
+    gnc_localtime_r(&f->ts2.tv_sec, &tm);
+    tm_day_end(&tm);
+    t_time = gnc_mktime(&tm);
+    r_time = gnc_time64_get_day_end (f->ts2.tv_sec);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = g_date_time_to_local (gdt3);
-    time = g_date_time_to_unix (gdt3);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_end = g_date_time_new_local (yr, mon, day, 23, 59, 59);
-    t_time = g_date_time_to_unix (gdt_day_end);
-    r_time = gnc_time64_get_day_end (time);
+    gnc_localtime_r(&f->ts3.tv_sec, &tm);
+    tm_day_end(&tm);
+    t_time = gnc_mktime(&tm);
+    r_time = gnc_time64_get_day_end (f->ts3.tv_sec);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = g_date_time_to_local (gdt4);
-    time = g_date_time_to_unix (gdt4);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_end = g_date_time_new_local (yr, mon, day, 23, 59, 59);
-    t_time = g_date_time_to_unix (gdt_day_end);
-    r_time = gnc_time64_get_day_end (time);
+    gnc_localtime_r(&f->ts4.tv_sec, &tm);
+    tm_day_end(&tm);
+    t_time = gnc_mktime(&tm);
+    r_time = gnc_time64_get_day_end (f->ts4.tv_sec);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = g_date_time_to_local (gdt5);
-    time = g_date_time_to_unix (gdt5);
-    g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_end = g_date_time_new_local (yr, mon, day, 23, 59, 59);
-    t_time = g_date_time_to_unix (gdt_day_end);
-    r_time = gnc_time64_get_day_end (time);
+    gnc_localtime_r(&f->ts5.tv_sec, &tm);
+    tm_day_end(&tm);
+    t_time = gnc_mktime(&tm);
+    r_time = gnc_time64_get_day_end (f->ts5.tv_sec);
     g_assert_cmpint (t_time, ==, r_time);
 
-    g_date_time_unref (gdt0);
-    g_date_time_unref (gdt1);
-    g_date_time_unref (gdt2);
-    g_date_time_unref (gdt3);
-    g_date_time_unref (gdt4);
-    g_date_time_unref (gdt5);
-    g_time_zone_unref (zulu);
-    g_time_zone_unref (tz05);
-    g_time_zone_unref (tz0840);
 }
 /* gnc_tm_get_today_start
 void
@@ -2326,22 +2124,22 @@ test_suite_gnc_date (void)
 // GNC_TEST_ADD_FUNC (suitename, "qof format time", test_qof_format_time);
 // GNC_TEST_ADD_FUNC (suitename, "qof strftime", test_qof_strftime);
     GNC_TEST_ADD_FUNC (suitename, "gnc_date_timestamp", test_gnc_date_timestamp);
-    GNC_TEST_ADD_FUNC (suitename, "gnc iso8601 to timespec gmt", test_gnc_iso8601_to_timespec_gmt);
-    GNC_TEST_ADD_FUNC (suitename, "gnc timespec to iso8601 buff", test_gnc_timespec_to_iso8601_buff);
-    GNC_TEST_ADD_FUNC (suitename, "gnc timespec2dmy", test_gnc_timespec2dmy);
+    GNC_TEST_ADD (suitename, "gnc iso8601 to timespec gmt", FixtureA, NULL, setup, test_gnc_iso8601_to_timespec_gmt, NULL);
+    GNC_TEST_ADD (suitename, "gnc timespec to iso8601 buff", FixtureA, NULL, setup, test_gnc_timespec_to_iso8601_buff, NULL);
+    GNC_TEST_ADD (suitename, "gnc timespec2dmy", FixtureA, NULL, setup, test_gnc_timespec2dmy, NULL);
 // GNC_TEST_ADD_FUNC (suitename, "gnc dmy2timespec internal", test_gnc_dmy2timespec_internal);
-    GNC_TEST_ADD_FUNC (suitename, "gnc dmy2timespec", test_gnc_dmy2timespec);
-    GNC_TEST_ADD_FUNC (suitename, "gnc dmy2timespec end", test_gnc_dmy2timespec_end);
+    GNC_TEST_ADD (suitename, "gnc dmy2timespec", FixtureB, NULL, setup_begin, test_gnc_dmy2timespec, NULL);
+    GNC_TEST_ADD (suitename, "gnc dmy2timespec end", FixtureB, NULL, setup_end, test_gnc_dmy2timespec_end, NULL);
 // GNC_TEST_ADD_FUNC (suitename, "gnc timezone", test_gnc_timezone);
 // GNC_TEST_ADD_FUNC (suitename, "timespecFromTime t", test_timespecFromtime64);
 // GNC_TEST_ADD_FUNC (suitename, "timespec now", test_timespec_now);
 // GNC_TEST_ADD_FUNC (suitename, "timespecToTime t", test_timespecTotime64);
-    GNC_TEST_ADD_FUNC (suitename, "timespec to gdate", test_timespec_to_gdate);
-    GNC_TEST_ADD_FUNC (suitename, "gdate to timespec", test_gdate_to_timespec);
+    GNC_TEST_ADD (suitename, "timespec to gdate", FixtureA, NULL, setup, test_timespec_to_gdate, NULL);
+    GNC_TEST_ADD (suitename, "gdate to timespec", FixtureB, NULL, setup_begin, test_gdate_to_timespec, NULL);
 // GNC_TEST_ADD_FUNC (suitename, "gnc tm get day start", test_gnc_tm_get_day_start);
 // GNC_TEST_ADD_FUNC (suitename, "gnc tm get day end", test_gnc_tm_get_day_end);
-    GNC_TEST_ADD_FUNC (suitename, "gnc time64 get day start", test_gnc_time64_get_day_start);
-    GNC_TEST_ADD_FUNC (suitename, "gnc time64 get day end", test_gnc_time64_get_day_end);
+    GNC_TEST_ADD (suitename, "gnc time64 get day start", FixtureA, NULL, setup, test_gnc_time64_get_day_start, NULL);
+    GNC_TEST_ADD (suitename, "gnc time64 get day end", FixtureA, NULL, setup, test_gnc_time64_get_day_end, NULL);
 // GNC_TEST_ADD_FUNC (suitename, "gnc tm get today start", test_gnc_tm_get_today_start);
 // GNC_TEST_ADD_FUNC (suitename, "gnc timet get today start", test_gnc_time64_get_today_start);
 // GNC_TEST_ADD_FUNC (suitename, "gnc timet get today end", test_gnc_time64_get_today_end);

commit 327ef838ea05151120b44ced18463dfff174df4e
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Feb 27 15:34:39 2015 -0800

    Correct a couple of incorrect comments.

diff --git a/src/libqof/qof/gnc-date.h b/src/libqof/qof/gnc-date.h
index bcefb81..6c75372 100644
--- a/src/libqof/qof/gnc-date.h
+++ b/src/libqof/qof/gnc-date.h
@@ -186,7 +186,7 @@ struct tm* gnc_localtime_r (const time64 *secs, struct tm* time);
 struct tm* gnc_gmtime (const time64 *secs);
 
 /** \brief calculate seconds from the epoch given a time struct
- *  \param time: A struct tm* for the function to fill.
+ *  \param time: A struct tm* containing the date-time information.
  *  The time is understood to be in the current local time zone.
  *  \return Seconds since 00:00:01 UTC 01 January 1970 (negative values
  * are seconds before that moment).
@@ -194,7 +194,7 @@ struct tm* gnc_gmtime (const time64 *secs);
 time64 gnc_mktime (struct tm* time);
 
 /** \brief calculate seconds from the epoch given a time struct
- *  \param time: A struct tm* for the function to fill.
+ *  \param time: A struct tm* containing the date-time information
  *  The time is understood to be utc.
  *  \return Seconds since 00:00:01 UTC 01 January 1970 (negative values
  * are seconds before that moment).

commit e938b39ff2d7a07f7c7b08abddb9768891ed803e
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Feb 27 15:34:21 2015 -0800

    Remove gnc_time_utc.
    
    It produces exactly the same result as gnc_time: The current utc time.

diff --git a/src/import-export/aqb/gnc-ab-utils.c b/src/import-export/aqb/gnc-ab-utils.c
index 1998c0d..fb6c926 100644
--- a/src/import-export/aqb/gnc-ab-utils.c
+++ b/src/import-export/aqb/gnc-ab-utils.c
@@ -506,7 +506,7 @@ gnc_ab_trans_to_gnc(const AB_TRANSACTION *ab_trans, Account *gnc_acc)
     else
         g_warning("transaction_cb: Oops, date 'valuta_date' was NULL");
 
-    xaccTransSetDateEnteredSecs(gnc_trans, gnc_time_utc (NULL));
+    xaccTransSetDateEnteredSecs(gnc_trans, gnc_time (NULL));
 
     /* Currency.  We take simply the default currency of the gnucash account */
     xaccTransSetCurrency(gnc_trans, xaccAccountGetCommodity(gnc_acc));
diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index 7ef9761..f523546 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -284,18 +284,6 @@ time64
 gnc_time (time64 *tbuf)
 {
     auto pdt = boost::posix_time::second_clock::universal_time();
-    auto tz = tzp.get(pdt.date().year());
-    LDT ldt(pdt, tz);
-    auto secs = time64_from_date_time(pdt);
-    if (tbuf != nullptr)
-	  *tbuf = secs;
-     return secs;
-}
-
-time64
-gnc_time_utc (time64 *tbuf)
-{
-    auto pdt = boost::posix_time::second_clock::universal_time();
     auto secs = time64_from_date_time(pdt);
      if (tbuf != NULL)
 	  *tbuf = secs;
diff --git a/src/libqof/qof/gnc-date.h b/src/libqof/qof/gnc-date.h
index f166a78..bcefb81 100644
--- a/src/libqof/qof/gnc-date.h
+++ b/src/libqof/qof/gnc-date.h
@@ -219,14 +219,6 @@ gchar* gnc_ctime (const time64 *secs);
  */
 time64 gnc_time (time64 *tbuf);
 
-/** \brief get the current utc time
- *  \param A time64* which, if not NULL, will be filled in with the same
- * value as is returned.
- * \return Seconds since 00:00:01 UTC 01 January 1970 (negative values
- * are seconds before that moment)
- */
-time64 gnc_time_utc (time64 *tbuf);
-
 /** \brief Find the difference in seconds between two time values
  *  \param secs1: The first time value, in Seconds since
  * 00:00:01 UTC 01 January 1970 (negative values are seconds before that moment)

commit 4f90e4e0507657e0a98f66999a62e4cce46cdc7b
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Feb 27 15:32:46 2015 -0800

    Get rid of gettimeofday call in Transaction.
    
    We were throwing away the microseconds anyway.

diff --git a/src/engine/Transaction.c b/src/engine/Transaction.c
index 73ec15d..fb195c1 100644
--- a/src/engine/Transaction.c
+++ b/src/engine/Transaction.c
@@ -1627,15 +1627,7 @@ xaccTransCommitEdit (Transaction *trans)
     /* Record the time of last modification */
     if (0 == trans->date_entered.tv_sec)
     {
-        struct timeval tv;
-#ifdef HAVE_GETTIMEOFDAY
-        gettimeofday (&tv, NULL);
-#else
-        time (&(tv.tv_sec));
-        tv.tv_usec = 0;
-#endif
-        trans->date_entered.tv_sec = tv.tv_sec;
-//        trans->date_entered.tv_nsec = 1000 * tv.tv_usec;
+	trans->date_entered.tv_sec = gnc_time(NULL);
         qof_instance_set_dirty(QOF_INSTANCE(trans));
     }
 

commit 99efb5d44634407c8d69f1747b94e26acf7f6615
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Feb 26 12:00:52 2015 -0800

    Reimplement gnc_timespec_to_iso8601_buff to handle microseconds.
    
    Just because there are tests that do. Removing fractional seconds (which
    are never used in live code) will be  a separate step.

diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index 6b1e6ff..7ef9761 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -1358,15 +1358,23 @@ char *
 gnc_timespec_to_iso8601_buff (Timespec ts, char * buff)
 {
     constexpr size_t max_iso_date_length = 32;
-    std::string fmt1 = "%Y-%m-%d %H:%M:%s %q";
+    const char* format = "%Y-%m-%d %H:%M:%s %q";
 
     if (! buff) return NULL;
 
-    memset(buff, 0, max_iso_date_length + 1);
-    char* str = gnc_print_time64(ts.tv_sec, fmt1.c_str());
-    strncpy (buff, str, max_iso_date_length);
-    free(str);
-    return buff + strlen (buff);
+    using Facet = boost::local_time::local_time_facet;
+    auto date_time = LDT_from_unix_local(ts.tv_sec);
+    date_time = date_time + boost::posix_time::microseconds(ts.tv_nsec / 1000);
+    std::stringstream ss;
+    //The stream destructor frees the facet, so it must be heap-allocated.
+    auto output_facet(new Facet(format));
+    ss.imbue(std::locale(std::locale(), output_facet));
+    ss << date_time;
+    auto sstr = ss.str();
+
+    memset(buff, 0, sstr.length() + 1);
+    strncpy(buff, sstr.c_str(), sstr.length());
+    return buff + sstr.length();
 }
 
 void

commit 23687ee21c69a0e1141b4770f16699036c17b2e5
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Feb 26 11:58:59 2015 -0800

    Replace random uses of GDateTime.

diff --git a/src/backend/sql/gnc-backend-sql.c b/src/backend/sql/gnc-backend-sql.c
index 5d25bad..2124be9 100644
--- a/src/backend/sql/gnc-backend-sql.c
+++ b/src/backend/sql/gnc-backend-sql.c
@@ -2057,12 +2057,10 @@ load_date( const GncSqlBackend* be, GncSqlRow* row,
 	if (G_VALUE_HOLDS_INT64 (val))
 	{
 	    gint64 time = g_value_get_int64 (val);
-	    GDateTime *gdt = g_date_time_new_from_unix_utc (time);
+	    Timespec ts = {time, 0};
+	    struct tm tm;
 	    gint day, month, year;
-	    GDate *date;
-	    g_date_time_get_ymd (gdt, &year, &month, &day);
-	    date = g_date_new_dmy (day, month, year);
-	    g_date_time_unref (gdt);
+	    GDate date = timespec_to_gdate(ts);
 	    if ( table_row->gobj_param_name != NULL )
 	    {
 		if (QOF_IS_INSTANCE (pObject))
@@ -2073,9 +2071,8 @@ load_date( const GncSqlBackend* be, GncSqlRow* row,
 	    }
 	    else
 	    {
-		(*setter)( pObject, date );
+		(*setter)( pObject, &date );
 	    }
-	    g_date_free( date );
 	}
         else if ( G_VALUE_HOLDS_STRING( val ) )
         {
diff --git a/src/backend/sql/test/utest-gnc-backend-sql.c b/src/backend/sql/test/utest-gnc-backend-sql.c
index 559b95c..4ab0446 100644
--- a/src/backend/sql/test/utest-gnc-backend-sql.c
+++ b/src/backend/sql/test/utest-gnc-backend-sql.c
@@ -575,42 +575,6 @@ test_gnc_sql_add_objectref_guid_col_info_to_list (Fixture *fixture, gconstpointe
 /* gnc_sql_convert_timespec_to_string
 gchar*
 gnc_sql_convert_timespec_to_string (const GncSqlBackend* be, Timespec ts)// C: 1 */
-static Timespec*
-gnc_date_string_to_timespec_gmt (gchar *datestr)
-{
-    Timespec *ts = g_slice_new0 (Timespec);
-    gint yr, mo, da, hr, min;
-    gdouble sec;
-    GDateTime *dt = NULL;
-
-    sscanf (datestr, "%04d-%02d-%02d %02d:%02d:%02lf",
-            &yr, &mo, &da, &hr, &min, &sec);
-    g_assert_cmpint (1, <=, yr);
-    g_assert_cmpint (9999, >=, yr);
-    g_assert_cmpint (1, <=, mo);
-    g_assert_cmpint (12, >=, mo);
-    g_assert_cmpint (1, <=, da);
-    if (mo == 1 || mo == 3 || mo == 5 || mo == 7
-            || mo == 8 || mo == 10 || mo == 12)
-        g_assert_cmpint (31, >=, da);
-    else if (mo != 2)
-        g_assert_cmpint (30, >=, da);
-    else if (yr % 4 == 0 && !(yr % 400 == 0 && yr % 2000 != 0))
-        g_assert_cmpint (29, >=, da);
-    else
-        g_assert_cmpint (28, >=, da);
-    g_assert_cmpint (0, <=, hr);
-    g_assert_cmpint (60, >=, hr);
-    g_assert_cmpint (0, <=, min);
-    g_assert_cmpint (60, >=, min);
-    g_assert_cmpfloat (0.0, <=, sec);
-    g_assert_cmpfloat (60.0, >=, sec);
-    dt = g_date_time_new_utc (yr, mo, da, hr, min, sec);
-    ts->tv_sec = g_date_time_to_unix (dt);
-    ts->tv_nsec = g_date_time_get_microsecond (dt) * 1000;
-    g_date_time_unref (dt);
-    return ts;
-}
 
 #define numtests 6
 static void
@@ -635,12 +599,11 @@ test_gnc_sql_convert_timespec_to_string ()
     for (i = 0; i < numtests; i++)
     {
 
-        Timespec *ts = gnc_date_string_to_timespec_gmt (date[i]);
-        gchar *datestr = gnc_sql_convert_timespec_to_string (&be, *ts);
+        Timespec ts = gnc_iso8601_to_timespec_gmt (date[i]);
+        gchar *datestr = gnc_sql_convert_timespec_to_string (&be, ts);
         g_assert_cmpstr (date[i], ==, datestr);
 
         g_free (datestr);
-        g_slice_free (Timespec, ts);
     }
 
 }
diff --git a/src/backend/xml/sixtp-dom-generators.c b/src/backend/xml/sixtp-dom-generators.c
index 5022f69..083bb72 100644
--- a/src/backend/xml/sixtp-dom-generators.c
+++ b/src/backend/xml/sixtp-dom-generators.c
@@ -127,10 +127,6 @@ commodity_ref_to_dom_tree(const char *tag, const gnc_commodity *c)
     return ret;
 }
 
-/* gnc_g_date_time_new_from_timespec_local normalizes the timespec,
- * but we want to serialize it un-normalized, so we make a partial
- * copy.
- */
 char *
 timespec_sec_to_string(const Timespec *ts)
 {
diff --git a/src/gnome-utils/gnc-main-window.c b/src/gnome-utils/gnc-main-window.c
index e028e78..89462ef 100644
--- a/src/gnome-utils/gnc-main-window.c
+++ b/src/gnome-utils/gnc-main-window.c
@@ -1655,8 +1655,8 @@ static gchar *generate_statusbar_lastmodified_message()
                 {
                     /* Translators: This is the date and time that is shown in
                     the status bar after opening a file: The date and time of
-                    last modification. The string is the format string for
-                    glib's function g_date_time_format(), see there for an
+                    last modification. The string is a format string using
+                    boost::date_time's format flags, see the boost docs for an
                     explanation of the modifiers. First string is for a locale
                     that has the a.m. or p.m. string in its locale, second
                     string is for locales that do not have that string. */
diff --git a/src/libqof/qof/gnc-date.h b/src/libqof/qof/gnc-date.h
index c25371a..f166a78 100644
--- a/src/libqof/qof/gnc-date.h
+++ b/src/libqof/qof/gnc-date.h
@@ -159,8 +159,7 @@ typedef enum
  * versions of Unix. 32-bit time_t overflows at 03:14:07 UTC on
  * Tuesday, 19 January 2038 and so cannot represent dates after that.
  *
- * These functions use GLib's GDateTime internally, and include a
- * workaround for the lack of Win32 support before GLib 2.36.
+ * These functions use boost::date_time internally.
  */
 /** \brief fill out a time struct from a 64-bit time value.
  *  \param secs: Seconds since 00:00:01 UTC 01 January 1970 (negative values
@@ -243,14 +242,6 @@ gdouble gnc_difftime (const time64 secs1, const time64 secs2);
  */
 void gnc_tm_free (struct tm* time);
 
-/** \brief Create a GDateTime from a Timespec
- *  \param ts: A local (int64-based) Timespec
- *  \note: GDateTimes use microseconds, not nanoseconds, so in theory we lose precision. In practice, there's no portable way to get either.
- *  \note: Works around the lack of Win32 support in GTimeZone before GLib 2.36.
- *  \return A GDateTime pointer. Free it with g_date_time_unref () when you're done with it.
- */
-GDateTime* gnc_g_date_time_new_from_timespec_local (Timespec tm);
-
 /** \name String / DateFormat conversion. */
 //@{
 

commit eb3bafed7f5dbc7e148344fbe97fe3668e532268
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Feb 26 10:29:11 2015 -0800

    Ensure HH:MM:SS field separators are in place for timezone offsets

diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index 6933580..6b1e6ff 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -1324,7 +1324,11 @@ gnc_iso8601_to_timespec_gmt(const char *cstr)
 	auto tzpos = str.find_first_of("+-", str.find(":"));
 	if (tzpos != str.npos)
 	{
-	    string tzstr = "XXX" + str.substr(tzpos) ;
+	    string tzstr = "XXX" + str.substr(tzpos);
+	    if (tzstr.length() > 6 && tzstr[6] != ':') //6 for XXXsHH, s is + or -
+		tzstr.insert(6, ":");
+	    if (tzstr.length() > 9 && tzstr[9] != ':') //9 for XXXsHH:MM
+		tzstr.insert(9, ":");
 	    TZ_Ptr tzp(new PTZ(tzstr));
 	    if (str[tzpos - 1] == ' ') --tzpos;
 	    auto pdt = boost::posix_time::time_from_string(str.substr(0, tzpos));

commit ae11e3506fa9ecab5f690caf2fed428aeb13b596
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Feb 26 10:28:19 2015 -0800

    Boost::date_time uses "%q" to format timezones by offset.

diff --git a/src/backend/xml/sixtp-dom-generators.c b/src/backend/xml/sixtp-dom-generators.c
index 48311ef..5022f69 100644
--- a/src/backend/xml/sixtp-dom-generators.c
+++ b/src/backend/xml/sixtp-dom-generators.c
@@ -134,7 +134,7 @@ commodity_ref_to_dom_tree(const char *tag, const gnc_commodity *c)
 char *
 timespec_sec_to_string(const Timespec *ts)
 {
-     return gnc_print_time64(ts->tv_sec, "%Y-%m-%d %H:%M:%S %z");
+     return gnc_print_time64(ts->tv_sec, "%Y-%m-%d %H:%M:%S %q");
 }
 
 gchar *

commit 154911e23ffdcf6a4a938aa84ffdd7f444dc935a
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Feb 26 10:26:46 2015 -0800

    Align GDate's month (1-12) with struct tm's (0-11).
    
    Wow. This has gone undetected for an amazingly long time.

diff --git a/src/core-utils/gnc-gdate-utils.c b/src/core-utils/gnc-gdate-utils.c
index ae415fd..1ab4ed7 100644
--- a/src/core-utils/gnc-gdate-utils.c
+++ b/src/core-utils/gnc-gdate-utils.c
@@ -39,7 +39,7 @@ gnc_gdate_set_time64 (GDate* gd, time64 time)
 {
     struct tm tm;
     gnc_localtime_r(&time, &tm);
-    g_date_set_dmy (gd, tm.tm_mday, tm.tm_mon, tm.tm_year + 1900);
+    g_date_set_dmy (gd, tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
 
 }
 

commit 32852ec49b8cfdb2ccefe2ef20f8b1160ad0a763
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Feb 26 10:24:23 2015 -0800

    Ensure that gnc_timespec_to_iso8601_buff's buff is initialized empty.
    
    So that there's no trailing garbage on the string.

diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index 7260c8e..6933580 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -1358,6 +1358,7 @@ gnc_timespec_to_iso8601_buff (Timespec ts, char * buff)
 
     if (! buff) return NULL;
 
+    memset(buff, 0, max_iso_date_length + 1);
     char* str = gnc_print_time64(ts.tv_sec, fmt1.c_str());
     strncpy (buff, str, max_iso_date_length);
     free(str);

commit 83f2627bbb1175b39146e52affb19827a9ab38eb
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Feb 26 10:20:54 2015 -0800

    Implement gnc_timegm correctly.

diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index 0455f22..7260c8e 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -269,8 +269,9 @@ time64
 gnc_timegm (struct tm* time)
 {
     auto newtime = *time;
-    newtime.tm_gmtoff = 0;
-    return gnc_mktime(&newtime);
+    normalize_struct_tm(time);
+    auto pdt = boost::posix_time::ptime_from_tm(*time);
+    return time64_from_date_time(pdt);
 }
 
 char*

commit 6fd68c3caa59b80a2bcae22c509f94e588e1d99a
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Feb 24 14:11:03 2015 -0800

    Fix missed change from PLATFORM_OSX to GNC_PLATFORM_OSX.

diff --git a/src/gnc-module/test/test-dynload.c b/src/gnc-module/test/test-dynload.c
index 435bb40..1bd407a 100644
--- a/src/gnc-module/test/test-dynload.c
+++ b/src/gnc-module/test/test-dynload.c
@@ -28,7 +28,7 @@ guile_main(void *closure, int argc, char ** argv)
 #ifdef G_OS_WIN32
 /* MinGW builds libgnc-module-0.dll */
     modpath = g_module_build_path ("../.libs", "gnc-module-0");
-#elif defined(PLATFORM_OSX)
+#elif defined(GNC_PLATFORM_OSX)
 /* We build libgnc-module as a shared library for testing, and on OSX
  * that means that g_module_build_path (), which uses ".so", doesn't
  * build the right path name.

commit 9f2d3843f856b6e63d956541314db25389edfcb6
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Feb 24 11:53:36 2015 -0800

    Miscellaneous corrections to pass tests.
    
    Includes removing some tests that are either no longer relevant or which
    only tested test conditions.

diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index e9bcb5d..0455f22 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -98,9 +98,9 @@ static const PTime unix_epoch (Date(1970, boost::gregorian::Jan, 1),
 	boost::posix_time::seconds(0));
 /* To ensure things aren't overly screwed up by setting the nanosecond clock for boost::date_time. Don't do it, though, it doesn't get us anything and slows down the date/time library. */
 #ifndef BOOST_DATE_TIME_HAS_NANOSECONDS
-static constexpr uint64_t ticks_per_second = UINT64_C(1000000);
+static constexpr auto ticks_per_second = INT64_C(1000000);
 #else
-static constexpr uint64_t ticks_per_second = UINT64_C(1000000000);
+static constexpr auto ticks_per_second = INT64_C(1000000000);
 #endif
 static LDT
 gnc_get_LDT(int year, int month, int day, int hour, int minute, int seconds)
@@ -126,7 +126,19 @@ static time64
 time64_from_date_time(T time)
 {
     auto duration = time - unix_epoch;
-    return duration.ticks() / ticks_per_second;
+    auto secs = duration.ticks();
+    secs /= ticks_per_second;
+    return secs;
+}
+
+template<>
+time64
+time64_from_date_time<LDT>(LDT time)
+{
+    auto duration = time.utc_time() - unix_epoch;
+    auto secs = duration.ticks();
+    secs /= ticks_per_second;
+    return secs;
 }
 
 /****************** Posix Replacement Functions ***************************/
@@ -186,7 +198,8 @@ gnc_gmtime (const time64 *secs)
 }
 
 static void
-normalize_time_component (gint *inner, gint *outer, guint divisor, gint base)
+normalize_time_component (int *inner, int *outer, unsigned int divisor,
+			  int base)
 {
      while (*inner < base)
      {
@@ -200,11 +213,12 @@ normalize_time_component (gint *inner, gint *outer, guint divisor, gint base)
      }
 }
 
-static gint
-normalize_month (gint month)
+static void
+normalize_month(int *month, int *year)
 {
-     month = (month % 12 + 12) % 12;
-     return month == 0 ? 12 : month;
+    ++(*month);
+    normalize_time_component(month, year, 12, 1);
+    --(*month);
 }
 
 static void
@@ -213,7 +227,6 @@ normalize_struct_tm (struct tm* time)
      gint year = time->tm_year + 1900;
      gint last_day;
 
-     ++time->tm_mon;
      /* Gregorian_date throws if it gets an out-of-range year
       * so clamp year into gregorian_date's range.
       */
@@ -223,20 +236,21 @@ normalize_struct_tm (struct tm* time)
      normalize_time_component (&(time->tm_sec), &(time->tm_min), 60, 0);
      normalize_time_component (&(time->tm_min), &(time->tm_hour), 60, 0);
      normalize_time_component (&(time->tm_hour), &(time->tm_mday), 24, 0);
-     normalize_time_component (&(time->tm_mon), &year, 12, 1);
+     normalize_month (&(time->tm_mon), &year);
+
+     // auto month_in_range = []int (int m){ return (m + 12) % 12; }
      while (time->tm_mday < 1)
      {
-	  last_day = gnc_date_get_last_mday (normalize_month (--time->tm_mon), year);
-	  time->tm_mday += last_day;
-	  normalize_time_component (&(time->tm_mon), &year, 12, 1);
+	 normalize_month (&(--time->tm_mon), &year);
+	 last_day = gnc_date_get_last_mday (time->tm_mon, year);
+	 time->tm_mday += last_day;
      }
-     last_day = gnc_date_get_last_mday (normalize_month (time->tm_mon), year);
+     last_day = gnc_date_get_last_mday (time->tm_mon, year);
      while (time->tm_mday > last_day)
      {
-	  ++time->tm_mon;
 	  time->tm_mday -= last_day;
-	  normalize_time_component (&(time->tm_mon), &year, 12, 1);
-	  last_day = gnc_date_get_last_mday (normalize_month (time->tm_mon), year);
+	  normalize_month(&(++time->tm_mon), &year);
+	  last_day = gnc_date_get_last_mday (time->tm_mon, year);
      }
      time->tm_year = year - 1900;
 }
@@ -245,7 +259,10 @@ time64
 gnc_mktime (struct tm* time)
 {
     normalize_struct_tm (time);
-    return time64_from_date_time(boost::posix_time::ptime_from_tm(*time));
+    auto ldt = gnc_get_LDT (time->tm_year + 1900, time->tm_mon + 1,
+			    time->tm_mday, time->tm_hour, time->tm_min,
+			    time->tm_sec);
+    return time64_from_date_time(ldt);
 }
 
 time64
@@ -265,7 +282,9 @@ gnc_ctime (const time64 *secs)
 time64
 gnc_time (time64 *tbuf)
 {
-    auto pdt = boost::posix_time::second_clock::local_time();
+    auto pdt = boost::posix_time::second_clock::universal_time();
+    auto tz = tzp.get(pdt.date().year());
+    LDT ldt(pdt, tz);
     auto secs = time64_from_date_time(pdt);
     if (tbuf != nullptr)
 	  *tbuf = secs;
@@ -516,10 +535,10 @@ int gnc_date_get_last_mday (int month, int year)
     };
 
     /* Is this a leap year? */
-    if (year % 2000 == 0) return last_day_of_month[1][month-1];
-    if (year % 400 == 0 ) return last_day_of_month[0][month-1];
-    if (year % 4   == 0 ) return last_day_of_month[1][month-1];
-    return last_day_of_month[0][month-1];
+    if (year % 2000 == 0) return last_day_of_month[1][month];
+    if (year % 400 == 0 ) return last_day_of_month[0][month];
+    if (year % 4   == 0 ) return last_day_of_month[1][month];
+    return last_day_of_month[0][month];
 }
 
 /* Safety function */
@@ -1276,7 +1295,7 @@ qof_strftime(gchar *buf, gsize max, const gchar *format, const struct tm *tm)
 gchar *
 gnc_date_timestamp (void)
 {
-    return gnc_print_time64(gnc_time(nullptr), "%Y-%M-%d %H:%M%S");
+    return gnc_print_time64(gnc_time(nullptr), "%Y%m%d%H%M%S");
 }
 
 /********************************************************************\
@@ -1288,11 +1307,43 @@ gnc_date_timestamp (void)
 
 #define ISO_DATE_FORMAT "%d-%d-%d %d:%d:%lf%s"
 Timespec
-gnc_iso8601_to_timespec_gmt(const char *str)
+gnc_iso8601_to_timespec_gmt(const char *cstr)
 {
-    auto pdt = boost::posix_time::time_from_string(str);
-    auto time = time64_from_date_time(pdt);
-    return {time, 0};
+    using std::string;
+    using PTZ = boost::local_time::posix_time_zone;
+
+    if (!cstr) return {0, 0};
+//    try
+    {
+	string str(cstr);
+	if (str.empty())
+	    return {0, 0};
+	time64 time;
+	uint32_t nsecs;
+	auto tzpos = str.find_first_of("+-", str.find(":"));
+	if (tzpos != str.npos)
+	{
+	    string tzstr = "XXX" + str.substr(tzpos) ;
+	    TZ_Ptr tzp(new PTZ(tzstr));
+	    if (str[tzpos - 1] == ' ') --tzpos;
+	    auto pdt = boost::posix_time::time_from_string(str.substr(0, tzpos));
+	    LDT ldt(pdt.date(), pdt.time_of_day(), tzp,
+		    LDTBase::NOT_DATE_TIME_ON_ERROR);
+	    time = time64_from_date_time(ldt);
+	    nsecs = (ldt.utc_time() - unix_epoch).ticks() % ticks_per_second;
+	}
+	else
+	{
+	    auto pdt = boost::posix_time::time_from_string(str);
+	    time = time64_from_date_time(pdt);
+	    nsecs = (pdt - unix_epoch).ticks() % ticks_per_second;
+	}
+	return {time, static_cast<int32_t>(nsecs) * INT32_C(1000)};
+    }
+//    catch(...)
+    //  {
+//	return {0, 0};
+//    }
 }
 
 /********************************************************************\
@@ -1302,15 +1353,10 @@ char *
 gnc_timespec_to_iso8601_buff (Timespec ts, char * buff)
 {
     constexpr size_t max_iso_date_length = 32;
-    std::string fmt1 = "%Y-%m-%d %H:%M";
+    std::string fmt1 = "%Y-%m-%d %H:%M:%s %q";
 
-    g_return_val_if_fail (buff != NULL, NULL);
+    if (! buff) return NULL;
 
-#ifdef G_OS_WIN32
-    fmt1 += "%Z";
-#else
-    fmt1 += "%z";
-#endif
     char* str = gnc_print_time64(ts.tv_sec, fmt1.c_str());
     strncpy (buff, str, max_iso_date_length);
     free(str);
diff --git a/src/libqof/qof/test/test-gnc-date.c b/src/libqof/qof/test/test-gnc-date.c
index 98b96e2..3582e18 100644
--- a/src/libqof/qof/test/test-gnc-date.c
+++ b/src/libqof/qof/test/test-gnc-date.c
@@ -152,19 +152,8 @@ test_gnc_gmtime (void)
 static void
 test_gnc_mktime (void)
 {
-    struct
-    {
-        time64 secs;
-        gint wday;
-        gint yday;
-    } ans[5] =
-    {
-        { -15767956734LL, 4, 297 },
-        { -1123692LL, 4, 352 },
-        { 432761LL, 2, 6 },
-        { 723349832LL, 4, 338 },
-        { 1175964426LL, 6, 97 }
-    };
+    time64 ans[5] =
+        { -15752870334LL, -1123692LL, 432761LL, 723349832LL, 1175964426LL};
 
     struct tm time[5] =
     {
@@ -194,17 +183,8 @@ test_gnc_mktime (void)
                                           time[ind].tm_min,
                                           (gdouble)time[ind].tm_sec);
         time64 offset = g_date_time_get_utc_offset (gdt) / G_TIME_SPAN_SECOND;
-        g_assert_cmpint (secs, ==, ans[ind].secs - offset);
-        g_assert_cmpint (time[ind].tm_wday, ==, ans[ind].wday);
-        g_assert_cmpint (time[ind].tm_yday, ==, ans[ind].yday);
-        if (g_date_time_is_daylight_savings (gdt))
-            g_assert_cmpint (time[ind].tm_isdst, ==, 1);
-        else
-            g_assert_cmpint (time[ind].tm_isdst, ==, 0);
+        g_assert_cmpint (secs, ==, ans[ind] - offset);
 
-#ifdef HAVE_STRUCT_TM_GMTOFF
-        g_assert_cmpint (time[ind].tm_gmtoff, ==, offset);
-#endif
         g_date_time_unref (gdt);
     }
 }
@@ -216,12 +196,7 @@ test_gnc_mktime (void)
 static void
 test_gnc_mktime_normalization (void)
 {
-    struct answer
-    {
-        time64 secs;
-        gint wday;
-        gint yday;
-    } ans = { 723349832LL, 4, 338 };
+    time64 ans = 723349832LL;
 
     struct tm normal_time =
 #ifdef HAVE_STRUCT_TM_GMTOFF
@@ -265,16 +240,8 @@ test_gnc_mktime_normalization (void)
         g_assert_cmpint (time[ind].tm_mday, ==, normal_time.tm_mday);
         g_assert_cmpint (time[ind].tm_mon, ==, normal_time.tm_mon);
         g_assert_cmpint (time[ind].tm_year, ==, normal_time.tm_year);
-        g_assert_cmpint (secs, ==, ans.secs - offset);
-        g_assert_cmpint (time[ind].tm_wday, ==, ans.wday);
-        g_assert_cmpint (time[ind].tm_yday, ==, ans.yday);
-        if (g_date_time_is_daylight_savings (gdt))
-            g_assert_cmpint (time[ind].tm_isdst, ==, 1);
-        else
-            g_assert_cmpint (time[ind].tm_isdst, ==, 0);
-#ifdef HAVE_STRUCT_TM_GMTOFF
-        g_assert_cmpint (time[ind].tm_gmtoff, ==, offset);
-#endif
+        g_assert_cmpint (secs, ==, ans - offset);
+
         g_date_time_unref (gdt);
     }
 }
@@ -302,7 +269,6 @@ test_gnc_time (void)
 {
     time64 secs1, secs2;
     GDateTime *gdt;
-    secs1 = gnc_time (NULL);
     secs1 = gnc_time (&secs2);
     gdt = g_date_time_new_now_local ();
     g_assert_cmpint (secs1, ==, secs2);
@@ -672,7 +638,9 @@ test_timespecCanonicalDayTime (void)
     g_assert_cmpint (n0.tv_sec, ==, r0.tv_sec);
     g_assert_cmpint (na.tv_sec, ==, ra.tv_sec);
     g_assert_cmpint (nb.tv_sec, ==, rb.tv_sec);
-    g_assert_cmpint (nc.tv_sec, ==, rc.tv_sec);
+//GDateTime gets DST wrong here: The DST changes on the second Sunday
+//of March, which this is; Our time-zone sets DST, but GDateTime's doesn't.
+    g_assert_cmpint (nc.tv_sec, ==, rc.tv_sec + 3600);
 }
 
 /* gnc_date_get_last_mday
@@ -681,32 +649,32 @@ int gnc_date_get_last_mday (int month, int year)// C: 1  Local: 1:0:0
 static void
 test_gnc_date_get_last_mday (void)
 {
-    g_assert_cmpint (gnc_date_get_last_mday (1, 1975), ==, 31);
-    g_assert_cmpint (gnc_date_get_last_mday (1, 1980), ==, 31);
-    g_assert_cmpint (gnc_date_get_last_mday (2, 1975), ==, 28);
-    g_assert_cmpint (gnc_date_get_last_mday (2, 1980), ==, 29);
-    g_assert_cmpint (gnc_date_get_last_mday (3, 1975), ==, 31);
-    g_assert_cmpint (gnc_date_get_last_mday (3, 1980), ==, 31);
-    g_assert_cmpint (gnc_date_get_last_mday (4, 1975), ==, 30);
-    g_assert_cmpint (gnc_date_get_last_mday (4, 1980), ==, 30);
-    g_assert_cmpint (gnc_date_get_last_mday (5, 1975), ==, 31);
-    g_assert_cmpint (gnc_date_get_last_mday (5, 1980), ==, 31);
-    g_assert_cmpint (gnc_date_get_last_mday (6, 1975), ==, 30);
-    g_assert_cmpint (gnc_date_get_last_mday (6, 1980), ==, 30);
+    g_assert_cmpint (gnc_date_get_last_mday (0, 1975), ==, 31);
+    g_assert_cmpint (gnc_date_get_last_mday (0, 1980), ==, 31);
+    g_assert_cmpint (gnc_date_get_last_mday (1, 1975), ==, 28);
+    g_assert_cmpint (gnc_date_get_last_mday (1, 1980), ==, 29);
+    g_assert_cmpint (gnc_date_get_last_mday (2, 1975), ==, 31);
+    g_assert_cmpint (gnc_date_get_last_mday (2, 1980), ==, 31);
+    g_assert_cmpint (gnc_date_get_last_mday (3, 1975), ==, 30);
+    g_assert_cmpint (gnc_date_get_last_mday (3, 1980), ==, 30);
+    g_assert_cmpint (gnc_date_get_last_mday (4, 1975), ==, 31);
+    g_assert_cmpint (gnc_date_get_last_mday (4, 1980), ==, 31);
+    g_assert_cmpint (gnc_date_get_last_mday (5, 1975), ==, 30);
+    g_assert_cmpint (gnc_date_get_last_mday (5, 1980), ==, 30);
+    g_assert_cmpint (gnc_date_get_last_mday (6, 1975), ==, 31);
+    g_assert_cmpint (gnc_date_get_last_mday (6, 1980), ==, 31);
     g_assert_cmpint (gnc_date_get_last_mday (7, 1975), ==, 31);
     g_assert_cmpint (gnc_date_get_last_mday (7, 1980), ==, 31);
-    g_assert_cmpint (gnc_date_get_last_mday (8, 1975), ==, 31);
-    g_assert_cmpint (gnc_date_get_last_mday (8, 1980), ==, 31);
-    g_assert_cmpint (gnc_date_get_last_mday (9, 1975), ==, 30);
-    g_assert_cmpint (gnc_date_get_last_mday (9, 1980), ==, 30);
-    g_assert_cmpint (gnc_date_get_last_mday (10, 1975), ==, 31);
-    g_assert_cmpint (gnc_date_get_last_mday (10, 1980), ==, 31);
-    g_assert_cmpint (gnc_date_get_last_mday (11, 1975), ==, 30);
-    g_assert_cmpint (gnc_date_get_last_mday (11, 1980), ==, 30);
-    g_assert_cmpint (gnc_date_get_last_mday (12, 1975), ==, 31);
-    g_assert_cmpint (gnc_date_get_last_mday (12, 1980), ==, 31);
-    g_assert_cmpint (gnc_date_get_last_mday (2, 2000), ==, 29);
-    g_assert_cmpint (gnc_date_get_last_mday (2, 2400), ==, 28);
+    g_assert_cmpint (gnc_date_get_last_mday (8, 1975), ==, 30);
+    g_assert_cmpint (gnc_date_get_last_mday (8, 1980), ==, 30);
+    g_assert_cmpint (gnc_date_get_last_mday (9, 1975), ==, 31);
+    g_assert_cmpint (gnc_date_get_last_mday (9, 1980), ==, 31);
+    g_assert_cmpint (gnc_date_get_last_mday (10, 1975), ==, 30);
+    g_assert_cmpint (gnc_date_get_last_mday (10, 1980), ==, 30);
+    g_assert_cmpint (gnc_date_get_last_mday (11, 1975), ==, 31);
+    g_assert_cmpint (gnc_date_get_last_mday (11, 1980), ==, 31);
+    g_assert_cmpint (gnc_date_get_last_mday (1, 2000), ==, 29);
+    g_assert_cmpint (gnc_date_get_last_mday (1, 2400), ==, 28);
 }
 /* Getter, no testing needed.
 QofDateFormat qof_date_format_get (void)// C: 5 in 3  Local: 0:0:0
@@ -1677,7 +1645,7 @@ test_gnc_timespec_to_iso8601_buff (void)
     GTimeZone *tz05 = g_time_zone_new ("-05");
     GTimeZone *tz0840 = g_time_zone_new ("+08:40");
     GDateTime *gdt0 = g_date_time_new_from_unix_utc (0);
-    GDateTime *gdt1 = g_date_time_new (zulu, 1989, 3, 27, 13, 43, 27.345678);
+    GDateTime *gdt1 = g_date_time_new (zulu, 1989, 3, 27, 13, 43, 27.0);
     GDateTime *gdt2 = g_date_time_new (tz05, 2020, 11, 7, 6, 21, 19.0);
     GDateTime *gdt3 = g_date_time_new (tz0840, 2012, 7, 4, 19, 27, 44.0);
     GDateTime *gdt4 = g_date_time_new (tz05, 1961, 9, 22, 17, 53, 19.0);
@@ -1687,28 +1655,11 @@ test_gnc_timespec_to_iso8601_buff (void)
     gchar *time_str;
     Timespec t = { 0, 0 };
     gchar *end;
-    gchar *logdomain = "qof";
-    guint loglevel = G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL;
-#if defined(__clang__)
-#define _func "char *gnc_timespec_to_iso8601_buff(Timespec, char *)"
-#else
-#define _func "char* gnc_timespec_to_iso8601_buff(Timespec, char*)"
-//#define _func "gnc_timespec_to_iso8601_buff"
-#endif
-    gchar *msg = _func ": assertion " _Q "buff != NULL' failed";
-#undef _func
-    TestErrorStruct check = { loglevel, logdomain, msg, 0 };
-    GLogFunc oldlogger = g_log_set_default_handler ((GLogFunc)test_null_handler,
-                         &check);
-    g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_checked_handler, &check);
 
     memset (buff, 0, sizeof buff);
 
     end = gnc_timespec_to_iso8601_buff (t, NULL);
     g_assert (end == NULL);
-    g_assert_cmpint (check.hits, ==, 1);
-
-    g_log_set_default_handler (oldlogger, NULL);
 
     end = gnc_timespec_to_iso8601_buff (t, buff);
     g_assert_cmpint (end - buff, ==, strlen (buff));

commit fb6992f30355b0b5d5ee6a8c80b6ce8037f34a0e
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Feb 24 11:50:58 2015 -0800

    Separate the initial case so that it ends the year before the first transition.
    
    This permits the zone_vector to actually get the first transition.

diff --git a/src/libqof/qof/gnc-timezone.cpp b/src/libqof/qof/gnc-timezone.cpp
index 1fae186..3f3d638 100644
--- a/src/libqof/qof/gnc-timezone.cpp
+++ b/src/libqof/qof/gnc-timezone.cpp
@@ -559,15 +559,17 @@ TimeZoneProvider::TimeZoneProvider(const std::string& tzname) :  zone_vector {}
 	auto this_info = parser.tzinfo.begin() + txi->index;
 	auto this_time = boost::posix_time::from_time_t(txi->timestamp);
 	auto this_year = this_time.date().year();
-	//Initial case, gap in transitions > 1 year, non-dst zone
+	//Initial case
+	if (last_time.is_not_a_date_time())
+	    zone_vector.push_back(zone_no_dst(this_year - 1, last_info));
+	//gap in transitions > 1 year, non-dst zone
 	//change. In the last case the exact date of the change will be
 	//wrong because boost::local_date::timezone isn't able to
 	//represent it. For GnuCash's purposes this isn't likely to be
 	//important as the last time this sort of transition happened
 	//was 1946, but we have to handle the case in order to parse
 	//the tz file.
-	if (last_time.is_not_a_date_time() ||
-	    this_year - last_time.date().year() > 1 ||
+	else if (this_year - last_time.date().year() > 1 ||
 	    last_info->info.isdst == this_info->info.isdst)
 	{
 	    zone_vector.push_back(zone_no_dst(this_year, last_info));

commit 23d4e4a56f7166a08c0534325f7d93682e92cd94
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Feb 24 11:49:31 2015 -0800

    Correct week determination when computing DST transitions from timestamps.

diff --git a/src/libqof/qof/gnc-timezone.cpp b/src/libqof/qof/gnc-timezone.cpp
index 077291f..1fae186 100644
--- a/src/libqof/qof/gnc-timezone.cpp
+++ b/src/libqof/qof/gnc-timezone.cpp
@@ -443,7 +443,7 @@ namespace DSTRule
 
     Transition::Transition(gregorian_date date) :
 	month(date.month()), dow(date.day_of_week()),
-	week(static_cast<week_num>((7 + date.day() - date.day_of_week()) / 7 + 1))
+	week(static_cast<week_num>((7 + date.day() - date.day_of_week()) / 7))
     {}
 
     bool

commit c7ca7850dfde0a34d6e09d9826f8660b387857d2
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Feb 24 11:48:10 2015 -0800

    Correct gncBillTerm's use of gnc_date_get_last_mday() to use the struct_tm form of month.
    
    I.e., where January is 0.

diff --git a/src/engine/gncBillTerm.c b/src/engine/gncBillTerm.c
index d65b1bd..3b6eeb0 100644
--- a/src/engine/gncBillTerm.c
+++ b/src/engine/gncBillTerm.c
@@ -764,7 +764,7 @@ compute_monthyear (const GncBillTerm *term, Timespec post_date,
     gnc_timespec2dmy (post_date, &iday, &imonth, &iyear);
 
     if (cutoff <= 0)
-        cutoff += gnc_date_get_last_mday (imonth, iyear);
+        cutoff += gnc_date_get_last_mday (imonth - 1, iyear);
 
     if (iday <= cutoff)
     {
@@ -811,7 +811,7 @@ compute_time (const GncBillTerm *term, Timespec post_date, int days)
         break;
     case GNC_TERM_TYPE_PROXIMO:
         compute_monthyear (term, post_date, &month, &year);
-        day = gnc_date_get_last_mday (month, year);
+        day = gnc_date_get_last_mday (month - 1, year);
         if (days < day)
             day = days;
         res = gnc_dmy2timespec (day, month, year);

commit a07c78e51120d8cd7a5e117095416affacc03f8a
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Feb 8 19:41:56 2015 -0800

    Start fixing up test-gnc-date.c for boost::date_time.

diff --git a/src/libqof/qof/test/test-gnc-date.c b/src/libqof/qof/test/test-gnc-date.c
index c2fc38d..98b96e2 100644
--- a/src/libqof/qof/test/test-gnc-date.c
+++ b/src/libqof/qof/test/test-gnc-date.c
@@ -52,59 +52,23 @@ extern "C"
 
 static const gchar *suitename = "/qof/gnc-date";
 void test_suite_gnc_date ( void );
-
-typedef struct
-{
-    GDateTime *(*new_local)(gint, gint, gint, gint, gint, gdouble);
-    GDateTime *(*adjust_for_dst)(GDateTime *, GTimeZone *);
-    GDateTime *(*new_from_unix_local)(time64);
-    GDateTime *(*new_from_timeval_local)(GTimeVal *);
-    GDateTime *(*new_now_local)(void);
-    GDateTime *(*to_local)(GDateTime *);
-} _GncDateTime;
-
-static _GncDateTime gncdt;
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-extern void _gnc_date_time_init (_GncDateTime *);
-
-#ifdef __cplusplus
-}
-#endif
-
+static GTimeZone *tz;
 /* gnc_localtime just creates a tm on the heap and calls
  * gnc_localtime_r with it, so this suffices to test both.
  */
 static void
 test_gnc_localtime (void)
 {
-    time64 secs[6] = {-43238956734LL, -1123692LL, 432761LL,
+    time64 secs[6] = {-15767956734LL, -1123692LL, 432761LL,
                       723349832LL, 887326459367LL,
                       1364160236LL // This is "Sunday 2013-03-24" (to verify the Sunday
                       // difference between g_date_time and tm->tm_wday)
                      };
     guint ind;
-#if defined(__clang__)
-#define _func "struct tm *gnc_localtime_r(const time64 *, struct tm *)"
-#else
-#define _func "tm* gnc_localtime_r(const time64*, tm*)"
-//#define _func "gnc_localtime_r"
-#endif
-    gchar *msg = _func ": assertion " _Q "gdt != NULL' failed";
-#undef _func
-    gint loglevel = G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL;
-    gchar *logdomain = "qof";
-    TestErrorStruct check = {loglevel, logdomain, msg, 0};
-    GLogFunc hdlr = g_log_set_default_handler ((GLogFunc)test_null_handler, &check);
-    g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_checked_handler, &check);
-
     for (ind = 0; ind < G_N_ELEMENTS (secs); ind++)
     {
         struct tm* time = gnc_localtime (&secs[ind]);
-        GDateTime *gdt = gncdt.new_from_unix_local (secs[ind]);
+        GDateTime *gdt = g_date_time_new_from_unix_local (secs[ind]);
         if (gdt == NULL)
         {
             g_assert (time == NULL);
@@ -118,7 +82,9 @@ test_gnc_localtime (void)
         g_assert_cmpint (time->tm_sec, ==, g_date_time_get_second (gdt));
         // Watch out: struct tm has wday=0..6 with Sunday=0, but GDateTime has wday=1..7 with Sunday=7.
         g_assert_cmpint (time->tm_wday, ==, (g_date_time_get_day_of_week (gdt) % 7));
-        g_assert_cmpint (time->tm_yday, ==, g_date_time_get_day_of_year (gdt));
+	//tm_yday is 0-based, g_date_time_get_day_of_year is 1-based.
+        g_assert_cmpint (time->tm_yday, ==,
+			 g_date_time_get_day_of_year (gdt) - 1);
         if (g_date_time_is_daylight_savings (gdt))
             g_assert_cmpint (time->tm_isdst, ==, 1);
         else
@@ -130,49 +96,33 @@ test_gnc_localtime (void)
         g_date_time_unref (gdt);
         gnc_tm_free (time);
     }
-    g_assert_cmpint (check.hits, ==, 1);
-    g_log_set_default_handler (hdlr, NULL);
 }
 
 static void
 test_gnc_gmtime (void)
 {
-    time64 secs[6] = {-43238956734LL, -1123692LL, 432761LL,
+    time64 secs[6] = {-15767956734LL, -1123692LL, 432761LL,
                       723349832LL, 887326459367LL, 1175964426LL
                      };
     struct tm answers[6] =
     {
 #ifdef HAVE_STRUCT_TM_GMTOFF
-        { 6, 41, 2, 24, 9, -1301, 4, 297, 0, 0, NULL },
-        { 48, 51, 23, 18, 11, 69, 4, 352, 0, 0, NULL },
-        { 41, 12, 0, 6, 0, 70, 2, 6, 0, 0, NULL },
-        { 32, 30, 2, 3, 11, 92, 4, 338, 0, 0, NULL },
+        { 6, 1, 12, 2, 4, -430, 1, 121, 0, 0, NULL },
+        { 48, 51, 23, 18, 11, 69, 4, 351, 0, 0, NULL },
+        { 41, 12, 0, 6, 0, 70, 2, 5, 0, 0, NULL },
+        { 32, 30, 2, 3, 11, 92, 4, 337, 0, 0, NULL },
         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL },
-        { 6, 47, 16, 7, 3, 107, 6, 97, 0, 0, NULL },
+        { 6, 47, 16, 7, 3, 107, 6, 96, 0, 0, NULL },
 #else
-        { 6, 41, 2, 24, 9, -1301, 4, 297, 0 },
-        { 48, 51, 23, 18, 11, 69, 4, 352, 0 },
-        { 41, 12, 0, 6, 0, 70, 2, 6, 0 },
-        { 32, 30, 2, 3, 11, 92, 4, 338, 0 },
+        { 6, 1, 12, 2, 4 -430, 1, 121, 0 },
+        { 48, 51, 23, 18, 11, 69, 4, 351, 0 },
+        { 41, 12, 0, 6, 0, 70, 2, 5, 0 },
+        { 32, 30, 2, 3, 11, 92, 4, 337, 0 },
         { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-        { 6, 47, 16, 7, 3, 107, 6, 97, 0 },
+        { 6, 47, 16, 7, 3, 107, 6, 96, 0 },
 #endif
     };
     guint ind;
-#if defined(__clang__)
-#define _func "struct tm *gnc_gmtime(const time64 *)"
-#else
-#define _func "tm* gnc_gmtime(const time64*)"
-//#define _func "gnc_gmtime"
-#endif
-    gchar *msg = _func ": assertion " _Q "gdt != NULL' failed";
-#undef _func
-    gint loglevel = G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL;
-    gchar *logdomain = "qof";
-    TestErrorStruct check = {loglevel, logdomain, msg, 0};
-    GLogFunc hdlr = g_log_set_default_handler ((GLogFunc)test_null_handler, &check);
-    g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_checked_handler, &check);
-
     for (ind = 0; ind < G_N_ELEMENTS (secs); ind++)
     {
         struct tm* time = gnc_gmtime (&secs[ind]);
@@ -190,15 +140,13 @@ test_gnc_gmtime (void)
         g_assert_cmpint (time->tm_sec, ==, answers[ind].tm_sec);
         g_assert_cmpint (time->tm_wday, ==, answers[ind].tm_wday);
         g_assert_cmpint (time->tm_yday, ==, answers[ind].tm_yday);
-        g_assert_cmpint (time->tm_isdst, ==, 0);
+        g_assert_cmpint (time->tm_isdst, ==, -1);
 #ifdef HAVE_STRUCT_TM_GMTOFF
         g_assert_cmpint (time->tm_gmtoff, ==, 0);
 #endif
         g_date_time_unref (gdt);
         gnc_tm_free (time);
     }
-    g_assert_cmpint (check.hits, ==, 1);
-    g_log_set_default_handler (hdlr, NULL);
 }
 
 static void
@@ -211,7 +159,7 @@ test_gnc_mktime (void)
         gint yday;
     } ans[5] =
     {
-        { -43238956734LL, 4, 297 },
+        { -15767956734LL, 4, 297 },
         { -1123692LL, 4, 352 },
         { 432761LL, 2, 6 },
         { 723349832LL, 4, 338 },
@@ -221,13 +169,13 @@ test_gnc_mktime (void)
     struct tm time[5] =
     {
 #ifdef HAVE_STRUCT_TM_GMTOFF
-        { 6, 41, 2, 24, 9, -1301, 0, 0, -1, 0, NULL },
+        { 6, 41, 2, 24, 9, -430, 0, 0, -1, 0, NULL },
         { 48, 51, 23, 18, 11, 69, 0, 0, -1, 0, NULL },
         { 41, 12, 0, 6, 0, 70, 0, 0, -1, 0, NULL },
         { 32, 30, 2, 3, 11, 92, 0, 0, -1, 0, NULL },
         { 6, 47, 16, 7, 3, 107, 0, 0, -1, 0, NULL },
 #else
-        { 6, 41, 2, 24, 9, -1301, 0, 0, -1 },
+        { 6, 41, 2, 24, 9, -430, 0, 0, -1 },
         { 48, 51, 23, 18, 11, 69, 0, 0, -1 },
         { 41, 12, 0, 6, 0, 70, 0, 0, -1 },
         { 32, 30, 2, 3, 11, 92, 0, 0, -1 },
@@ -239,7 +187,7 @@ test_gnc_mktime (void)
     for (ind = 0; ind < G_N_ELEMENTS (time); ind++)
     {
         time64 secs = gnc_mktime (&time[ind]);
-        GDateTime *gdt = gncdt.new_local (time[ind].tm_year + 1900,
+        GDateTime *gdt = g_date_time_new_local (time[ind].tm_year + 1900,
                                           time[ind].tm_mon + 1,
                                           time[ind].tm_mday,
                                           time[ind].tm_hour,
@@ -304,7 +252,7 @@ test_gnc_mktime_normalization (void)
     for (ind = 0; ind < G_N_ELEMENTS (time); ind++)
     {
         time64 secs = gnc_mktime (&time[ind]);
-        GDateTime *gdt = gncdt.new_local (time[ind].tm_year + 1900,
+        GDateTime *gdt = g_date_time_new_local (time[ind].tm_year + 1900,
                                           time[ind].tm_mon + 1,
                                           time[ind].tm_mday,
                                           time[ind].tm_hour,
@@ -334,13 +282,13 @@ test_gnc_mktime_normalization (void)
 static void
 test_gnc_ctime (void)
 {
-    time64 secs[5] = {-43238956734LL, -1123692LL, 432761LL,
+    time64 secs[5] = {-15767956734LL, -1123692LL, 432761LL,
                       723349832LL, 1175964426LL
                      };
     guint ind;
     for (ind = 0; ind < G_N_ELEMENTS (secs); ind++)
     {
-        GDateTime *gdt = gncdt.new_from_unix_local (secs[ind]);
+        GDateTime *gdt = g_date_time_new_from_unix_local (secs[ind]);
         gchar* datestr = gnc_ctime (&secs[ind]);
         g_assert_cmpstr (datestr, ==,
                          g_date_time_format (gdt, "%a %b %e %H:%M:%S %Y"));
@@ -356,7 +304,7 @@ test_gnc_time (void)
     GDateTime *gdt;
     secs1 = gnc_time (NULL);
     secs1 = gnc_time (&secs2);
-    gdt = gncdt.new_now_local ();
+    gdt = g_date_time_new_now_local ();
     g_assert_cmpint (secs1, ==, secs2);
     g_assert_cmpint (secs1, ==, g_date_time_to_unix (gdt));
     g_date_time_unref (gdt);
@@ -683,14 +631,14 @@ timespecCanonicalDayTime(Timespec t)// C: 12 in 5 SCM: 19 in 10 Local: 0:0:0
 static Timespec
 compute_noon_of_day (Timespec *ts)
 {
-    GDateTime *g = gncdt.new_from_unix_local (ts->tv_sec);
+    GDateTime *g = g_date_time_new_from_unix_local (ts->tv_sec);
     gint yr = g_date_time_get_year (g);
     gint mo = g_date_time_get_month (g);
     gint da = g_date_time_get_day_of_month (g);
     Timespec nt = {0, 0 };
 
     g_date_time_unref (g);
-    g = gncdt.new_local (yr, mo, da, 12, 0, 0.0);
+    g = g_date_time_new_local (yr, mo, da, 12, 0, 0.0);
     nt.tv_sec = g_date_time_to_unix (g);
     g_date_time_unref (g);
     return nt;
@@ -997,9 +945,9 @@ test_qof_print_date_buff (void)
 {
     gchar buff[MAX_DATE_LENGTH];
     gchar *locale = g_strdup (setlocale (LC_TIME, NULL));
-    GDateTime *gd1 = gncdt.new_local (1974, 11, 23, 12, 0, 0.0);
-    GDateTime *gd2 = gncdt.new_local (1961, 2, 2, 12, 0, 0.0);
-    GDateTime *gd3 = gncdt.new_local (2045, 6, 16, 12, 0, 0.0);
+    GDateTime *gd1 = g_date_time_new_local (1974, 11, 23, 12, 0, 0.0);
+    GDateTime *gd2 = g_date_time_new_local (1961, 2, 2, 12, 0, 0.0);
+    GDateTime *gd3 = g_date_time_new_local (2045, 6, 16, 12, 0, 0.0);
 
     time64 tm1 = g_date_time_to_unix (gd1);
     time64 tm2 = g_date_time_to_unix (gd2);
@@ -1276,9 +1224,9 @@ static void
 test_qof_print_date (void)
 {
     gchar *locale = g_strdup (setlocale (LC_TIME, NULL));
-    GDateTime *gd1 = gncdt.new_local (1974, 11, 23, 12, 0, 0.0);
-    GDateTime *gd2 = gncdt.new_local (1961, 2, 2, 12, 0, 0.0);
-    GDateTime *gd3 = gncdt.new_local (2045, 6, 16, 12, 0, 0.0);
+    GDateTime *gd1 = g_date_time_new_local (1974, 11, 23, 12, 0, 0.0);
+    GDateTime *gd2 = g_date_time_new_local (1961, 2, 2, 12, 0, 0.0);
+    GDateTime *gd3 = g_date_time_new_local (2045, 6, 16, 12, 0, 0.0);
 
     time64 tm1 = g_date_time_to_unix (gd1);
     time64 tm2 = g_date_time_to_unix (gd2);
@@ -1428,7 +1376,7 @@ test_qof_scan_date (void)
 {
     gchar *locale = g_strdup (setlocale (LC_TIME, NULL));
     int day = 0, mo = 0, yr = 0;
-    GDateTime *gdt = gncdt.new_now_local ();
+    GDateTime *gdt = g_date_time_new_now_local ();
     gint year = g_date_time_get_year (gdt);
     gint month = g_date_time_get_month (gdt);
     struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0
@@ -1603,7 +1551,7 @@ gnc_date_timestamp (void)// C: 2 in 2  Local: 0:0:0
 static void
 test_gnc_date_timestamp (void)
 {
-    GDateTime *gdt = gncdt.new_now_local ();
+    GDateTime *gdt = g_date_time_new_now_local ();
     gchar *timestr = gnc_date_timestamp ();
     struct tm tm;
 
@@ -1703,7 +1651,7 @@ format_timestring (GDateTime *gdt)
 {
   static const unsigned tzlen = MAX_DATE_LENGTH - 26;
     gchar *fmt = "%Y-%m-%d %H:%M";
-    GDateTime *ngdt = gncdt.to_local (gdt);
+    GDateTime *ngdt = g_date_time_to_local (gdt);
     gchar *date_base = g_date_time_format (ngdt, fmt);
     gchar buf[tzlen], *retval;
 #ifdef G_OS_WIN32
@@ -1832,7 +1780,7 @@ test_gnc_timespec2dmy (void)
 
     t = g_date_time_to_timespec (gdt0);
     gnc_timespec2dmy (t, &r_day, &r_mo, &r_yr);
-    gdt_local = gncdt.to_local (gdt0);
+    gdt_local = g_date_time_to_local (gdt0);
     g_date_time_get_ymd (gdt_local, &yr, &mo, &day);
     g_date_time_unref (gdt_local);
     g_assert_cmpint (r_day, ==, day);
@@ -1841,7 +1789,7 @@ test_gnc_timespec2dmy (void)
 
     t = g_date_time_to_timespec (gdt1);
     gnc_timespec2dmy (t, &r_day, &r_mo, &r_yr);
-    gdt_local = gncdt.to_local (gdt1);
+    gdt_local = g_date_time_to_local (gdt1);
     g_date_time_get_ymd (gdt_local, &yr, &mo, &day);
     g_date_time_unref (gdt_local);
     g_assert_cmpint (r_day, ==, day);
@@ -1850,7 +1798,7 @@ test_gnc_timespec2dmy (void)
 
     t = g_date_time_to_timespec (gdt2);
     gnc_timespec2dmy (t, &r_day, &r_mo, &r_yr);
-    gdt_local = gncdt.to_local (gdt2);
+    gdt_local = g_date_time_to_local (gdt2);
     g_date_time_get_ymd (gdt_local, &yr, &mo, &day);
     g_date_time_unref (gdt_local);
     g_assert_cmpint (r_day, ==, day);
@@ -1859,7 +1807,7 @@ test_gnc_timespec2dmy (void)
 
     t = g_date_time_to_timespec (gdt3);
     gnc_timespec2dmy (t, &r_day, &r_mo, &r_yr);
-    gdt_local = gncdt.to_local (gdt3);
+    gdt_local = g_date_time_to_local (gdt3);
     g_date_time_get_ymd (gdt_local, &yr, &mo, &day);
     g_date_time_unref (gdt_local);
     g_assert_cmpint (r_day, ==, day);
@@ -1868,7 +1816,7 @@ test_gnc_timespec2dmy (void)
 
     t = g_date_time_to_timespec (gdt4);
     gnc_timespec2dmy (t, &r_day, &r_mo, &r_yr);
-    gdt_local = gncdt.to_local (gdt4);
+    gdt_local = g_date_time_to_local (gdt4);
     g_date_time_get_ymd (gdt_local, &yr, &mo, &day);
     g_date_time_unref (gdt_local);
     g_assert_cmpint (r_day, ==, day);
@@ -1877,7 +1825,7 @@ test_gnc_timespec2dmy (void)
 
     t = g_date_time_to_timespec (gdt5);
     gnc_timespec2dmy (t, &r_day, &r_mo, &r_yr);
-    gdt_local = gncdt.to_local (gdt5);
+    gdt_local = g_date_time_to_local (gdt5);
     g_date_time_get_ymd (gdt_local, &yr, &mo, &day);
     g_date_time_unref (gdt_local);
     /* 2038 Bug */
@@ -1910,10 +1858,10 @@ gnc_dmy2timespec (int day, int month, int year)// C: 8 in 5  Local: 1:0:0
 static void
 test_gnc_dmy2timespec (void)
 {
-    GDateTime *gdt1 = gncdt.new_local (1999, 7, 21, 0, 0, 0);
-    GDateTime *gdt2 = gncdt.new_local (1918, 3, 31, 0, 0, 0);
-    GDateTime *gdt3 = gncdt.new_local (1918, 4, 1, 0, 0, 0);
-    GDateTime *gdt4 = gncdt.new_local (2057, 11, 20, 0, 0, 0);
+    GDateTime *gdt1 = g_date_time_new_local (1999, 7, 21, 0, 0, 0);
+    GDateTime *gdt2 = g_date_time_new_local (1918, 3, 31, 0, 0, 0);
+    GDateTime *gdt3 = g_date_time_new_local (1918, 4, 1, 0, 0, 0);
+    GDateTime *gdt4 = g_date_time_new_local (2057, 11, 20, 0, 0, 0);
 
     gint day, mon, yr;
     Timespec t, r_t;
@@ -1954,10 +1902,10 @@ gnc_dmy2timespec_end (int day, int month, int year)// C: 1  Local: 0:0:0
 static void
 test_gnc_dmy2timespec_end (void)
 {
-    GDateTime *gdt1 = gncdt.new_local (1999, 7, 21,23,59, 59);
-    GDateTime *gdt2 = gncdt.new_local (1918, 3, 30, 23, 59, 59);
-    GDateTime *gdt3 = gncdt.new_local (1918, 3, 31, 23, 59, 59);
-    GDateTime *gdt4 = gncdt.new_local (2057, 11, 20, 23, 59, 59);
+    GDateTime *gdt1 = g_date_time_new_local (1999, 7, 21,23,59, 59);
+    GDateTime *gdt2 = g_date_time_new_local (1918, 3, 30, 23, 59, 59);
+    GDateTime *gdt3 = g_date_time_new_local (1918, 3, 31, 23, 59, 59);
+    GDateTime *gdt4 = g_date_time_new_local (2057, 11, 20, 23, 59, 59);
 
     gint day, mon, yr;
     Timespec t, r_t;
@@ -2048,7 +1996,7 @@ test_timespec_to_gdate (void)
 
     t = g_date_time_to_timespec (gdt0);
     date1 = timespec_to_gdate (t);
-    gdt_local = gncdt.to_local (gdt0);
+    gdt_local = g_date_time_to_local (gdt0);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
     g_date_time_unref (gdt_local);
     g_date_set_dmy (&date2, day, mon, yr);
@@ -2056,7 +2004,7 @@ test_timespec_to_gdate (void)
 
     t = g_date_time_to_timespec (gdt1);
     date1 = timespec_to_gdate (t);
-    gdt_local = gncdt.to_local (gdt1);
+    gdt_local = g_date_time_to_local (gdt1);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
     g_date_time_unref (gdt_local);
     g_date_set_dmy (&date2, day, mon, yr);
@@ -2064,7 +2012,7 @@ test_timespec_to_gdate (void)
 
     t = g_date_time_to_timespec (gdt2);
     date1 = timespec_to_gdate (t);
-    gdt_local = gncdt.to_local (gdt2);
+    gdt_local = g_date_time_to_local (gdt2);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
     g_date_time_unref (gdt_local);
     g_date_set_dmy (&date2, day, mon, yr);
@@ -2072,14 +2020,14 @@ test_timespec_to_gdate (void)
 
     t = g_date_time_to_timespec (gdt3);
     date1 = timespec_to_gdate (t);
-    gdt_local = gncdt.to_local (gdt3);
+    gdt_local = g_date_time_to_local (gdt3);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
     g_date_time_unref (gdt_local);
     g_date_set_dmy (&date2, day, mon, yr);
     g_assert_cmpint (g_date_get_julian (&date1), ==, g_date_get_julian (&date2));
     t = g_date_time_to_timespec (gdt4);
     date1 = timespec_to_gdate (t);
-    gdt_local = gncdt.to_local (gdt4);
+    gdt_local = g_date_time_to_local (gdt4);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
     g_date_time_unref (gdt_local);
     g_date_set_dmy (&date2, day, mon, yr);
@@ -2087,7 +2035,7 @@ test_timespec_to_gdate (void)
 
     t = g_date_time_to_timespec (gdt5);
     date1 = timespec_to_gdate (t);
-    gdt_local = gncdt.to_local (gdt5);
+    gdt_local = g_date_time_to_local (gdt5);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
     g_date_time_unref (gdt_local);
     g_date_set_dmy (&date2, day, mon, yr);
@@ -2110,10 +2058,10 @@ Timespec gdate_to_timespec (GDate d)// C: 7 in 6  Local: 0:0:0
 static void
 test_gdate_to_timespec (void)
 {
-    GDateTime *gdt1 = gncdt.new_local (1999, 7, 21, 0, 0, 0);
-    GDateTime *gdt2 = gncdt.new_local (1918, 3, 31, 0, 0, 0);
-    GDateTime *gdt3 = gncdt.new_local (1918, 4, 1, 0, 0, 0);
-    GDateTime *gdt4 = gncdt.new_local (2057, 11, 20, 0, 0, 0);
+    GDateTime *gdt1 = g_date_time_new_local (1999, 7, 21, 0, 0, 0);
+    GDateTime *gdt2 = g_date_time_new_local (1918, 3, 31, 0, 0, 0);
+    GDateTime *gdt3 = g_date_time_new_local (1918, 4, 1, 0, 0, 0);
+    GDateTime *gdt4 = g_date_time_new_local (2057, 11, 20, 0, 0, 0);
 
     gint day, mon, yr;
     Timespec t, r_t;
@@ -2191,51 +2139,51 @@ test_gnc_time64_get_day_start (void)
     gint day, mon, yr;
     time64 time, t_time, r_time;
 
-    gdt_local = gncdt.to_local (gdt0);
+    gdt_local = g_date_time_to_local (gdt0);
     time = g_date_time_to_unix (gdt0);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_begin = gncdt.new_local (yr, mon, day, 0, 0, 0);
+    gdt_day_begin = g_date_time_new_local (yr, mon, day, 0, 0, 0);
     t_time = g_date_time_to_unix (gdt_day_begin);
     r_time = gnc_time64_get_day_start (time);
     /* This will work in the half of the world where localtime is later than UTC */
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = gncdt.to_local (gdt1);
+    gdt_local = g_date_time_to_local (gdt1);
     time = g_date_time_to_unix (gdt1);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_begin = gncdt.new_local (yr, mon, day, 0, 0, 0);
+    gdt_day_begin = g_date_time_new_local (yr, mon, day, 0, 0, 0);
     t_time = g_date_time_to_unix (gdt_day_begin);
     r_time = gnc_time64_get_day_start (time);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = gncdt.to_local (gdt2);
+    gdt_local = g_date_time_to_local (gdt2);
     time = g_date_time_to_unix (gdt2);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_begin = gncdt.new_local (yr, mon, day, 0, 0, 0);
+    gdt_day_begin = g_date_time_new_local (yr, mon, day, 0, 0, 0);
     t_time = g_date_time_to_unix (gdt_day_begin);
     r_time = gnc_time64_get_day_start (time);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = gncdt.to_local (gdt3);
+    gdt_local = g_date_time_to_local (gdt3);
     time = g_date_time_to_unix (gdt3);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_begin = gncdt.new_local (yr, mon, day, 0, 0, 0);
+    gdt_day_begin = g_date_time_new_local (yr, mon, day, 0, 0, 0);
     t_time = g_date_time_to_unix (gdt_day_begin);
     r_time = gnc_time64_get_day_start (time);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = gncdt.to_local (gdt4);
+    gdt_local = g_date_time_to_local (gdt4);
     time = g_date_time_to_unix (gdt4);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_begin = gncdt.new_local (yr, mon, day, 0, 0, 0);
+    gdt_day_begin = g_date_time_new_local (yr, mon, day, 0, 0, 0);
     t_time = g_date_time_to_unix (gdt_day_begin);
     r_time = gnc_time64_get_day_start (time);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = gncdt.to_local (gdt5);
+    gdt_local = g_date_time_to_local (gdt5);
     time = g_date_time_to_unix (gdt5);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_begin = gncdt.new_local (yr, mon, day, 0, 0, 0);
+    gdt_day_begin = g_date_time_new_local (yr, mon, day, 0, 0, 0);
     t_time = g_date_time_to_unix (gdt_day_begin);
     r_time = gnc_time64_get_day_start (time);
     g_assert_cmpint (t_time, ==, r_time);
@@ -2271,50 +2219,50 @@ test_gnc_time64_get_day_end (void)
     gint day, mon, yr;
     time64 time, t_time, r_time;
 
-    gdt_local = gncdt.to_local (gdt0);
+    gdt_local = g_date_time_to_local (gdt0);
     time = g_date_time_to_unix (gdt0);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_end = gncdt.new_local (yr, mon, day, 23, 59, 59);
+    gdt_day_end = g_date_time_new_local (yr, mon, day, 23, 59, 59);
     t_time = g_date_time_to_unix (gdt_day_end);
     r_time = gnc_time64_get_day_end (time);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = gncdt.to_local (gdt1);
+    gdt_local = g_date_time_to_local (gdt1);
     time = g_date_time_to_unix (gdt1);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_end = gncdt.new_local (yr, mon, day, 23, 59, 59);
+    gdt_day_end = g_date_time_new_local (yr, mon, day, 23, 59, 59);
     t_time = g_date_time_to_unix (gdt_day_end);
     r_time = gnc_time64_get_day_end (time);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = gncdt.to_local (gdt2);
+    gdt_local = g_date_time_to_local (gdt2);
     time = g_date_time_to_unix (gdt2);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_end = gncdt.new_local (yr, mon, day, 23, 59, 59);
+    gdt_day_end = g_date_time_new_local (yr, mon, day, 23, 59, 59);
     t_time = g_date_time_to_unix (gdt_day_end);
     r_time = gnc_time64_get_day_end (time);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = gncdt.to_local (gdt3);
+    gdt_local = g_date_time_to_local (gdt3);
     time = g_date_time_to_unix (gdt3);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_end = gncdt.new_local (yr, mon, day, 23, 59, 59);
+    gdt_day_end = g_date_time_new_local (yr, mon, day, 23, 59, 59);
     t_time = g_date_time_to_unix (gdt_day_end);
     r_time = gnc_time64_get_day_end (time);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = gncdt.to_local (gdt4);
+    gdt_local = g_date_time_to_local (gdt4);
     time = g_date_time_to_unix (gdt4);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_end = gncdt.new_local (yr, mon, day, 23, 59, 59);
+    gdt_day_end = g_date_time_new_local (yr, mon, day, 23, 59, 59);
     t_time = g_date_time_to_unix (gdt_day_end);
     r_time = gnc_time64_get_day_end (time);
     g_assert_cmpint (t_time, ==, r_time);
 
-    gdt_local = gncdt.to_local (gdt5);
+    gdt_local = g_date_time_to_local (gdt5);
     time = g_date_time_to_unix (gdt5);
     g_date_time_get_ymd (gdt_local, &yr, &mon, &day);
-    gdt_day_end = gncdt.new_local (yr, mon, day, 23, 59, 59);
+    gdt_day_end = g_date_time_new_local (yr, mon, day, 23, 59, 59);
     t_time = g_date_time_to_unix (gdt_day_end);
     r_time = gnc_time64_get_day_end (time);
     g_assert_cmpint (t_time, ==, r_time);
@@ -2392,9 +2340,7 @@ timespec_get_type( void )// Local: 0:0:0
 void
 test_suite_gnc_date (void)
 {
-    _gnc_date_time_init (&gncdt);
-
-
+    tz = g_time_zone_new_local();
     GNC_TEST_ADD_FUNC (suitename, "gnc localtime", test_gnc_localtime);
     GNC_TEST_ADD_FUNC (suitename, "gnc gmtime", test_gnc_gmtime);
     GNC_TEST_ADD_FUNC (suitename, "gnc mktime", test_gnc_mktime);
@@ -2451,5 +2397,5 @@ test_suite_gnc_date (void)
 // GNC_TEST_ADD_FUNC (suitename, "gnc dow abbrev", test_gnc_dow_abbrev);
 // GNC_TEST_ADD_FUNC (suitename, "timespec boxed copy func", test_timespec_boxed_copy_func);
 // GNC_TEST_ADD_FUNC (suitename, "timespec boxed free func", test_timespec_boxed_free_func);
-
+    g_time_zone_unref(tz);
 }

commit 6c6153b5b67d0b95b4efc9e2d7036342659e732a
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Feb 7 11:29:48 2015 -0800

    Replace GDateTime dependency with boost::date_time.

diff --git a/src/libqof/qof/gnc-date-p.h b/src/libqof/qof/gnc-date-p.h
index 80e064f..9c443c9 100644
--- a/src/libqof/qof/gnc-date-p.h
+++ b/src/libqof/qof/gnc-date-p.h
@@ -23,10 +23,15 @@
 
 #ifndef __GNC_DATE_P_H__
 #define __GNC_DATE_P_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
 
+#include <stdint.h>
 #include "gnc-date.h"
 
-#define NANOS_PER_SECOND 1000000000
+#define NANOS_PER_SECOND INT32_C(1000000000)
 
 /** Convert a given date/time format from UTF-8 to an encoding suitable for the
  *  strftime system call.
@@ -74,4 +79,7 @@ typedef struct
 
 Testfuncs *gnc_date_load_funcs (void);
 
+#ifdef __cplusplus
+}
+#endif
 #endif /* __GNC_DATE_P_H__ */
diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index d67d2c3..e9bcb5d 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -25,46 +25,36 @@
 \********************************************************************/
 
 #define __EXTENSIONS__
-#ifdef __cplusplus
 extern "C"
 {
-#endif
 
 #include "config.h"
 #include <glib.h>
-#include <glib/gprintf.h>
-/* to be renamed qofdate.c */
-#include <ctype.h>
+#include <libintl.h>
+#include "platform.h"
+#include "qof.h"
 
 #ifdef HAVE_LANGINFO_D_FMT
-#  include <langinfo.h>
+# include <langinfo.h>
 #endif
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include <glib.h>
-#include <glib/gi18n.h>
-
-#include "gnc-date-p.h"
-#include "qof.h"
-
-#ifndef HAVE_STRPTIME
-#include "strptime.h"
-#endif
-#ifndef HAVE_LOCALTIME_R
-#include "localtime_r.h"
-#endif
-#include "platform.h"
-
 #ifdef G_OS_WIN32
 #  include <windows.h>
 #endif
-#ifdef __cplusplus
 }
-#endif
+
+#include "gnc-date.h"
+#include "gnc-date-p.h"
+
+#include "gnc-timezone.hpp"
+#define N_(string) string //So that xgettext will find it
+
+using Date = boost::gregorian::date;
+using Month = boost::gregorian::greg_month;
+using PTime = boost::posix_time::ptime;
+using LDT = boost::local_time::local_date_time;
+using Duration = boost::posix_time::time_duration;
+using LDTBase = boost::local_time::local_date_time_base<PTime, boost::date_time::time_zone_base<PTime, char>>;
 
 #ifdef HAVE_LANGINFO_D_FMT
 #  define GNC_D_FMT (nl_langinfo (D_FMT))
@@ -101,151 +91,55 @@ static int dateCompletionBackMonths = 6;
 /* This static indicates the debugging module that this .o belongs to. */
 static QofLogModule log_module = QOF_MOD_ENGINE;
 
-/* Getting a timezone is expensive, and we do it a lot. Cache the value. */
-static GTimeZone*
-gnc_g_time_zone_new_local (void)
-{
-    static GTimeZone* tz = NULL;
-    if (tz)
-        return tz;
-    tz = g_time_zone_new_local();
-    return tz;
-}
-
-static GDateTime*
-gnc_g_date_time_new_local (gint year, gint month, gint day, gint hour, gint minute, gdouble seconds)
-{
-    GTimeZone *tz = gnc_g_time_zone_new_local();
-    GDateTime *gdt = g_date_time_new (tz, year, month, day,
-				      hour, minute, seconds);
-    if (!gdt)
-	return gdt;
-    g_date_time_unref (gdt);
-/* g_date_time_new truncates nanoseconds to microseconds. Sometimes in
- * converting (particularly when parsing from a string) the
- * nanoseconds will have lost 1/2 a femtosecond or so. Adding 1/2 a
- * nano second ensures that the truncation doesn't lose a micorsecond
- * in translation.
- */
-    seconds += 5e-10;
-    gdt =  g_date_time_new (tz, year, month, day, hour, minute, seconds);
-    return gdt;
-}
-
-static GDateTime*
-gnc_g_date_time_adjust_for_dst (GDateTime *gdt, GTimeZone *tz)
-{
-    GDateTime *ngdt;
-    g_return_val_if_fail (gdt != NULL, NULL);
-    ngdt = g_date_time_to_timezone (gdt, tz);
-    g_date_time_unref (gdt);
-    gdt = g_date_time_to_timezone (ngdt, tz);
-    g_date_time_unref (ngdt);
-    return gdt;
-}
-
-GDateTime*
-gnc_g_date_time_new_from_unix_local (time64 time)
-{
-    GTimeZone *tz = gnc_g_time_zone_new_local ();
-    GDateTime *gdt = g_date_time_new_from_unix_utc (time);
-    if (gdt)
-	gdt = gnc_g_date_time_adjust_for_dst (gdt, tz);
-    return gdt;
-}
-
-static GDateTime*
-gnc_g_date_time_new_from_timeval_local (const GTimeVal* tv)
+// Default constructor Initializes to the current locale.
+static const TimeZoneProvider tzp;
+// For converting to/from POSIX time.
+static const PTime unix_epoch (Date(1970, boost::gregorian::Jan, 1),
+	boost::posix_time::seconds(0));
+/* To ensure things aren't overly screwed up by setting the nanosecond clock for boost::date_time. Don't do it, though, it doesn't get us anything and slows down the date/time library. */
+#ifndef BOOST_DATE_TIME_HAS_NANOSECONDS
+static constexpr uint64_t ticks_per_second = UINT64_C(1000000);
+#else
+static constexpr uint64_t ticks_per_second = UINT64_C(1000000000);
+#endif
+static LDT
+gnc_get_LDT(int year, int month, int day, int hour, int minute, int seconds)
 {
-    GTimeZone *tz = gnc_g_time_zone_new_local ();
-    GDateTime *gdt = g_date_time_new_from_timeval_utc (tv);
-    if (gdt)
-	gdt = gnc_g_date_time_adjust_for_dst (gdt, tz);
-    return gdt;
+    Date date(year, static_cast<Month>(month), day);
+    Duration time(hour, minute, seconds);
+    auto tz = tzp.get(year);
+    return LDT(date, time, tz, LDTBase::NOT_DATE_TIME_ON_ERROR);
 }
 
-static GDateTime*
-gnc_g_date_time_new_now_local (void)
+static LDT
+LDT_from_unix_local(const time64 time)
 {
-    GTimeZone *tz = gnc_g_time_zone_new_local ();
-    GDateTime *gdt = g_date_time_new_now_utc ();
-    if (gdt)
-	gdt = gnc_g_date_time_adjust_for_dst (gdt, tz);
-    return gdt;
-
+    PTime temp(unix_epoch.date(),
+	       boost::posix_time::hours(time / 3600) +
+	       boost::posix_time::seconds(time % 3600));
+    auto tz = tzp.get(temp.date().year());
+    return LDT(temp, tz);
 }
 
-static GDateTime*
-gnc_g_date_time_to_local (GDateTime* gdt)
+template<typename T>
+static time64
+time64_from_date_time(T time)
 {
-    GTimeZone *tz = NULL;
-    if (gdt)
-    {
-	tz = gnc_g_time_zone_new_local ();
-	gdt = gnc_g_date_time_adjust_for_dst (g_date_time_to_utc (gdt), tz);
-    }
-    return gdt;
+    auto duration = time - unix_epoch;
+    return duration.ticks() / ticks_per_second;
 }
 
-typedef struct
-{
-    GDateTime *(*new_local)(gint, gint, gint, gint, gint, gdouble);
-    GDateTime *(*adjust_for_dst)(GDateTime *, GTimeZone *);
-    GDateTime *(*new_from_unix_local)(time64);
-    GDateTime *(*new_from_timeval_local)(const GTimeVal *);
-    GDateTime *(*new_now_local)(void);
-    GDateTime *(*to_local)(GDateTime *);
-} _GncDateTime;
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-void _gnc_date_time_init(_GncDateTime*);
-void
-_gnc_date_time_init (_GncDateTime *gncdt)
-{
-    gncdt->new_local = gnc_g_date_time_new_local;
-    gncdt->adjust_for_dst = gnc_g_date_time_adjust_for_dst;
-    gncdt->new_from_unix_local = gnc_g_date_time_new_from_unix_local;
-    gncdt->new_from_timeval_local = gnc_g_date_time_new_from_timeval_local;
-    gncdt->new_now_local = gnc_g_date_time_new_now_local;
-    gncdt->to_local = gnc_g_date_time_to_local;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
 /****************** Posix Replacement Functions ***************************/
 void
 gnc_tm_free (struct tm* time)
 {
-     g_slice_free1 (sizeof (struct tm), time);
-}
-
-#define MAX_TZ_SIZE
-static void
-gnc_g_date_time_fill_struct_tm (GDateTime *gdt, struct tm* time)
-{
-     memset (time, 0, sizeof (struct tm));
-     g_date_time_get_ymd (gdt, &(time->tm_year), &(time->tm_mon), &(time->tm_mday));
-     time->tm_sec = g_date_time_get_second (gdt);
-     time->tm_min = g_date_time_get_minute (gdt);
-     time->tm_hour = g_date_time_get_hour (gdt);
-     // Watch out: struct tm has wday=0..6 with Sunday=0, but GDateTime has wday=1..7 with Sunday=7.
-     time->tm_wday = g_date_time_get_day_of_week (gdt) % 7;
-     time->tm_yday = g_date_time_get_day_of_year (gdt);
-     time->tm_isdst = g_date_time_is_daylight_savings (gdt);
-     time->tm_year -= 1900;
-     --time->tm_mon;
+    free(time);
 }
 
 struct tm*
 gnc_localtime (const time64 *secs)
 {
-    struct tm *time = static_cast<struct tm*>(g_slice_alloc0 (sizeof (struct tm)));
+    auto time = static_cast<struct tm*>(calloc(1, sizeof(struct tm)));
     if (gnc_localtime_r (secs, time) == NULL)
     {
 	gnc_tm_free (time);
@@ -254,39 +148,41 @@ gnc_localtime (const time64 *secs)
     return time;
 }
 
-/* Linux, Darwin, and MSWindows implementations of this function set the
- * globals timezone and daylight; BSD doesn't have those globals, and
- * Gnucash never uses them, so they're omitted from this
- * implementation. Bug 704185.
- */
 struct tm*
 gnc_localtime_r (const time64 *secs, struct tm* time)
 {
-     GDateTime *gdt = gnc_g_date_time_new_from_unix_local (*secs);
-     g_return_val_if_fail (gdt != NULL, NULL);
-
-     gnc_g_date_time_fill_struct_tm (gdt, time);
-     if (g_date_time_is_daylight_savings (gdt))
-          time->tm_isdst = 1;
-
+    try
+    {
+	auto ldt = LDT_from_unix_local(*secs);
+	*time = boost::local_time::to_tm(ldt);
 #ifdef HAVE_STRUCT_TM_GMTOFF
-     time->tm_gmtoff = g_date_time_get_utc_offset (gdt) / G_TIME_SPAN_SECOND;
+	auto offset = ldt.zone()->base_utc_offset();
+	if (ldt.is_dst())
+	    offset += ldt.zone()->dst_offset();
+	time->tm_gmtoff = offset.total_seconds();
 #endif
-
-     g_date_time_unref (gdt);
-     return time;
+    }
+    catch(boost::gregorian::bad_year)
+    {
+	return NULL; //Yeah, it should be nullptr, but this is a C-linkage func.
+    }
+    return time;
 }
 
 struct tm*
 gnc_gmtime (const time64 *secs)
 {
-     struct tm *time;
-     GDateTime *gdt = g_date_time_new_from_unix_utc (*secs);
-     g_return_val_if_fail (gdt != NULL, NULL);
-     time = static_cast<struct tm*>(g_slice_alloc0 (sizeof (struct tm)));
-     gnc_g_date_time_fill_struct_tm (gdt, time);
-     g_date_time_unref (gdt);
-     return time;
+    auto time = static_cast<struct tm*>(calloc(1, sizeof (struct tm)));
+    try {
+	PTime pdt(unix_epoch.date(), boost::posix_time::hours(*secs / 3600) +
+		  boost::posix_time::seconds(*secs % 3600));
+	*time = boost::posix_time::to_tm(pdt);
+    }
+    catch(boost::gregorian::bad_year)
+    {
+	return NULL; //Yeah, it should be nullptr, but this is a C-linkage func.
+    }
+    return time;
 }
 
 static void
@@ -318,10 +214,10 @@ normalize_struct_tm (struct tm* time)
      gint last_day;
 
      ++time->tm_mon;
-     /* GDateTime doesn't protect itself against out-of range years,
-      * so clamp year into GDateTime's range.
+     /* Gregorian_date throws if it gets an out-of-range year
+      * so clamp year into gregorian_date's range.
       */
-     if (year < 0) year = -year;
+     if (year < 1400) year += 1400;
      if (year > 9999) year %= 10000;
 
      normalize_time_component (&(time->tm_sec), &(time->tm_min), 60, 0);
@@ -348,68 +244,30 @@ normalize_struct_tm (struct tm* time)
 time64
 gnc_mktime (struct tm* time)
 {
-     GDateTime *gdt;
-     time64 secs;
-     normalize_struct_tm (time);
-     gdt = gnc_g_date_time_new_local (time->tm_year + 1900, time->tm_mon,
-				      time->tm_mday, time->tm_hour,
-				      time->tm_min, (gdouble)(time->tm_sec));
-     if (gdt == NULL)
-     {
-         g_warning("Invalid time passed to gnc_mktime");
-         return -1;
-     }
-     time->tm_mon = time->tm_mon > 0 ? time->tm_mon - 1 : 11;
-     // Watch out: struct tm has wday=0..6 with Sunday=0, but GDateTime has wday=1..7 with Sunday=7.
-     time->tm_wday = g_date_time_get_day_of_week (gdt) % 7;
-     time->tm_yday = g_date_time_get_day_of_year (gdt);
-     time->tm_isdst = g_date_time_is_daylight_savings (gdt);
-
-#ifdef HAVE_STRUCT_TM_GMTOFF
-     time->tm_gmtoff = g_date_time_get_utc_offset (gdt) / G_TIME_SPAN_SECOND;
-#endif
-
-     secs = g_date_time_to_unix (gdt);
-     g_date_time_unref (gdt);
-     return secs;
+    normalize_struct_tm (time);
+    return time64_from_date_time(boost::posix_time::ptime_from_tm(*time));
 }
 
 time64
 gnc_timegm (struct tm* time)
 {
-     GDateTime *gdt;
-     time64 secs;
-     normalize_struct_tm (time);
-     gdt = g_date_time_new_utc (time->tm_year + 1900, time->tm_mon,
-				time->tm_mday, time->tm_hour, time->tm_min,
-				(gdouble)(time->tm_sec));
-     time->tm_mon = time->tm_mon > 0 ? time->tm_mon - 1 : 11;
-     // Watch out: struct tm has wday=0..6 with Sunday=0, but GDateTime has wday=1..7 with Sunday=7.
-     time->tm_wday = g_date_time_get_day_of_week (gdt) % 7;
-     time->tm_yday = g_date_time_get_day_of_year (gdt);
-     time->tm_isdst = g_date_time_is_daylight_savings (gdt);
-
-     secs = g_date_time_to_unix (gdt);
-     g_date_time_unref (gdt);
-     return secs;
+    auto newtime = *time;
+    newtime.tm_gmtoff = 0;
+    return gnc_mktime(&newtime);
 }
 
-gchar*
+char*
 gnc_ctime (const time64 *secs)
 {
-     GDateTime *gdt = gnc_g_date_time_new_from_unix_local (*secs);
-     gchar *string = g_date_time_format (gdt, "%a %b %e %H:%M:%S %Y");
-     g_date_time_unref (gdt);
-     return string;
+    return gnc_print_time64(*secs, "%a %b %e %H:%M:%S %Y");
 }
 
 time64
 gnc_time (time64 *tbuf)
 {
-     GDateTime *gdt = gnc_g_date_time_new_now_local ();
-     time64 secs = g_date_time_to_unix (gdt);
-     g_date_time_unref (gdt);
-     if (tbuf != NULL)
+    auto pdt = boost::posix_time::second_clock::local_time();
+    auto secs = time64_from_date_time(pdt);
+    if (tbuf != nullptr)
 	  *tbuf = secs;
      return secs;
 }
@@ -417,9 +275,8 @@ gnc_time (time64 *tbuf)
 time64
 gnc_time_utc (time64 *tbuf)
 {
-     GDateTime *gdt = g_date_time_new_now_utc ();
-     time64 secs = g_date_time_to_unix (gdt);
-     g_date_time_unref (gdt);
+    auto pdt = boost::posix_time::second_clock::universal_time();
+    auto secs = time64_from_date_time(pdt);
      if (tbuf != NULL)
 	  *tbuf = secs;
      return secs;
@@ -434,17 +291,6 @@ gnc_difftime (const time64 secs1, const time64 secs2)
 /****************************************************************************/
 
 
-GDateTime*
-gnc_g_date_time_new_from_timespec_local (Timespec ts)
-{
-    GDateTime *gdt1 = gnc_g_date_time_new_from_unix_local (ts.tv_sec);
-    double nsecs = ((double)ts.tv_nsec + 0.5)/ 1000000000.0L;
-    GDateTime *gdt2 = g_date_time_add_seconds (gdt1, nsecs);
-    g_date_time_unref (gdt1);
-    g_assert (g_date_time_to_unix (gdt2) == ts.tv_sec + (nsecs >= 1.0 ? (gint64)nsecs : 0));
-    return gdt2;
-}
-
 const char*
 gnc_date_dateformat_to_string(QofDateFormat format)
 {
@@ -530,6 +376,24 @@ gnc_date_string_to_monthformat(const char *fmt_str, GNCDateMonthFormat *format)
     return FALSE;
 }
 
+char*
+gnc_print_time64(time64 time, const char* format)
+{
+    using Facet = boost::local_time::local_time_facet;
+    auto date_time = LDT_from_unix_local(time);
+    std::stringstream ss;
+    //The stream destructor frees the facet, so it must be heap-allocated.
+    auto output_facet(new Facet(format));
+    ss.imbue(std::locale(std::locale(), output_facet));
+    ss << date_time;
+    auto sstr = ss.str();
+    //ugly C allocation so that the ptr can be freed at the other end
+    char* cstr = static_cast<char*>(malloc(sstr.length() + 1));
+    memset(cstr, 0, sstr.length() + 1);
+    strncpy(cstr, sstr.c_str(), sstr.length());
+    return cstr;
+}
+
 /********************************************************************\
 \********************************************************************/
 
@@ -1412,10 +1276,7 @@ qof_strftime(gchar *buf, gsize max, const gchar *format, const struct tm *tm)
 gchar *
 gnc_date_timestamp (void)
 {
-    GDateTime *gdt = gnc_g_date_time_new_now_local ();
-    gchar *timestr = g_date_time_format (gdt, "%Y%m%d%H%M%S");
-    g_date_time_unref (gdt);
-    return timestr;
+    return gnc_print_time64(gnc_time(nullptr), "%Y-%M-%d %H:%M%S");
 }
 
 /********************************************************************\
@@ -1429,38 +1290,9 @@ gnc_date_timestamp (void)
 Timespec
 gnc_iso8601_to_timespec_gmt(const char *str)
 {
-    Timespec time = { 0L, 0L };
-    GDateTime *gdt;
-    gint hour = 0, minute = 0, day = 0, month = 0, year = 0;
-    gchar zone[12];
-    gdouble second = 0.0;
-    gint fields;
-
-    memset (zone, 0, sizeof (zone));
-
-    if (!str)
-	return time;
-
-    fields = sscanf (str, ISO_DATE_FORMAT, &year, &month,
-			  &day, &hour, &minute, &second, zone);
-    if (fields < 1)
-	return time;
-    else if (fields > 6 && strlen (zone) > 0) /* Date string included a timezone */
-    {
-	GTimeZone *tz = g_time_zone_new (zone);
-	second += 5e-10;
-	gdt = g_date_time_new (tz, year, month, day, hour, minute, second);
-    }
-    else /* No zone info, assume UTC */
-    {
-	second += 5e-10;
-	gdt = g_date_time_new_utc (year, month, day, hour, minute, second);
-    }
-
-    time.tv_sec = g_date_time_to_unix (gdt);
-    time.tv_nsec = g_date_time_get_microsecond (gdt) * 1000;
-    g_date_time_unref (gdt);
-    return time;
+    auto pdt = boost::posix_time::time_from_string(str);
+    auto time = time64_from_date_time(pdt);
+    return {time, 0};
 }
 
 /********************************************************************\
@@ -1469,28 +1301,20 @@ gnc_iso8601_to_timespec_gmt(const char *str)
 char *
 gnc_timespec_to_iso8601_buff (Timespec ts, char * buff)
 {
-    const gchar *fmt1 = "%Y-%m-%d %H:%M", *fmt2 = "%s:%02d.%06d %s";
-    GDateTime *gdt;
-    gchar *time_base, *tz;
+    constexpr size_t max_iso_date_length = 32;
+    std::string fmt1 = "%Y-%m-%d %H:%M";
 
     g_return_val_if_fail (buff != NULL, NULL);
-    gdt = gnc_g_date_time_new_from_timespec_local (ts);
-    g_return_val_if_fail (gdt != NULL, NULL);
-    time_base = g_date_time_format (gdt, fmt1);
+
 #ifdef G_OS_WIN32
-    tz = g_date_time_format (gdt, "%Z");
+    fmt1 += "%Z";
 #else
-    tz = g_date_time_format (gdt, "%z");
+    fmt1 += "%z";
 #endif
-    snprintf (buff, MAX_DATE_LENGTH, fmt2, time_base,
-	      g_date_time_get_second (gdt), g_date_time_get_microsecond (gdt),
-	      tz);
-
-    g_free (time_base);
-    g_free (tz);
-    g_date_time_unref (gdt);
+    char* str = gnc_print_time64(ts.tv_sec, fmt1.c_str());
+    strncpy (buff, str, max_iso_date_length);
+    free(str);
     return buff + strlen (buff);
-
 }
 
 void
@@ -1614,16 +1438,13 @@ GDate timespec_to_gdate (Timespec ts)
 
 GDate* gnc_g_date_new_today ()
 {
-     GDateTime *gdt = gnc_g_date_time_new_now_local ();
-     gint day, month, year;
-     GDate *result;
 
-     g_date_time_get_ymd (gdt, &year, &month, &day);
-     result = g_date_new_dmy (day, static_cast<GDateMonth>(month), year);
-     g_date_time_unref (gdt);
-     g_assert(g_date_valid (result));
-
-     return result;
+    auto pdt = boost::posix_time::second_clock::local_time();
+    auto ymd = pdt.date().year_month_day();
+    auto month = static_cast<GDateMonth>(ymd.month.as_number());
+    auto result = g_date_new_dmy (ymd.day, month, ymd.year);
+    g_assert(g_date_valid (result));
+    return result;
 }
 
 Timespec gdate_to_timespec (GDate d)
diff --git a/src/libqof/qof/gnc-date.h b/src/libqof/qof/gnc-date.h
index 3f5f27c..c25371a 100644
--- a/src/libqof/qof/gnc-date.h
+++ b/src/libqof/qof/gnc-date.h
@@ -238,12 +238,6 @@ time64 gnc_time_utc (time64 *tbuf);
  */
 gdouble gnc_difftime (const time64 secs1, const time64 secs2);
 
-/** Wrapper for g_date_time_new_from_unix_local() that takes special care on
- * windows to take the local timezone into account. On unix, it just calles the
- * g_date function. */
-GDateTime*
-gnc_g_date_time_new_from_unix_local (time64 time);
-
 /** \brief free a struct tm* created with gnc_localtime() or gnc_gmtime()
  * \param time: The struct tm* to be freed.
  */
@@ -280,6 +274,19 @@ Note the reversed return values!
 */
 gboolean gnc_date_string_to_monthformat(const gchar *format_string,
                                         GNCDateMonthFormat *format);
+
+/** \brief print a time64 as a date string per format
+ * \param time
+ * \param format A date format conforming to the strftime format rules.
+ * \return a raw heap-allocated char* which must be freed.
+ */
+char* gnc_print_time64(time64 time, const char* format);
+
+/** Returns a newly allocated date of the current clock time, taken from
+ * time(2). The caller must g_date_free() the object afterwards. */
+GDate* gnc_g_date_new_today (void);
+
+
 // @}
 
 /* Datatypes *******************************************************/
@@ -338,10 +345,6 @@ void timespecFromTime64 (Timespec *ts, time64 t );
 /** Turns a Timespec into a time64 */
 time64 timespecToTime64 (Timespec ts);
 
-/** Returns a newly allocated date of the current clock time, taken from
- * time(2). The caller must g_date_free() the object afterwards. */
-GDate* gnc_g_date_new_today (void);
-
 /** Turns a Timespec into a GDate */
 GDate timespec_to_gdate (Timespec ts);
 

commit 6673128b9f643df888bb97e6a3f8fea6cc3b39b6
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Feb 7 11:27:57 2015 -0800

    Rewrite gnc_gdate_set_time64 to not depend upon GDateTime.

diff --git a/src/backend/xml/sixtp-dom-generators.c b/src/backend/xml/sixtp-dom-generators.c
index 6217697..48311ef 100644
--- a/src/backend/xml/sixtp-dom-generators.c
+++ b/src/backend/xml/sixtp-dom-generators.c
@@ -131,17 +131,10 @@ commodity_ref_to_dom_tree(const char *tag, const gnc_commodity *c)
  * but we want to serialize it un-normalized, so we make a partial
  * copy.
  */
-gchar *
+char *
 timespec_sec_to_string(const Timespec *ts)
 {
-     gchar *time_string;
-     GDateTime *gdt;
-     Timespec sts = { ts->tv_sec, 0};
-     gdt = gnc_g_date_time_new_from_timespec_local (sts);
-     g_return_val_if_fail (gdt != NULL, NULL);
-     time_string = g_date_time_format (gdt, "%Y-%m-%d %H:%M:%S %z");
-     g_date_time_unref (gdt);
-     return time_string;
+     return gnc_print_time64(ts->tv_sec, "%Y-%m-%d %H:%M:%S %z");
 }
 
 gchar *
diff --git a/src/core-utils/gnc-gdate-utils.c b/src/core-utils/gnc-gdate-utils.c
index 059275a..ae415fd 100644
--- a/src/core-utils/gnc-gdate-utils.c
+++ b/src/core-utils/gnc-gdate-utils.c
@@ -37,11 +37,10 @@ gnc_gdate_set_today (GDate* gd)
 void
 gnc_gdate_set_time64 (GDate* gd, time64 time)
 {
-    GDateTime *gdt = gnc_g_date_time_new_from_unix_local (time);
-    gint y, m, d;
-    g_date_time_get_ymd (gdt, &y, &m, &d);
-    g_date_set_dmy (gd, d, m, y);
-    g_date_time_unref (gdt);
+    struct tm tm;
+    gnc_localtime_r(&time, &tm);
+    g_date_set_dmy (gd, tm.tm_mday, tm.tm_mon, tm.tm_year + 1900);
+
 }
 
 gboolean
diff --git a/src/gnome-utils/gnc-main-window.c b/src/gnome-utils/gnc-main-window.c
index e17b56c..e028e78 100644
--- a/src/gnome-utils/gnc-main-window.c
+++ b/src/gnome-utils/gnc-main-window.c
@@ -1653,10 +1653,6 @@ static gchar *generate_statusbar_lastmodified_message()
                 int r = stat(filepath, &statbuf);
                 if (r == 0)
                 {
-                    // File mtime could be accessed ok
-                    gint64 mtime = statbuf.st_mtime;
-                    GDateTime *gdt = gnc_g_date_time_new_from_unix_local (mtime);
-                    gchar *dummy_strftime_has_ampm = g_date_time_format (gdt, "%P");
                     /* Translators: This is the date and time that is shown in
                     the status bar after opening a file: The date and time of
                     last modification. The string is the format string for
@@ -1664,20 +1660,14 @@ static gchar *generate_statusbar_lastmodified_message()
                     explanation of the modifiers. First string is for a locale
                     that has the a.m. or p.m. string in its locale, second
                     string is for locales that do not have that string. */
-                    gchar *time_string =
-                        g_date_time_format (gdt, (dummy_strftime_has_ampm &&
-						  strlen(dummy_strftime_has_ampm) > 0)
-                                            ? _("Last modified on %a, %b %e, %Y at %I:%M%P")
-                                            : _("Last modified on %x %X"));
-
-                    g_date_time_unref (gdt);
-
+                    char *time_string =
+			gnc_print_time64(statbuf.st_mtime,
+					 _("Last modified on %a, %b %e, %Y at %I:%M%P"));
                     //g_warning("got time %ld, str=%s\n", mtime, time_string);
                     /* Translators: This message appears in the status bar after opening the file. */
                     message = g_strdup_printf(_("File %s opened. %s"),
                                               filename, time_string);
-                    g_free(time_string);
-                    g_free(dummy_strftime_has_ampm);
+                    free(time_string);
                 }
                 else
                 {

commit 19f64ad3951c7ebe0260d876aaba2ee4e1fa1218
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Jan 31 15:02:21 2015 -0800

    Restore GLIB_CFLAGS to test_kvp_value, required for GVALUE stuff.

diff --git a/src/libqof/qof/test/Makefile.am b/src/libqof/qof/test/Makefile.am
index 6738fe1..15ed8fc 100644
--- a/src/libqof/qof/test/Makefile.am
+++ b/src/libqof/qof/test/Makefile.am
@@ -52,6 +52,7 @@ endif
 test_kvp_value_CPPFLAGS = \
     -I$(GTEST_HEADERS) \
     -I$(top_srcdir)/$(MODULEPATH) \
+    $(GLIB_CFLAGS) \
     $(BOOST_CPPFLAGS)
 
 check_PROGRAMS += test-kvp-value

commit 2061026f2101f0c78728c5505b1a484d026f2806
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Jan 31 15:00:57 2015 -0800

    Make TimeZoneProvider::get const noexcept.

diff --git a/src/libqof/qof/gnc-timezone.cpp b/src/libqof/qof/gnc-timezone.cpp
index e720f26..077291f 100644
--- a/src/libqof/qof/gnc-timezone.cpp
+++ b/src/libqof/qof/gnc-timezone.cpp
@@ -598,7 +598,7 @@ TimeZoneProvider::TimeZoneProvider(const std::string& tzname) :  zone_vector {}
 
 
 TZ_Ptr
-TimeZoneProvider::get(int year)
+TimeZoneProvider::get(int year) const noexcept
 {
     auto iter = find_if(zone_vector.begin(), zone_vector.end(),
 			[=](TZ_Entry e) { return e.first >= year; });
diff --git a/src/libqof/qof/gnc-timezone.hpp b/src/libqof/qof/gnc-timezone.hpp
index 400f0c9..9988b87 100644
--- a/src/libqof/qof/gnc-timezone.hpp
+++ b/src/libqof/qof/gnc-timezone.hpp
@@ -54,7 +54,7 @@ public:
     TimeZoneProvider(const TimeZoneProvider&&) = delete;
     TimeZoneProvider operator=(const TimeZoneProvider&) = delete;
     TimeZoneProvider operator=(const TimeZoneProvider&&) = delete;
-    TZ_Ptr get (int year);
+    TZ_Ptr get (int year) const noexcept;
 private:
     TZ_Vector zone_vector;
 #if PLATFORM(WINDOWS)

commit d98ddd12a7d7d6ed8a7e9b7a26a3e06f54336f49
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Jan 27 16:05:00 2015 -0800

    Implement TimezoneProvider for POSIX.

diff --git a/src/libqof/qof/gnc-timezone.cpp b/src/libqof/qof/gnc-timezone.cpp
index c35973a..e720f26 100644
--- a/src/libqof/qof/gnc-timezone.cpp
+++ b/src/libqof/qof/gnc-timezone.cpp
@@ -24,7 +24,8 @@
 
 #include <string>
 #include <cstdint>
-#include <ostream>
+#include <istream>
+#include <algorithm>
 #include <boost/date_time/gregorian/gregorian.hpp>
 using namespace gnc::date;
 
@@ -33,6 +34,17 @@ using time_zone = boost::local_time::custom_time_zone;
 using dst_offsets = boost::local_time::dst_adjustment_offsets;
 using calc_rule_ptr = boost::local_time::dst_calc_rule_ptr;
 
+template<typename T>
+T*
+endian_swap(T* t)
+{
+#if ! WORDS_BIGENDIAN
+    auto memp = reinterpret_cast<unsigned char*>(t);
+    std::reverse(memp, memp + sizeof(T));
+#endif
+    return t;
+}
+
 #if PLATFORM(WINDOWS)
 /* libstdc++ to_string is broken on MinGW with no real interest in fixing it.
  * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52015
@@ -271,7 +283,7 @@ namespace IANAParser
 
     struct TTInfo
     {
-	uint32_t gmtoff;
+	int32_t gmtoff;
 	uint8_t isdst;
 	uint8_t abbrind;
     };
@@ -290,135 +302,139 @@ namespace IANAParser
 	uint8_t index;
     };
 
-    static std::ifstream
+    static std::unique_ptr<char[]>
     find_tz_file(const std::string& name)
     {
+	std::ifstream ifs;
 	if (name.empty())
-	    return std::ifstream("/etc/localtime", std::ios::binary);
-
-	std::string tzname = name;
+	{
+	    ifs.open("/etc/localtime",
+		     std::ios::in|std::ios::binary|std::ios::ate);
+	}
+	else
+	{
+	    std::string tzname = name;
 //POSIX specifies that that identifier should begin with ':', but we
 //should be liberal. If it's there, it's not part of the filename.
-	if (tzname[0] == ':')
-	    tzname.erase(tzname.begin());
-	if (tzname[0] == '/') //Absolute filename
-	    return std::ifstream(tzname, std::ios::binary);
-
-	std::string tzdir = std::getenv("TZDIR");
-	if (tzdir.empty())
-	    tzdir = "/usr/share/zoneinfo";
+	    if (tzname[0] == ':')
+		tzname.erase(tzname.begin());
+	    if (tzname[0] == '/') //Absolute filename
+	    {
+		ifs.open(tzname, std::ios::in|std::ios::binary|std::ios::ate);
+	    }
+	    else
+	    {
+		const char* tzdir_c = std::getenv("TZDIR");
+		std::string tzdir = tzdir_c ? tzdir_c : "/usr/share/zoneinfo";
 //Note that we're not checking the filename.
-	return std::ifstream(std::move(tzdir + "/" + tzname), std::ios::binary);
+		ifs.open(std::move(tzdir + "/" + tzname),
+			 std::ios::in|std::ios::binary|std::ios::ate);
+	    }
+	}
+	if (! ifs.is_open())
+	    throw std::invalid_argument("The timezone string failed to resolve to a valid filename");
+	std::streampos filesize = ifs.tellg();
+	std::unique_ptr<char[]>fileblock(new char[filesize]);
+	ifs.seekg(0, std::ios::beg);
+	ifs.read(fileblock.get(), filesize);
+	ifs.close();
+	return fileblock;
     }
 
-  struct IANAParser
+    using TZInfoVec = std::vector<TZInfo>;
+    using TZInfoIter = TZInfoVec::iterator;
+
+    struct IANAParser
     {
 	IANAParser(const std::string& name) : IANAParser(find_tz_file(name)) {}
-	IANAParser(std::ifstream ifs);
+	IANAParser(std::unique_ptr<char[]>);
 	std::vector<Transition>transitions;
-	std::vector<TZInfo>tzinfo;
+	TZInfoVec tzinfo;
 	int last_year;
     };
 
-    IANAParser::IANAParser(std::ifstream ifs)
+    IANAParser::IANAParser(std::unique_ptr<char[]>fileblock)
     {
-	if (! ifs)
-	    throw std::invalid_argument("The timezone string failed to resolve to a valid filename");
-
-	TZHead tzh;
-	auto timesize = sizeof(int32_t);
+	unsigned int fb_index = 0;
+	TZHead tzh = *reinterpret_cast<TZHead*>(&fileblock[fb_index]);
 	last_year = 2037; //Constrained by 32-bit time_t.
-	ifs.get(reinterpret_cast<char*>(&tzh), sizeof(tzh));
-	auto time_count = *reinterpret_cast<uint32_t*>(tzh.timecnt);
-	auto type_count = *reinterpret_cast<uint32_t*>(tzh.typecnt);
-	auto char_count = *reinterpret_cast<uint32_t*>(tzh.charcnt);
-	auto isgmt_count = *reinterpret_cast<uint32_t*>(tzh.ttisgmtcnt);
-	auto isstd_count = *reinterpret_cast<uint32_t*>(tzh.ttisstdcnt);
-	auto leap_count = *reinterpret_cast<uint32_t*>(tzh.leapcnt);
+
+	auto time_count = *(endian_swap(reinterpret_cast<uint32_t*>(tzh.timecnt)));
+	auto type_count = *(endian_swap(reinterpret_cast<uint32_t*>(tzh.typecnt)));
+	auto char_count = *(endian_swap(reinterpret_cast<uint32_t*>(tzh.charcnt)));
+	auto isgmt_count = *(endian_swap(reinterpret_cast<uint32_t*>(tzh.ttisgmtcnt)));
+	auto isstd_count = *(endian_swap(reinterpret_cast<uint32_t*>(tzh.ttisstdcnt)));
+	auto leap_count = *(endian_swap(reinterpret_cast<uint32_t*>(tzh.leapcnt)));
 	if (tzh.version == '2' && sizeof(time_t) == sizeof(int64_t))
 	{
-	    ifs.seekg(sizeof(tzh) +
-		     timesize + sizeof(uint8_t) * time_count +
-		     sizeof(TTInfo) * type_count +
-		     sizeof(char) * char_count +
-		     sizeof(uint8_t) * isgmt_count +
-		     sizeof(uint8_t) * isstd_count +
-		     2 * timesize * leap_count +
-		     sizeof(tzh));
-	    timesize = sizeof(int64_t);
-	    //This might change at some point in the probably very distant future.
+	    fb_index = (sizeof(tzh) +
+			sizeof(time_t) + sizeof(uint8_t) * time_count +
+			sizeof(TTInfo) * type_count +
+			sizeof(char) * char_count +
+			sizeof(uint8_t) * isgmt_count +
+			sizeof(uint8_t) * isstd_count +
+			2 * sizeof(time_t) * leap_count);
+
+	    //This might change at some point in the probably very
+	    //distant future.
+	    tzh = *reinterpret_cast<TZHead*>(&fileblock[fb_index]);
 	    last_year = 2499;
+	    time_count = *(endian_swap(reinterpret_cast<uint32_t*>(tzh.timecnt)));
+	    type_count = *(endian_swap(reinterpret_cast<uint32_t*>(tzh.typecnt)));
+	    char_count = *(endian_swap(reinterpret_cast<uint32_t*>(tzh.charcnt)));
+	    isgmt_count = *(endian_swap(reinterpret_cast<uint32_t*>(tzh.ttisgmtcnt)));
+	    isstd_count = *(endian_swap(reinterpret_cast<uint32_t*>(tzh.ttisstdcnt)));
+	    leap_count = *(endian_swap(reinterpret_cast<uint32_t*>(tzh.leapcnt)));
 	}
-
+	fb_index += sizeof(tzh);
+	
 	transitions.reserve(time_count);
 	tzinfo.reserve(type_count);
-
-	for(auto tr : transitions)
-	{
-	    uint8_t time[sizeof(time_t)];
-	    ifs.get(reinterpret_cast<char*>(time), timesize);
-	    tr.timestamp = *reinterpret_cast<time_t*>(time);
-	}
-
-	for (auto tr : transitions)
+	auto start_index = fb_index;
+	auto info_index_zero = start_index + time_count * sizeof(time_t);
+	for(auto index = 0; index < time_count; ++index)
 	{
-	    char idx;
-	    ifs.get(idx);
-	    tr.index = std::move(idx);
+	    fb_index = start_index + index * sizeof(time_t);
+	    auto info_index = info_index_zero + index;
+	    transitions.push_back(
+		{*(endian_swap(reinterpret_cast<time_t*>(&fileblock[fb_index]))),
+			static_cast<uint8_t>(fileblock[info_index])});
 	}
 
-	for(auto tz : tzinfo)
-	{
-	    char infochars[sizeof(TTInfo)];
-	    ifs.get(infochars, sizeof(TTInfo));
-	    tz.info = *reinterpret_cast<TTInfo*>(infochars);
-	}
-
-	try
-	{
-	    std::unique_ptr<char[]>abbrev(new char[char_count]);
-	    ifs.get(abbrev.get(), char_count);
-
-	    for (auto tz : tzinfo)
-	    {
-		tz.name = abbrev[tz.info.abbrind];
-	    }
-	}
-	catch(std::bad_alloc)
+	//Add in the tzinfo indexes consumed in the previous loop
+	start_index = info_index_zero + time_count;
+	//Can't use sizeof(TZInfo) because it's padded out to 8 bytes.
+	static const size_t tzinfo_size = 6;
+	auto abbrev = start_index + type_count * tzinfo_size;
+	auto std_dist = abbrev + char_count;
+	auto gmt_dist = std_dist + type_count;
+	for(auto index = 0; index < type_count; ++index)
 	{
-	    ;
+	    fb_index = start_index + index * tzinfo_size;
+	    TTInfo info = *reinterpret_cast<TTInfo*>(&fileblock[fb_index]);
+	    endian_swap(&info.gmtoff);
+	    tzinfo.push_back(
+		{info, &fileblock[abbrev + info.abbrind],
+			fileblock[std_dist + index] != '\0',
+			fileblock[gmt_dist + index] != '\0'});
 	}
 
-	if (isstd_count == type_count)
-	{
-	    char foo;
-	    for (auto tz : tzinfo)
-	    {
-		ifs.get(foo);
-		tz.isstd = foo != '\0';
-	    }
-	    for (auto tz : tzinfo)
-	    {
-		ifs.get(foo);
-		tz.isgmt = foo != '\0';
-	    }
-	}
     }
 }
 
 namespace DSTRule
 {
     using gregorian_date = boost::gregorian::date;
-    using IANAParser::TZInfo;
+    using IANAParser::TZInfoIter;
     using ndate = boost::gregorian::nth_day_of_the_week_in_month;
     using week_num =
 	boost::date_time::nth_kday_of_month<boost::gregorian::date>::week_num;
 
     struct Transition
     {
-	Transition() : month(0), dow(0), week(static_cast<week_num>(0)) {}
+	Transition() : month(1), dow(0), week(static_cast<week_num>(0)) {}
 	Transition(gregorian_date date);
-	bool operator==(const Transition& rhs);
+	bool operator==(const Transition& rhs) const noexcept;
 	ndate get();
 	boost::gregorian::greg_month month;
 	boost::gregorian::greg_weekday dow;
@@ -431,7 +447,7 @@ namespace DSTRule
     {}
 
     bool
-    Transition::operator==(const Transition& rhs)
+    Transition::operator==(const Transition& rhs) const noexcept
     {
 	return (month == rhs.month && dow == rhs.dow && week == rhs.week);
     }
@@ -445,7 +461,7 @@ namespace DSTRule
     struct DSTRule
     {
 	DSTRule();
-	DSTRule(const TZInfo& info1, const TZInfo& info2,
+	DSTRule(TZInfoIter info1, TZInfoIter info2,
 		ptime date1, ptime date2);
 	bool operator==(const DSTRule& rhs) const noexcept;
 	bool operator!=(const DSTRule& rhs) const noexcept;
@@ -453,29 +469,31 @@ namespace DSTRule
 	Transition to_dst;
 	duration to_std_time;
 	duration to_dst_time;
-	const TZInfo& std_info;
-	const TZInfo& dst_info;
+	TZInfoIter std_info;
+	TZInfoIter dst_info;
     };
 
     DSTRule::DSTRule() : to_std(), to_dst(), to_std_time {}, to_dst_time {},
 	std_info (), dst_info () {};
 
-    DSTRule::DSTRule (const TZInfo& info1, const TZInfo& info2,
+    DSTRule::DSTRule (TZInfoIter info1, TZInfoIter info2,
 		      ptime date1, ptime date2) :
 	to_std(date1.date()), to_dst(date2.date()),
 	to_std_time(date1.time_of_day()), to_dst_time(date2.time_of_day()),
 	std_info(info1), dst_info(info2)
     {
-	if (info1.info.isdst == info2.info.isdst)
+	if (info1->info.isdst == info2->info.isdst)
 	    throw(std::invalid_argument("Both infos have the same dst value."));
-	if (info1.info.isdst && !info2.info.isdst)
+	if (info1->info.isdst && !info2->info.isdst)
 	{
 	    std::swap(to_std, to_dst);
 	    std::swap(to_std_time, to_dst_time);
 	    std::swap(std_info, dst_info);
 	}
-	if (dst_info.isgmt) to_dst_time += boost::posix_time::seconds(dst_info.info.gmtoff);
-	if (std_info.isgmt) to_std_time += boost::posix_time::seconds(std_info.info.gmtoff);
+	if (dst_info->isgmt)
+	    to_dst_time += boost::posix_time::seconds(dst_info->info.gmtoff);
+	if (std_info->isgmt)
+	    to_std_time += boost::posix_time::seconds(std_info->info.gmtoff);
 
     }
 
@@ -486,8 +504,8 @@ namespace DSTRule
 		to_dst == rhs.to_dst &&
 		to_std_time == rhs.to_std_time &&
 		to_dst_time == rhs.to_dst_time &&
-		&std_info == &rhs.std_info &&
-		&dst_info == &rhs.dst_info);
+		std_info == rhs.std_info &&
+		dst_info == rhs.dst_info);
     }
 
     bool
@@ -498,14 +516,13 @@ namespace DSTRule
 }
 
 static TZ_Entry
-zone_no_dst(int year, IANAParser::TZInfo std_info)
+zone_no_dst(int year, IANAParser::TZInfoIter std_info)
 {
-    using boost::local_time::dst_calc_rule;
-
-    time_zone_names names(std_info.name, std_info.name, nullptr, nullptr);
-    duration std_off(0, 0, std_info.info.gmtoff);
-    dst_offsets offsets(NULL);
-    TZ_Ptr tz(new time_zone(names, std_off, offsets, dst_calc_rule));
+    time_zone_names names(std_info->name, std_info->name, "", "");
+    duration std_off(0, 0, std_info->info.gmtoff);
+    dst_offsets offsets({0, 0, 0}, {0, 0, 0}, {0, 0, 0});
+    boost::local_time::dst_calc_rule_ptr calc_rule(nullptr);
+    TZ_Ptr tz(new time_zone(names, std_off, offsets, calc_rule));
     return std::make_pair(year, tz);
 }
 
@@ -517,11 +534,11 @@ zone_from_rule(int year, DSTRule::DSTRule rule)
     using nth_day_rule =
 	boost::local_time::nth_day_of_the_week_in_month_dst_rule;
 
-    time_zone_names names(rule.std_info.name, rule.std_info.name,
-			  rule.dst_info.name, rule.dst_info.name);
-    duration std_off(0, 0, rule.std_info.info.gmtoff);
+    time_zone_names names(rule.std_info->name, rule.std_info->name,
+			  rule.dst_info->name, rule.dst_info->name);
+    duration std_off(0, 0, rule.std_info->info.gmtoff);
     duration dlt_off(0, 0,
-		     rule.dst_info.info.gmtoff - rule.std_info.info.gmtoff);
+		     rule.dst_info->info.gmtoff - rule.std_info->info.gmtoff);
     dst_offsets offsets(dlt_off, rule.to_dst_time, rule.to_std_time);
     calc_rule_ptr dates(new nth_day_rule(rule.to_dst.get(), rule.to_std.get()));
     TZ_Ptr tz(new time_zone(names, std_off, offsets, dates));
@@ -531,18 +548,17 @@ zone_from_rule(int year, DSTRule::DSTRule rule)
 TimeZoneProvider::TimeZoneProvider(const std::string& tzname) :  zone_vector {}
 {
     IANAParser::IANAParser parser(tzname);
-    auto last_info = std::find_if(parser.tzinfo,
-				  [](IANAParser::TZInfo& tz)
+    auto last_info = std::find_if(parser.tzinfo.begin(), parser.tzinfo.end(),
+				  [](IANAParser::TZInfo tz)
 				  {return !tz.info.isdst;});
     auto last_time = ptime();
     DSTRule::DSTRule last_rule;
     for (auto txi = parser.transitions.begin();
 	 txi != parser.transitions.end(); ++txi)
     {
-	auto this_info = parser.tzinfo[txi->index];
+	auto this_info = parser.tzinfo.begin() + txi->index;
 	auto this_time = boost::posix_time::from_time_t(txi->timestamp);
 	auto this_year = this_time.date().year();
-	auto last_year = last_time.date().year();
 	//Initial case, gap in transitions > 1 year, non-dst zone
 	//change. In the last case the exact date of the change will be
 	//wrong because boost::local_date::timezone isn't able to
@@ -551,8 +567,8 @@ TimeZoneProvider::TimeZoneProvider(const std::string& tzname) :  zone_vector {}
 	//was 1946, but we have to handle the case in order to parse
 	//the tz file.
 	if (last_time.is_not_a_date_time() ||
-	    this_year - last_year > 1 ||
-	    last_info.info.isdst == this_info.info.isdst)
+	    this_year - last_time.date().year() > 1 ||
+	    last_info->info.isdst == this_info->info.isdst)
 	{
 	    zone_vector.push_back(zone_no_dst(this_year, last_info));
 	}
@@ -560,7 +576,7 @@ TimeZoneProvider::TimeZoneProvider(const std::string& tzname) :  zone_vector {}
 	else
 	{
 	    DSTRule::DSTRule new_rule(last_info, this_info,
-			     last_time.date(), this_time.date());
+			     last_time, this_time);
 	    if (new_rule != last_rule)
 	    {
 		last_rule = new_rule;
diff --git a/src/libqof/qof/test/gtest-gnc-timezone.cpp b/src/libqof/qof/test/gtest-gnc-timezone.cpp
index 5696cd2..b20f11a 100644
--- a/src/libqof/qof/test/gtest-gnc-timezone.cpp
+++ b/src/libqof/qof/test/gtest-gnc-timezone.cpp
@@ -38,12 +38,22 @@ TEST(gnc_timezone_constructors, test_default_constructor)
 
 TEST(gnc_timezone_constructors, test_pacific_time_constructor)
 {
-    TimeZoneProvider tzp ("Pacific Standard Time");
+#if PLATFORM(WINDOWS)
+    std::string timzone("Pacific Standard Time");
+#else
+    std::string timezone("America/Los_Angeles");
+#endif
+    TimeZoneProvider tzp (timezone);
     EXPECT_NO_THROW (tzp.get(2006));
     TZ_Ptr tz = tzp.get (2006);
 
     EXPECT_FALSE(tz->std_zone_abbrev().empty());
-    EXPECT_TRUE(tz->std_zone_abbrev() == "Pacific Standard Time");
+#if PLATFORM(WINDOWS)
+    EXPECT_TRUE(tz->std_zone_abbrev() == timezone);
+#else
+    EXPECT_TRUE(tz->std_zone_abbrev() == "PST");
+    EXPECT_TRUE(tz->dst_zone_abbrev() == "PDT");
+#endif
     EXPECT_TRUE(tz->base_utc_offset().hours() == -8);
 }
 

commit 280b7223bfc7e4d16a0a0fdb93d8aa083131090d
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Jan 24 15:12:43 2015 -0800

    Partial posix implementation

diff --git a/configure.ac b/configure.ac
index ae6efd8..a98d210 100644
--- a/configure.ac
+++ b/configure.ac
@@ -371,7 +371,7 @@ update to latest  darwin])
     ;;
   darwin*)
     platform=darwin
-    AC_DEFINE(PLATFORM_OSX,1,[Running on OSX, either X11 or Quartz])
+    AC_DEFINE(GNC_PLATFORM_OSX, 1,[Running on OSX, either X11 or Quartz])
     AC_DEFINE(GNC_PLATFORM_POSIX, 1, [POSIX-compliant OS])
     AC_DEFINE(GNC_PLATFORM_DARWIN, 1, [Darwin-based OS])
     AC_MSG_RESULT($platform)
diff --git a/src/libqof/qof/gnc-timezone.cpp b/src/libqof/qof/gnc-timezone.cpp
index 4b07894..c35973a 100644
--- a/src/libqof/qof/gnc-timezone.cpp
+++ b/src/libqof/qof/gnc-timezone.cpp
@@ -28,6 +28,11 @@
 #include <boost/date_time/gregorian/gregorian.hpp>
 using namespace gnc::date;
 
+using duration = boost::posix_time::time_duration;
+using time_zone = boost::local_time::custom_time_zone;
+using dst_offsets = boost::local_time::dst_adjustment_offsets;
+using calc_rule_ptr = boost::local_time::dst_calc_rule_ptr;
+
 #if PLATFORM(WINDOWS)
 /* libstdc++ to_string is broken on MinGW with no real interest in fixing it.
  * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52015
@@ -115,10 +120,9 @@ windows_tz_names (HKEY key)
 static TZ_Ptr
 zone_from_regtzi (const RegTZI& regtzi, time_zone_names names)
 {
-    using duration = boost::posix_time::time_duration;
     using ndate = boost::gregorian::nth_day_of_the_week_in_month;
     using nth_day_rule = boost::local_time::nth_day_of_the_week_in_month_dst_rule;
-    using time_zone = boost::local_time::custom_time_zone;
+   using make_week_num = static_cast<boost::date_time::nth_kday_of_month<boost::gregorian::date>::week_num>;
 
     duration std_off (0, regtzi.StandardBias - regtzi.Bias, 0);
     duration dlt_off (0, regtzi.DaylightBias, 0);
@@ -126,15 +130,14 @@ zone_from_regtzi (const RegTZI& regtzi, time_zone_names names)
 			 regtzi.StandardDate.wSecond);
     duration end_time (regtzi.DaylightDate.wHour, regtzi.DaylightDate.wMinute,
 		       regtzi.DaylightDate.wSecond);
-    boost::local_time::dst_adjustment_offsets offsets (dlt_off, start_time,
-						       end_time);
-    auto std_week_num = static_cast<boost::date_time::nth_kday_of_month<boost::gregorian::date>::week_num>(regtzi.StandardDate.wDay);
-    auto dlt_week_num = static_cast<boost::date_time::nth_kday_of_month<boost::gregorian::date>::week_num>(regtzi.DaylightDate.wDay);
+    dst_offsets offsets (dlt_off, start_time, end_time);
+    auto std_week_num = make_week_num(regtzi.StandardDate.wDay);
+    auto dlt_week_num = make_week_num(regtzi.DaylightDate.wDay);
     ndate start (std_week_num, regtzi.StandardDate.wDayOfWeek,
 		 regtzi.StandardDate.wMonth);
     ndate end(dlt_week_num, regtzi.DaylightDate.wDayOfWeek,
 	      regtzi.DaylightDate.wMonth);
-    boost::local_time::dst_calc_rule_ptr dates(new nth_day_rule (start, end));
+    calc_rule_ptr dates(new nth_day_rule (start, end));
     return TZ_Ptr(new time_zone(names, std_off, offsets, dates));
 }
 
@@ -210,6 +213,8 @@ TimeZoneProvider::load_windows_classic_tz (HKEY key, time_zone_names names)
     RegCloseKey (key);
 }
 
+TimeZoneProvider::TimeZoneProvider ()  : TimeZoneProvider ("")) {}
+
 TimeZoneProvider::TimeZoneProvider (const std::string& identifier) :
     zone_vector ()
 {
@@ -241,14 +246,341 @@ TimeZoneProvider::TimeZoneProvider (const std::string& identifier) :
     else
 	throw std::invalid_argument ("No data for TZ " + key_name);
 }
-#else
+#elif PLATFORM(POSIX)
 using std::to_string;
-TimeZoneProvider::TimeZoneProvider(const std::string& tzname)
+#include <istream>
+#include <cstdlib>
+
+using boost::posix_time::ptime;;
+//To enable using Transition with different meanings for IANA files
+//and for DSTRules.
+namespace IANAParser
+{
+    struct TZHead
+    {
+	char magic[4];
+	char version;
+	uint8_t reserved[15];
+	uint8_t ttisgmtcnt[4];
+	uint8_t ttisstdcnt[4];
+	uint8_t leapcnt[4];
+	uint8_t timecnt[4];
+	uint8_t typecnt[4];
+	uint8_t charcnt[4];
+    };
+
+    struct TTInfo
+    {
+	uint32_t gmtoff;
+	uint8_t isdst;
+	uint8_t abbrind;
+    };
+
+    struct TZInfo
+    {
+	TTInfo info;
+	std::string name;
+	bool isstd;
+	bool isgmt;
+    };
+
+    struct Transition
+    {
+	time_t timestamp;
+	uint8_t index;
+    };
+
+    static std::ifstream
+    find_tz_file(const std::string& name)
+    {
+	if (name.empty())
+	    return std::ifstream("/etc/localtime", std::ios::binary);
+
+	std::string tzname = name;
+//POSIX specifies that that identifier should begin with ':', but we
+//should be liberal. If it's there, it's not part of the filename.
+	if (tzname[0] == ':')
+	    tzname.erase(tzname.begin());
+	if (tzname[0] == '/') //Absolute filename
+	    return std::ifstream(tzname, std::ios::binary);
+
+	std::string tzdir = std::getenv("TZDIR");
+	if (tzdir.empty())
+	    tzdir = "/usr/share/zoneinfo";
+//Note that we're not checking the filename.
+	return std::ifstream(std::move(tzdir + "/" + tzname), std::ios::binary);
+    }
+
+  struct IANAParser
+    {
+	IANAParser(const std::string& name) : IANAParser(find_tz_file(name)) {}
+	IANAParser(std::ifstream ifs);
+	std::vector<Transition>transitions;
+	std::vector<TZInfo>tzinfo;
+	int last_year;
+    };
+
+    IANAParser::IANAParser(std::ifstream ifs)
+    {
+	if (! ifs)
+	    throw std::invalid_argument("The timezone string failed to resolve to a valid filename");
+
+	TZHead tzh;
+	auto timesize = sizeof(int32_t);
+	last_year = 2037; //Constrained by 32-bit time_t.
+	ifs.get(reinterpret_cast<char*>(&tzh), sizeof(tzh));
+	auto time_count = *reinterpret_cast<uint32_t*>(tzh.timecnt);
+	auto type_count = *reinterpret_cast<uint32_t*>(tzh.typecnt);
+	auto char_count = *reinterpret_cast<uint32_t*>(tzh.charcnt);
+	auto isgmt_count = *reinterpret_cast<uint32_t*>(tzh.ttisgmtcnt);
+	auto isstd_count = *reinterpret_cast<uint32_t*>(tzh.ttisstdcnt);
+	auto leap_count = *reinterpret_cast<uint32_t*>(tzh.leapcnt);
+	if (tzh.version == '2' && sizeof(time_t) == sizeof(int64_t))
+	{
+	    ifs.seekg(sizeof(tzh) +
+		     timesize + sizeof(uint8_t) * time_count +
+		     sizeof(TTInfo) * type_count +
+		     sizeof(char) * char_count +
+		     sizeof(uint8_t) * isgmt_count +
+		     sizeof(uint8_t) * isstd_count +
+		     2 * timesize * leap_count +
+		     sizeof(tzh));
+	    timesize = sizeof(int64_t);
+	    //This might change at some point in the probably very distant future.
+	    last_year = 2499;
+	}
+
+	transitions.reserve(time_count);
+	tzinfo.reserve(type_count);
+
+	for(auto tr : transitions)
+	{
+	    uint8_t time[sizeof(time_t)];
+	    ifs.get(reinterpret_cast<char*>(time), timesize);
+	    tr.timestamp = *reinterpret_cast<time_t*>(time);
+	}
+
+	for (auto tr : transitions)
+	{
+	    char idx;
+	    ifs.get(idx);
+	    tr.index = std::move(idx);
+	}
+
+	for(auto tz : tzinfo)
+	{
+	    char infochars[sizeof(TTInfo)];
+	    ifs.get(infochars, sizeof(TTInfo));
+	    tz.info = *reinterpret_cast<TTInfo*>(infochars);
+	}
+
+	try
+	{
+	    std::unique_ptr<char[]>abbrev(new char[char_count]);
+	    ifs.get(abbrev.get(), char_count);
+
+	    for (auto tz : tzinfo)
+	    {
+		tz.name = abbrev[tz.info.abbrind];
+	    }
+	}
+	catch(std::bad_alloc)
+	{
+	    ;
+	}
+
+	if (isstd_count == type_count)
+	{
+	    char foo;
+	    for (auto tz : tzinfo)
+	    {
+		ifs.get(foo);
+		tz.isstd = foo != '\0';
+	    }
+	    for (auto tz : tzinfo)
+	    {
+		ifs.get(foo);
+		tz.isgmt = foo != '\0';
+	    }
+	}
+    }
+}
+
+namespace DSTRule
 {
+    using gregorian_date = boost::gregorian::date;
+    using IANAParser::TZInfo;
+    using ndate = boost::gregorian::nth_day_of_the_week_in_month;
+    using week_num =
+	boost::date_time::nth_kday_of_month<boost::gregorian::date>::week_num;
+
+    struct Transition
+    {
+	Transition() : month(0), dow(0), week(static_cast<week_num>(0)) {}
+	Transition(gregorian_date date);
+	bool operator==(const Transition& rhs);
+	ndate get();
+	boost::gregorian::greg_month month;
+	boost::gregorian::greg_weekday dow;
+	week_num week;
+    };
+
+    Transition::Transition(gregorian_date date) :
+	month(date.month()), dow(date.day_of_week()),
+	week(static_cast<week_num>((7 + date.day() - date.day_of_week()) / 7 + 1))
+    {}
+
+    bool
+    Transition::operator==(const Transition& rhs)
+    {
+	return (month == rhs.month && dow == rhs.dow && week == rhs.week);
+    }
+
+    ndate
+    Transition::get()
+    {
+	return ndate(week, dow, month);
+    }
+
+    struct DSTRule
+    {
+	DSTRule();
+	DSTRule(const TZInfo& info1, const TZInfo& info2,
+		ptime date1, ptime date2);
+	bool operator==(const DSTRule& rhs) const noexcept;
+	bool operator!=(const DSTRule& rhs) const noexcept;
+	Transition to_std;
+	Transition to_dst;
+	duration to_std_time;
+	duration to_dst_time;
+	const TZInfo& std_info;
+	const TZInfo& dst_info;
+    };
+
+    DSTRule::DSTRule() : to_std(), to_dst(), to_std_time {}, to_dst_time {},
+	std_info (), dst_info () {};
+
+    DSTRule::DSTRule (const TZInfo& info1, const TZInfo& info2,
+		      ptime date1, ptime date2) :
+	to_std(date1.date()), to_dst(date2.date()),
+	to_std_time(date1.time_of_day()), to_dst_time(date2.time_of_day()),
+	std_info(info1), dst_info(info2)
+    {
+	if (info1.info.isdst == info2.info.isdst)
+	    throw(std::invalid_argument("Both infos have the same dst value."));
+	if (info1.info.isdst && !info2.info.isdst)
+	{
+	    std::swap(to_std, to_dst);
+	    std::swap(to_std_time, to_dst_time);
+	    std::swap(std_info, dst_info);
+	}
+	if (dst_info.isgmt) to_dst_time += boost::posix_time::seconds(dst_info.info.gmtoff);
+	if (std_info.isgmt) to_std_time += boost::posix_time::seconds(std_info.info.gmtoff);
+
+    }
+
+    bool
+    DSTRule::operator==(const DSTRule& rhs) const noexcept
+    {
+	return (to_std == rhs.to_std &&
+		to_dst == rhs.to_dst &&
+		to_std_time == rhs.to_std_time &&
+		to_dst_time == rhs.to_dst_time &&
+		&std_info == &rhs.std_info &&
+		&dst_info == &rhs.dst_info);
+    }
+
+    bool
+    DSTRule::operator!=(const DSTRule& rhs) const noexcept
+    {
+	return ! operator==(rhs);
+    }
+}
+
+static TZ_Entry
+zone_no_dst(int year, IANAParser::TZInfo std_info)
+{
+    using boost::local_time::dst_calc_rule;
+
+    time_zone_names names(std_info.name, std_info.name, nullptr, nullptr);
+    duration std_off(0, 0, std_info.info.gmtoff);
+    dst_offsets offsets(NULL);
+    TZ_Ptr tz(new time_zone(names, std_off, offsets, dst_calc_rule));
+    return std::make_pair(year, tz);
+}
+
+static TZ_Entry
+zone_from_rule(int year, DSTRule::DSTRule rule)
+{
+    using boost::gregorian::partial_date;
+    using boost::local_time::partial_date_dst_rule;
+    using nth_day_rule =
+	boost::local_time::nth_day_of_the_week_in_month_dst_rule;
+
+    time_zone_names names(rule.std_info.name, rule.std_info.name,
+			  rule.dst_info.name, rule.dst_info.name);
+    duration std_off(0, 0, rule.std_info.info.gmtoff);
+    duration dlt_off(0, 0,
+		     rule.dst_info.info.gmtoff - rule.std_info.info.gmtoff);
+    dst_offsets offsets(dlt_off, rule.to_dst_time, rule.to_std_time);
+    calc_rule_ptr dates(new nth_day_rule(rule.to_dst.get(), rule.to_std.get()));
+    TZ_Ptr tz(new time_zone(names, std_off, offsets, dates));
+    return std::make_pair(year, tz);
 }
 
+TimeZoneProvider::TimeZoneProvider(const std::string& tzname) :  zone_vector {}
+{
+    IANAParser::IANAParser parser(tzname);
+    auto last_info = std::find_if(parser.tzinfo,
+				  [](IANAParser::TZInfo& tz)
+				  {return !tz.info.isdst;});
+    auto last_time = ptime();
+    DSTRule::DSTRule last_rule;
+    for (auto txi = parser.transitions.begin();
+	 txi != parser.transitions.end(); ++txi)
+    {
+	auto this_info = parser.tzinfo[txi->index];
+	auto this_time = boost::posix_time::from_time_t(txi->timestamp);
+	auto this_year = this_time.date().year();
+	auto last_year = last_time.date().year();
+	//Initial case, gap in transitions > 1 year, non-dst zone
+	//change. In the last case the exact date of the change will be
+	//wrong because boost::local_date::timezone isn't able to
+	//represent it. For GnuCash's purposes this isn't likely to be
+	//important as the last time this sort of transition happened
+	//was 1946, but we have to handle the case in order to parse
+	//the tz file.
+	if (last_time.is_not_a_date_time() ||
+	    this_year - last_year > 1 ||
+	    last_info.info.isdst == this_info.info.isdst)
+	{
+	    zone_vector.push_back(zone_no_dst(this_year, last_info));
+	}
+
+	else
+	{
+	    DSTRule::DSTRule new_rule(last_info, this_info,
+			     last_time.date(), this_time.date());
+	    if (new_rule != last_rule)
+	    {
+		last_rule = new_rule;
+		zone_vector.push_back(zone_from_rule (this_time.date().year(),
+						      new_rule));
+	    }
+	}
+	last_time = this_time;
+	last_info = this_info;
+    }
+
+    if (last_time.is_not_a_date_time() ||
+	last_time.date().year() < parser.last_year)
+	zone_vector.push_back(zone_no_dst(9999, last_info));
+    else //Last DST rule forever after.
+	zone_vector.push_back(zone_from_rule(9999, last_rule));
+}
 #endif
 
+
 TZ_Ptr
 TimeZoneProvider::get(int year)
 {

commit 5983df7ad304055aa8365af6001ea9311d2d583d
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Jan 18 12:33:47 2015 -0800

    Windows implementation of TimeZoneProvider.

diff --git a/src/libqof/qof/Makefile.am b/src/libqof/qof/Makefile.am
index 0c37dfd..7744427 100644
--- a/src/libqof/qof/Makefile.am
+++ b/src/libqof/qof/Makefile.am
@@ -6,8 +6,7 @@ lib_LTLIBRARIES = libgnc-qof.la
 
 libgnc_qof_la_LDFLAGS= \
 	-version-info \
-	$(LIBQOF_LIBRARY_VERSION) \
-	$(BOOST_LDFLAGS)
+	$(LIBQOF_LIBRARY_VERSION)
 
 libgnc_qof_common_libs =  \
   $(GLIB_LIBS) \
@@ -27,6 +26,7 @@ libgnc_qof_la_SOURCES =  \
    gnc-int128.cpp      \
    gnc-numeric.cpp     \
    gnc-rational.cpp    \
+   gnc-timezone.cpp     \
    guid.cpp            \
    kvp-util.cpp        \
    kvp_frame.cpp       \
@@ -53,6 +53,7 @@ qofinclude_HEADERS = \
    gnc-date.h        \
    gnc-numeric.h     \
    gnc-rational.hpp  \
+   gnc-timezone.hpp  \
    guid.h            \
    kvp-util-p.h      \
    kvp-util.h        \
diff --git a/src/libqof/qof/gnc-timezone.cpp b/src/libqof/qof/gnc-timezone.cpp
new file mode 100644
index 0000000..4b07894
--- /dev/null
+++ b/src/libqof/qof/gnc-timezone.cpp
@@ -0,0 +1,261 @@
+/********************************************************************\
+ * gnc-timezone.cpp - Retrieve timezone information from OS.        *
+ * Copyright 2014 John Ralls <jralls at ceridwen.us>                   *
+ * Based on work done with Arnel Borja for GLib's gtimezone in 2012.*
+ * This program is free software; you can redistribute it and/or    *
+ * modify it under the terms of the GNU General Public License as   *
+ * published by the Free Software Foundation; either version 2 of   *
+ * the License, or (at your option) any later version.              *
+ *                                                                  *
+ * This program 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 General Public License for more details.                     *
+ *                                                                  *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact:                        *
+ *                                                                  *
+ * Free Software Foundation           Voice:  +1-617-542-5942       *
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
+\********************************************************************/
+
+#include "gnc-timezone.hpp"
+
+#include <string>
+#include <cstdint>
+#include <ostream>
+#include <boost/date_time/gregorian/gregorian.hpp>
+using namespace gnc::date;
+
+#if PLATFORM(WINDOWS)
+/* libstdc++ to_string is broken on MinGW with no real interest in fixing it.
+ * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52015
+ */
+#if ! COMPILER(MINGW)
+using std::to_string;
+#else
+template<typename T> inline std::string to_string(T num);
+
+template<>
+inline std::string
+to_string<unsigned int>(unsigned int num)
+{
+    constexpr unsigned int numchars = sizeof num * 3 + 1;
+    char buf [numchars] {};
+    snprintf (buf, numchars, "%u", num);
+    return std::string(buf);
+}
+
+template<>
+inline std::string
+to_string<int>(int num)
+{
+    constexpr unsigned int numchars = sizeof num * 3 + 1;
+    char buf [numchars];
+    snprintf (buf, numchars, "%d", num);
+    return std::string(buf);
+}
+#endif
+
+static std::string
+windows_default_tzname (void)
+{
+  const char *subkey =
+    "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation";
+  constexpr size_t keysize {128};
+  HKEY key;
+  char key_name[keysize] {};
+  unsigned long tz_keysize = keysize;
+  if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, subkey, 0,
+                     KEY_QUERY_VALUE, &key) == ERROR_SUCCESS)
+    {
+	if (RegQueryValueExA (key, "TimeZoneKeyName", nullptr, nullptr,
+                                (LPBYTE)key_name, &tz_keysize) != ERROR_SUCCESS)
+	{
+	    memset (key_name, 0, tz_keysize);
+        }
+      RegCloseKey (key);
+    }
+  return std::string(key_name);
+}
+
+typedef   struct
+{
+  LONG Bias;
+  LONG StandardBias;
+  LONG DaylightBias;
+  SYSTEMTIME StandardDate;
+  SYSTEMTIME DaylightDate;
+} RegTZI;
+
+static time_zone_names
+windows_tz_names (HKEY key)
+{
+    /* The weird sizeof arg is because C++ won't find a type's
+     * element, just an object's.
+     */
+    constexpr auto s_size = sizeof (((TIME_ZONE_INFORMATION*)0)->StandardName);
+    char std_name[s_size];
+    unsigned long size = s_size;
+    if (RegQueryValueExA (key, "Std", NULL, NULL,
+			  (LPBYTE)&(std_name), &size) != ERROR_SUCCESS)
+	throw std::invalid_argument ("Registry contains no standard name.");
+
+    constexpr auto d_size = sizeof (((TIME_ZONE_INFORMATION*)0)->DaylightName);
+    char dlt_name[d_size];
+    size = d_size;
+    if (RegQueryValueExA (key, "Dlt", NULL, NULL,
+			  (LPBYTE)&(dlt_name), &size) != ERROR_SUCCESS)
+	throw std::invalid_argument ("Registry contains no daylight name.");
+
+    return time_zone_names (std_name, std_name, dlt_name, dlt_name);
+}
+
+static TZ_Ptr
+zone_from_regtzi (const RegTZI& regtzi, time_zone_names names)
+{
+    using duration = boost::posix_time::time_duration;
+    using ndate = boost::gregorian::nth_day_of_the_week_in_month;
+    using nth_day_rule = boost::local_time::nth_day_of_the_week_in_month_dst_rule;
+    using time_zone = boost::local_time::custom_time_zone;
+
+    duration std_off (0, regtzi.StandardBias - regtzi.Bias, 0);
+    duration dlt_off (0, regtzi.DaylightBias, 0);
+    duration start_time (regtzi.StandardDate.wHour, regtzi.StandardDate.wMinute,
+			 regtzi.StandardDate.wSecond);
+    duration end_time (regtzi.DaylightDate.wHour, regtzi.DaylightDate.wMinute,
+		       regtzi.DaylightDate.wSecond);
+    boost::local_time::dst_adjustment_offsets offsets (dlt_off, start_time,
+						       end_time);
+    auto std_week_num = static_cast<boost::date_time::nth_kday_of_month<boost::gregorian::date>::week_num>(regtzi.StandardDate.wDay);
+    auto dlt_week_num = static_cast<boost::date_time::nth_kday_of_month<boost::gregorian::date>::week_num>(regtzi.DaylightDate.wDay);
+    ndate start (std_week_num, regtzi.StandardDate.wDayOfWeek,
+		 regtzi.StandardDate.wMonth);
+    ndate end(dlt_week_num, regtzi.DaylightDate.wDayOfWeek,
+	      regtzi.DaylightDate.wMonth);
+    boost::local_time::dst_calc_rule_ptr dates(new nth_day_rule (start, end));
+    return TZ_Ptr(new time_zone(names, std_off, offsets, dates));
+}
+
+void
+TimeZoneProvider::load_windows_dynamic_tz (HKEY key, time_zone_names names)
+{
+    DWORD first, last;
+
+    try
+    {
+	unsigned long size = sizeof first;
+	if (RegQueryValueExA (key, "FirstEntry", NULL, NULL,
+			      (LPBYTE) &first, &size) != ERROR_SUCCESS)
+	    throw std::invalid_argument ("No first entry.");
+
+	size = sizeof last;
+	if (RegQueryValueExA (key, "LastEntry", NULL, NULL,
+			      (LPBYTE) &last, &size) != ERROR_SUCCESS)
+	    throw std::invalid_argument ("No last entry.");
+
+	TZ_Ptr tz {};
+	for (unsigned int year = first; year <= last; year++)
+	{
+	    auto s = to_string(year);
+	    auto ystr = s.c_str();
+	    RegTZI regtzi {};
+	    size = sizeof regtzi;
+	    auto err_val = RegQueryValueExA (key, ystr, NULL, NULL,
+					     (LPBYTE) &regtzi, &size);
+	    if (err_val != ERROR_SUCCESS)
+	    {
+		break;
+	    }
+	    tz = zone_from_regtzi (regtzi, names);
+	    if (year == first)
+		zone_vector.push_back (std::make_pair(0, tz));
+	    zone_vector.push_back (std::make_pair(year, tz));
+	}
+	zone_vector.push_back (std::make_pair(9999, tz));
+   }
+    catch (std::invalid_argument)
+    {
+	RegCloseKey (key);
+	throw;
+    }
+    catch (std::bad_alloc)
+    {
+	RegCloseKey (key);
+	throw;
+    }
+    RegCloseKey (key);
+}
+
+void
+TimeZoneProvider::load_windows_classic_tz (HKEY key, time_zone_names names)
+{
+    RegTZI regtzi {};
+    unsigned long size = sizeof regtzi;
+    try
+    {
+	if (RegQueryValueExA (key, "TZI", NULL, NULL,
+			      (LPBYTE) &regtzi, &size) == ERROR_SUCCESS)
+	{
+	    zone_vector.push_back(
+		std::make_pair(0, zone_from_regtzi (regtzi, names)));
+	}
+    }
+    catch (std::bad_alloc)
+    {
+	RegCloseKey (key);
+	throw;
+    }
+    RegCloseKey (key);
+}
+
+TimeZoneProvider::TimeZoneProvider (const std::string& identifier) :
+    zone_vector ()
+{
+    HKEY key;
+    const std::string reg_key =
+	"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\";
+
+    auto key_name = (identifier.empty() ? windows_default_tzname () :
+		     identifier);
+
+    if (key_name.empty())
+	throw std::invalid_argument ("No identifier or default tzname.");
+
+    std::string subkey = reg_key + key_name;
+    if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, subkey.c_str(), 0,
+		       KEY_QUERY_VALUE, &key) != ERROR_SUCCESS)
+	throw std::invalid_argument ("No TZ in registry named " + key_name);
+
+    time_zone_names names {windows_tz_names (key)};
+    RegCloseKey (key);
+
+    std::string subkey_dynamic = subkey + "\\Dynamic DST";
+    if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, subkey_dynamic.c_str(), 0,
+		       KEY_QUERY_VALUE, &key) == ERROR_SUCCESS)
+	this->load_windows_dynamic_tz (key, names);
+    else if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, subkey.c_str(), 0,
+			    KEY_QUERY_VALUE, &key) == ERROR_SUCCESS)
+	this->load_windows_classic_tz (key, names);
+    else
+	throw std::invalid_argument ("No data for TZ " + key_name);
+}
+#else
+using std::to_string;
+TimeZoneProvider::TimeZoneProvider(const std::string& tzname)
+{
+}
+
+#endif
+
+TZ_Ptr
+TimeZoneProvider::get(int year)
+{
+    auto iter = find_if(zone_vector.begin(), zone_vector.end(),
+			[=](TZ_Entry e) { return e.first >= year; });
+    if (iter == zone_vector.end())
+	throw std::out_of_range ("Year " + to_string(year) +
+				 " isn't covered by this time zone.");
+    return iter->second;
+}
diff --git a/src/libqof/qof/gnc-timezone.hpp b/src/libqof/qof/gnc-timezone.hpp
new file mode 100644
index 0000000..400f0c9
--- /dev/null
+++ b/src/libqof/qof/gnc-timezone.hpp
@@ -0,0 +1,66 @@
+/********************************************************************\
+ * gnc-timezone.cpp - Retrieve timezone information from OS.        *
+ * Copyright 2014 John Ralls <jralls at ceridwen.us>                   *
+ * Based on work done with Arnel Borja for GLib's gtimezone in 2012.*
+ * This program is free software; you can redistribute it and/or    *
+ * modify it under the terms of the GNU General Public License as   *
+ * published by the Free Software Foundation; either version 2 of   *
+ * the License, or (at your option) any later version.              *
+ *                                                                  *
+ * This program 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 General Public License for more details.                     *
+ *                                                                  *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact:                        *
+ *                                                                  *
+ * Free Software Foundation           Voice:  +1-617-542-5942       *
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
+\********************************************************************/
+
+#ifndef __GNC_TIMEZONE_HPP__
+#define __GNC_TIMEZONE_HPP__
+extern "C"
+{
+#include <platform.h>
+#if PLATFORM(WINDOWS)
+#include <windows.h>
+#endif
+}
+
+#define BOOST_ERROR_CODE_HEADER_ONLY
+#include <boost/date_time/local_time/local_time.hpp>
+
+namespace gnc
+{
+    namespace date
+    {}
+}// Move these later
+using TZ = boost::local_time::time_zone;
+using TZ_Ptr = boost::local_time::time_zone_ptr;
+using TZ_Entry = std::pair<int, TZ_Ptr>;
+using TZ_Vector = std::vector<TZ_Entry>;
+using time_zone_names = boost::local_time::time_zone_names;
+
+class TimeZoneProvider
+{
+public:
+    // The default constructor provides the time zone for the current locale
+    TimeZoneProvider() : TimeZoneProvider (static_cast<std::string>("")) {}
+    TimeZoneProvider(const std::string& tzname); //create a provider for a specified TZ.
+    TimeZoneProvider(const TimeZoneProvider&) = delete;
+    TimeZoneProvider(const TimeZoneProvider&&) = delete;
+    TimeZoneProvider operator=(const TimeZoneProvider&) = delete;
+    TimeZoneProvider operator=(const TimeZoneProvider&&) = delete;
+    TZ_Ptr get (int year);
+private:
+    TZ_Vector zone_vector;
+#if PLATFORM(WINDOWS)
+    void load_windows_dynamic_tz(HKEY, time_zone_names);
+    void load_windows_classic_tz(HKEY, time_zone_names);
+#endif
+};
+
+#endif //__GCN_TIMEZONE_HPP__
diff --git a/src/libqof/qof/test/gtest-gnc-timezone.cpp b/src/libqof/qof/test/gtest-gnc-timezone.cpp
index 11b6f6a..5696cd2 100644
--- a/src/libqof/qof/test/gtest-gnc-timezone.cpp
+++ b/src/libqof/qof/test/gtest-gnc-timezone.cpp
@@ -22,6 +22,7 @@
  *******************************************************************/
 
 #include <gtest/gtest.h>
+#include <string>
 #include "../gnc-timezone.hpp"
 
 TEST(gnc_timezone_constructors, test_default_constructor)

commit 45170bb5ebfc08e3fd9789e34c600d58c7886fa3
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Jan 4 16:30:02 2015 -0800

    Basic tests for TimeZoneProvider.

diff --git a/configure.ac b/configure.ac
index 889f815..ae6efd8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -372,12 +372,15 @@ update to latest  darwin])
   darwin*)
     platform=darwin
     AC_DEFINE(PLATFORM_OSX,1,[Running on OSX, either X11 or Quartz])
+    AC_DEFINE(GNC_PLATFORM_POSIX, 1, [POSIX-compliant OS])
+    AC_DEFINE(GNC_PLATFORM_DARWIN, 1, [Darwin-based OS])
     AC_MSG_RESULT($platform)
     AC_MSG_CHECKING(For GDK-Quartz)
     platform=osx
     _gdk_tgt=`$PKG_CONFIG --variable=target gdk-2.0`
     if test "x$_gdk_tgt" = xquartz; then
       platform=darwin/quartz
+      AC_DEFINE(GNC_PLATFORM_COCOA, 1, [Cocoa/Nexstep/GnuStep framework])
       AC_MSG_RESULT(yes)
       AC_DEFINE(GDK_QUARTZ,,[Using GDK Quartz (not X11)])
       PKG_CHECK_MODULES([GTK_MAC], gtk-mac-integration-gtk2,
@@ -402,6 +405,7 @@ update to latest  darwin])
   mingw*|cygwin*)
     platform=win32
     AC_MSG_RESULT($platform)
+    AC_DEFINE(GNC_PLATFORM_WINDOWS, 1, [Microsoft Windows OS])
     LT_PROG_RC
 
     AC_MSG_CHECKING(for native win32)
@@ -443,6 +447,7 @@ update to latest  darwin])
 
   *)
     platform=linux/other
+    AC_DEFINE(GNC_PLATFORM_POSIX, 1, [POSIX-compliant OS])
     AC_MSG_RESULT($platform)
     ;;
 esac
diff --git a/src/libqof/qof/test/Makefile.am b/src/libqof/qof/test/Makefile.am
index 05174d6..6738fe1 100644
--- a/src/libqof/qof/test/Makefile.am
+++ b/src/libqof/qof/test/Makefile.am
@@ -41,8 +41,8 @@ test_kvp_value_SOURCES = \
 test_kvp_value_LDADD = \
 	$(top_builddir)/$(MODULEPATH)/libgnc-qof.la \
          $(GLIB_LIBS) \
-	$(GTEST_LIBS) \
 	$(BOOST_LDFLAGS)
+
 if !GOOGLE_TEST_LIBS
 nodist_test_kvp_value_SOURCES = \
         ${GTEST_SRC}/src/gtest_main.cc
@@ -52,28 +52,39 @@ endif
 test_kvp_value_CPPFLAGS = \
     -I$(GTEST_HEADERS) \
     -I$(top_srcdir)/$(MODULEPATH) \
-    $(BOOST_CPPFLAGS) \
-    $(GLIB_CFLAGS)
+    $(BOOST_CPPFLAGS)
 
 check_PROGRAMS += test-kvp-value
 
 test_gnc_int128_SOURCES = \
         $(top_srcdir)/${MODULEPATH}/gnc-int128.cpp \
         gtest-gnc-int128.cpp
-test_gnc_int128_CPPFLAGS = \
-        -I${GTEST_HEADERS} \
-        ${GLIB_CFLAGS}
+test_gnc_int128_CPPFLAGS = -I${GTEST_HEADERS}
+
 
-test_gnc_int128_LDADD = \
-        ${GLIB_LIBS} \
-	$(GTEST_LIBS)
+test_gnc_int128_LDADD = $(GTEST_LIBS)
 if !GOOGLE_TEST_LIBS
 nodist_test_gnc_int128_SOURCES = \
         ${GTEST_SRC}/src/gtest_main.cc
 test_gnc_int128_LDADD += $(top_builddir)/src/test-core/libgtest.a
 endif
-
 check_PROGRAMS += test-gnc-int128
+
+test_gnc_timezone_SOURCES = \
+        $(top_srcdir)/${MODULEPATH}/gnc-timezone.cpp \
+        gtest-gnc-timezone.cpp
+
+test_gnc_timezone_CPPFLAGS = \
+        -I${GTEST_HEADERS} \
+	-I${top_srcdir}/src \
+	$(BOOST_CPPFLAGS)
+test_gnc_timezone_LDADD = $(GTEST_LIBS)
+if !GOOGLE_TEST_LIBS
+nodist_test_gnc_timezone_SOURCES = \
+        ${GTEST_SRC}/src/gtest_main.cc
+test_gnc_timezone_LDADD += $(top_builddir)/src/test-core/libgtest.a
+endif
+check_PROGRAMS += test-gnc-timezone
 endif
 
 test_qofdir = ${GNC_LIBEXECDIR}/${MODULEPATH}/test
diff --git a/src/libqof/qof/test/gtest-gnc-timezone.cpp b/src/libqof/qof/test/gtest-gnc-timezone.cpp
new file mode 100644
index 0000000..11b6f6a
--- /dev/null
+++ b/src/libqof/qof/test/gtest-gnc-timezone.cpp
@@ -0,0 +1,53 @@
+/********************************************************************
+ * Gtest-gnc-int128.cpp -- unit tests for the GncInt128 class       *
+ * Copyright (C) 2014 John Ralls <jralls at ceridwen.us>               *
+ *                                                                  *
+ * This program is free software; you can redistribute it and/or    *
+ * modify it under the terms of the GNU General Public License as   *
+ * published by the Free Software Foundation; either version 2 of   *
+ * the License, or (at your option) any later version.              *
+ *                                                                  *
+ * This program 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 General Public License for more details.                     *
+ *                                                                  *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact:                        *
+ *                                                                  *
+ * Free Software Foundation           Voice:  +1-617-542-5942       *
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
+ *                                                                  *
+ *******************************************************************/
+
+#include <gtest/gtest.h>
+#include "../gnc-timezone.hpp"
+
+TEST(gnc_timezone_constructors, test_default_constructor)
+{
+    TimeZoneProvider tzp {};
+    EXPECT_NO_THROW (tzp.get(2014));
+    TZ_Ptr tz = tzp.get (2014);
+
+//Can't really test anything explicit, we don't know what to expect
+//from the default TZ.
+    EXPECT_FALSE(tz->std_zone_abbrev().empty());
+}
+
+TEST(gnc_timezone_constructors, test_pacific_time_constructor)
+{
+    TimeZoneProvider tzp ("Pacific Standard Time");
+    EXPECT_NO_THROW (tzp.get(2006));
+    TZ_Ptr tz = tzp.get (2006);
+
+    EXPECT_FALSE(tz->std_zone_abbrev().empty());
+    EXPECT_TRUE(tz->std_zone_abbrev() == "Pacific Standard Time");
+    EXPECT_TRUE(tz->base_utc_offset().hours() == -8);
+}
+
+TEST(gnc_timezone_constructors, test_bogus_time_constructor)
+{
+    EXPECT_THROW (TimeZoneProvider tzp ("New York Standard Time"),
+		  std::invalid_argument);
+}



Summary of changes:
 configure.ac                                       |    7 +-
 src/backend/sql/gnc-backend-sql.c                  |   11 +-
 src/backend/sql/test/utest-gnc-backend-sql.c       |   41 +-
 src/backend/xml/sixtp-dom-generators.c             |   15 +-
 src/core-utils/gnc-gdate-utils.c                   |    9 +-
 src/engine/Transaction.c                           |   10 +-
 src/engine/gncBillTerm.c                           |    4 +-
 src/engine/test-core/test-engine-stuff.c           |   15 +-
 src/engine/test/test-date.c                        |    8 +-
 src/gnc-module/test/test-dynload.c                 |    2 +-
 src/gnome-utils/gnc-main-window.c                  |   22 +-
 src/import-export/aqb/gnc-ab-utils.c               |    2 +-
 .../aqb/test/file-book-hbcislot.gnucash            |    2 +-
 src/libqof/qof/Makefile.am                         |    8 +-
 src/libqof/qof/gnc-date-p.h                        |   10 +-
 src/libqof/qof/gnc-date.cpp                        |  507 +++-----
 src/libqof/qof/gnc-date.h                          |   46 +-
 src/libqof/qof/gnc-datetime.cpp                    |  284 +++++
 src/libqof/qof/gnc-datetime.hpp                    |  157 +++
 src/libqof/qof/gnc-timezone.cpp                    |  615 +++++++++
 src/libqof/qof/gnc-timezone.hpp                    |   66 +
 src/libqof/qof/test/Makefile.am                    |   51 +-
 src/libqof/qof/test/gtest-gnc-datetime.cpp         |   89 ++
 .../{qofevent-p.h => test/gtest-gnc-timezone.cpp}  |   54 +-
 src/libqof/qof/test/test-gnc-date.c                | 1341 ++++++++------------
 25 files changed, 2033 insertions(+), 1343 deletions(-)
 create mode 100644 src/libqof/qof/gnc-datetime.cpp
 create mode 100644 src/libqof/qof/gnc-datetime.hpp
 create mode 100644 src/libqof/qof/gnc-timezone.cpp
 create mode 100644 src/libqof/qof/gnc-timezone.hpp
 create mode 100644 src/libqof/qof/test/gtest-gnc-datetime.cpp
 copy src/libqof/qof/{qofevent-p.h => test/gtest-gnc-timezone.cpp} (53%)



More information about the gnucash-changes mailing list