gnucash unstable: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Sun Nov 26 12:39:05 EST 2017


Updated	 via  https://github.com/Gnucash/gnucash/commit/0afef080 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/13657ee1 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/0d8112bf (commit)
	 via  https://github.com/Gnucash/gnucash/commit/1674eb0b (commit)
	 via  https://github.com/Gnucash/gnucash/commit/af1bc450 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/23f25d74 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/ff76db28 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/742064ee (commit)
	from  https://github.com/Gnucash/gnucash/commit/50874d89 (commit)



commit 0afef080a7db47f1951cf1d49151546f7690de21
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Nov 25 16:33:30 2017 -0800

    Release 2.7.2

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8704645..f35ac5c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -13,14 +13,14 @@ ENABLE_TESTING()
 # Version number of gnucash
 SET (GNUCASH_MAJOR_VERSION 2)
 SET (GNUCASH_MINOR_VERSION 7)
-SET (GNUCASH_MICRO_VERSION 1)
+SET (GNUCASH_MICRO_VERSION 2)
 SET (GNUCASH_NANO_VERSION 0)
 SET (VERSION "${GNUCASH_MAJOR_VERSION}.${GNUCASH_MINOR_VERSION}.${GNUCASH_MICRO_VERSION}")
 SET (GNUCASH_LATEST_STABLE_SERIES 2.6)
 
 SET (PACKAGE gnucash)
 SET (PACKAGE_NAME GnuCash)
-SET (PACKAGE_VERSION 2.7.1)
+SET (PACKAGE_VERSION 2.7.2)
 SET (PACKAGE_BUGREPORT gnucash-devel at gnucash.org)
 SET (PACKAGE_TARNAME ${PACKAGE})
 SET (PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
diff --git a/ChangeLog b/ChangeLog
index e5a3ce6..acc933a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,378 @@
+2017-11-25 John Ralls 
+
+	* Release 2.7.2 (HEAD -> unstable)
+
+2017-11-25 John Ralls 
+
+	* Merge branch 'maint' into unstable
+
+2017-11-25 John Ralls 
+
+	* Correct GUILE_LOAD_COMPILE_PATH to include Guile's own modules as well as ours. (origin/unstable)
+
+2017-11-24 John Ralls 
+
+	* Correct quoting for SQL backends.
+
+2017-11-24 Geert Janssens 
+
+	* Merge branch 'gtk3-update8' of https://github.com/Bob-IT/gnucash into unstable
+
+2017-11-21 Jose Marino 
+
+	* report: fix default colors incorrectly set to transparent
+
+2017-11-23 John Ralls 
+
+	* Bug 784623 - GNUCash does not work with sql backend.
+
+2017-11-23 Rob Gowin 
+
+	* Bug 790620 - Failed to create file “/usr/share/glib-2.0/schemas/gschemas.compiled.XY789Y” (origin/maint, maint)
+
+2017-11-23 Robert Fewell 
+
+	* Fix some corrupted glade files
+
+2017-11-23 Robert Fewell 
+
+	* Change assistant-ab-initial.glade to gtk3.10 version
+
+2017-11-23 Robert Fewell 
+
+	* Replace deprecated GTK_STOCK_ macro identifiers
+
+2017-11-23 Robert Fewell 
+
+	* Change a couple of deprecated functions in gnc-html-webkit1.c
+
+2017-11-23 Robert Fewell 
+
+	* Control the toggle button width
+
+2017-11-23 Robert Fewell 
+
+	* Move the double line to be inside the cursor cell
+
+2017-11-23 Robert Fewell 
+
+	* If a font size is specified for the sheet, popup size may be wrong
+
+2017-11-23 Robert Fewell 
+
+	* Use previously created functions
+
+2017-11-23 Robert Fewell 
+
+	* Provide two functions for common code
+
+2017-11-23 Robert Fewell 
+
+	* This function doesn't do much and is only used for new account registers
+
+2017-11-23 Robert Fewell 
+
+	* Adjust the sheet to get its spacings from the item_edit CSS
+
+2017-11-23 Robert Fewell 
+
+	* Get the item_edit cell padding from CSS instead of defines
+
+2017-11-23 Robert Fewell 
+
+	* Replace the cell foreground and background colour handlers
+
+2017-11-01 Robert Fewell 
+
+	* Test the widget state to get the correct background colour.
+
+2017-11-21 John Ralls 
+
+	* Set GncSqlObjectBackend::m_version to the appropriate TABLE_VERSION.
+
+2017-11-21 John Ralls 
+
+	* Fix python build and test errors on Mac.
+
+2017-11-21 Geert Janssens 
+
+	* Revert "Merge branch 'gtk3-update8' of https://github.com/Bob-IT/gnucash into unstable"
+
+2017-11-21 Geert Janssens 
+
+	* Merge branch 'gtk3-update8' of https://github.com/Bob-IT/gnucash into unstable (origin/master, origin/HEAD)
+
+2017-11-21 Geert Janssens 
+
+	* Merge branch 'gtk3-update9' of https://github.com/Bob-IT/gnucash into unstable
+
+2017-11-19 John Ralls 
+
+	* Fix missing/misspelled files for distribution.
+
+2017-11-19 John Ralls 
+
+	* Bug 790550 - FTBFS: missing __init__.py
+
+2017-11-19 John Ralls 
+
+	* Fix distribution paths for resource files.
+
+2017-11-19 John Ralls 
+
+	* Fix bad string construction in adjust_sql_options.
+
+2017-11-19 John Ralls 
+
+	* A better way to handle MySQL's 0000-00-00 invalid date indicator.
+
+2017-11-19 John Ralls 
+
+	* Don't try to unref a NULL GDateTime*.
+
+2017-11-18 Geert Janssens 
+
+	* Fix a few travis failures (potentially uninitialized use)
+
+2017-11-18 Geert Janssens 
+
+	* Bug 736765 - Assign as payment... should re-populate the payment represented by the selected transaction if any
+
+2017-11-15 Geert Janssens 
+
+	* Bug 778692 - Assign as payment should work for employee expense vouchers
+
+2017-11-18 Geert Janssens 
+
+	* Assign as payment - when random transaction is selected, reset transaction description to owner
+
+2017-11-14 Geert Janssens 
+
+	* Assign as payment - refactor a few code blocks into separate functions
+
+2017-11-14 Geert Janssens 
+
+	* Assign as payment - Differentiate between new and existing payments for 'Assign as payment'
+
+2017-11-14 Geert Janssens 
+
+	* Assign as payment - offer possible payment splits to user in case there are multiple valid candidates for assignment
+
+2017-11-09 Geert Janssens 
+
+	* Bug 734865 - Assign as Payment... can silently 'unpay' a payed invoice
+
+2017-11-13 Geert Janssens 
+
+	* Add functions to retrieve a copy of splits of a certain type from business transactions
+
+2017-11-09 Geert Janssens 
+
+	* Inform the user when assign as payment can't be used
+
+2017-11-14 Geert Janssens 
+
+	* Mark unused function parameters as such in dialog-payment.c
+
+2017-11-15 fell 
+
+	* Add po/glossary/gnc-glossary.pot to .gitignore
+
+2017-11-15 fell 
+
+	* Fix a few encodings and Content-* tags in glossary
+
+2017-11-09 John Ralls 
+
+	* Bug 789608 - Compilation problems when linking libraries.
+
+2017-11-09 John Ralls 
+
+	* Merge branch 'maint' into unstable
+
+2017-11-09 John Ralls 
+
+	* Fix with_Python build in cmake.
+
+2017-11-09 Robert Fewell 
+
+	* Prevent the rename popup from appearing in the dense calendar
+
+2017-11-09 Robert Fewell 
+
+	* Dense calendar popup window of screen at bottom
+
+2017-11-09 Robert Fewell 
+
+	* Add a margin to the Date label
+
+2017-11-09 Robert Fewell 
+
+	* Don't re-populate dense calendar treeview on every mouse move
+
+2017-11-09 Robert Fewell 
+
+	* Save the screen dimensions on button click
+
+2017-11-09 Robert Fewell 
+
+	* If there are no marked days on Windows the dense calendar crashes
+
+2017-11-07 John Ralls 
+
+	* Bug 789928 - FTBFS with libdbi 0.9.0-5 on Debian
+
+2017-11-07 John Ralls 
+
+	* Merge J. Marino's 'fix-negative-colors' into unstable.
+
+2017-10-31 John Ralls 
+
+	* Convert shell-executed scheme tests to run directly from Guile.
+
+2017-11-02 John Ralls 
+
+	* Remove extraneous parameters from GNC_ADD_SCHEME_TARGETS
+
+2017-11-02 Jose Marino 
+
+	* report: fix negative colors in barcharts
+
+2017-11-01 Robert Fewell 
+
+	* Update the register for the change in RegisterColor enums
+
+2017-11-01 Robert Fewell 
+
+	* Change the split and entry models to reflect the colour changes
+
+2017-11-01 Robert Fewell 
+
+	* Reduce the RegisterColor enums so there is one for each type
+
+2017-11-01 Robert Fewell 
+
+	* Replace the cell foreground and background colour handlers
+
+2017-11-01 Robert Fewell 
+
+	* Test the widget state to get the correct background colour.
+
+2017-11-01 Robert Fewell 
+
+	* Change the look of the toggle button
+
+2017-11-01 Robert Fewell 
+
+	* Control the toggle button width
+
+2017-11-01 Robert Fewell 
+
+	* Move the double line to be inside the cursor cell
+
+2017-11-01 Robert Fewell 
+
+	* If a font size is specified for the sheet, popup size may be wrong
+
+2017-11-01 Robert Fewell 
+
+	* Use previously created functions
+
+2017-11-01 Robert Fewell 
+
+	* Provide two functions for common code
+
+2017-11-01 Robert Fewell 
+
+	* This function doesn't do much and is only used for new account registers
+
+2017-11-01 Robert Fewell 
+
+	* Adjust the sheet to get its spacings from the item_edit CSS
+
+2017-11-01 Robert Fewell 
+
+	* Get the item_edit cell padding from CSS instead of defines
+
+2017-10-31 John Ralls 
+
+	* Merge branch J. Marino's fix-report-colors into unstable (manjusri/master)
+
+2017-10-31 John Ralls 
+
+	* Merge J. Marino's 'fix/report-net-barchart' into unstable
+
+2017-10-18 Jose Marino 
+
+	* report/category-barchart: fix unit test to work with gnc-monetary
+
+2017-10-18 Jose Marino 
+
+	* report/category-barchart: calculate using gnc-monetary instead of double
+
+2017-10-18 Jose Marino 
+
+	* report/net-linechart: fix unit test to work with gnc-monetary
+
+2017-10-18 Jose Marino 
+
+	* report/net-linechart: calculate using gnc-monetary instead of double
+
+2017-10-17 Jose Marino 
+
+	* report/net-barchart: fix unit test to work with gnc-monetary
+
+2017-10-17 Jose Marino 
+
+	* report/net-barchart: default to list of zeros instead of empty list
+
+2017-10-13 Jose Marino 
+
+	* report/net-barchart: calculate using gnc-monetary instead of double
+
+2017-10-31 John Ralls 
+
+	* [Gwenhywfar] Use the new getpassword API only on the gwen5 branch.
+
+2017-10-31 John Ralls 
+
+	* Provide for report/report-system/test/test-extras to be built before other tests.
+
+2017-10-31 John Ralls 
+
+	* Ensure that report unit tests dependencies are built with  target.
+
+2017-10-31 John Ralls 
+
+	* Merge J. Marino's cashflow-barchart updates into unstable.
+
+2017-10-31 Jose Marino 
+
+	* report-test: move add-to-load-path to build system
+
+2017-10-30 John Ralls 
+
+	* Remove X11 error handler
+
+2017-10-31 Geert Janssens 
+
+	* Merge branch 'gtk3-update7' of https://github.com/Bob-IT/gnucash into unstable
+
+2017-10-02 Robert Fewell 
+
+	* Move the CSS files to a Gresource file
+
+2017-10-28 John Ralls 
+
+	* Release 2.7.1 (tag: 2.7.1)
+
+2017-10-29 John Ralls 
+
+	* Set relative path to icon file in Windows resource script.
+
 2017-10-28 John Ralls 
 
-	* Don't copy ChangeLog on a tarball build. (HEAD -> unstable, origin/unstable)
+	* Don't copy ChangeLog on a tarball build.
 
 2017-10-28 John Ralls 
 
@@ -10,6 +382,18 @@
 
 	* Set a parent window for the options dialogs.
 
+2017-10-27 Jose Marino 
+
+	* cashflow-barchart: split option "show money in/out" into two separate ones
+
+2017-10-27 Jose Marino 
+
+	* cashflow-barchart: delete unnecessary intermediate lists
+
+2017-10-27 Jose Marino 
+
+	* cashflow-barchart: use direct gnc-monetary math instead of collectors
+
 2017-10-27 John Ralls 
 
 	* Merge branch Christopher Lam's Transaction Report Improvements into unstable.
@@ -20,7 +404,7 @@
 
 2017-10-27 John Ralls 
 
-	* Merge Aaron Law's branch 'buildfix' to unstable. (origin/master, origin/HEAD)
+	* Merge Aaron Law's branch 'buildfix' to unstable.
 
 2017-10-27 John Ralls 
 
@@ -134,10 +518,34 @@
 
 	* Add fixed bugs for 2.7.0 to NEWS.
 
+2017-10-20 fell 
+
+	* Add a bunch of translator comments and a few accelerators to glade files (manjusri/maint)
+
 2017-10-20 Geert Janssens 
 
 	* Remove configure option --enable-locale-specific-tax and make gnucash always behave as if it was set
 
+2017-10-20 fell 
+
+	* Add a bunch of translator comments to C files
+
+2017-10-20 fell 
+
+	* Improve type of bank accounts in SKR03
+
+2017-10-20 fell 
+
+	* Add "Assets & Liabilities", "Profit & Loss" to the glossary,
+
+2017-10-20 fell 
+
+	* Mayor overhaul of de.po
+
+2017-10-20 fell 
+
+	* Fix wiki link
+
 2017-10-19 Jose Marino 
 
 	* fix reconcile dialog always showing ending balance of zero
@@ -198,6 +606,26 @@
 
 	* Fix html temp-file URI.
 
+2017-10-13 fell 
+
+	* update de.po to commit f283437
+
+2017-10-12 Jose Marino 
+
+	* report: render linechart with requested line colors
+
+2017-10-12 Jose Marino 
+
+	* report: render piechart with requested colors
+
+2017-10-12 Jose Marino 
+
+	* report: render barchart with requested bar colors
+
+2017-10-11 fell 
+
+	* Merge branch 'maint' of https://github.com/DiMan/Gnucash into maint
+
 2017-10-11 fell 
 
 	* reapply commit 3cdac65 on the new dialog-ab-pref and remove obsolete section from dialog-ab.gade
@@ -206,6 +634,10 @@
 
 	* add new report: cashflow-barchart.scm
 
+2017-10-07 Di Mang 
+
+	* Adjustment of some Russian translations
+
 2017-10-06 fell 
 
 	* Merge branch 'maint' into unstable
@@ -244,7 +676,7 @@
 
 2017-10-02 fell 
 
-	* Readd the missing glade msgctx strings to ru.po (maint)
+	* Readd the missing glade msgctx strings to ru.po
 
 2017-10-02 fell 
 
@@ -444,7 +876,7 @@
 
 2017-09-26 Geert Janssens 
 
-	* Fix build failures if userdata_home exists but gnc_userdata_home  doesn't (master)
+	* Fix build failures if userdata_home exists but gnc_userdata_home  doesn't
 
 2017-09-26 Josep-Maria Prat 
 
@@ -528,7 +960,7 @@
 
 2017-09-16 John Ralls 
 
-	* Fix the fix from mac for test-userdata-dir.c
+	* Fix the fix from mac for test-userdata-dir.c (master)
 
 2017-09-16 John Ralls 
 
@@ -6610,7 +7042,3 @@
 
 	* Remove xaccSchedXactionGetInstanceAfter
 
-2016-01-02 fell 
-
-	* Add a missing gettext in plugin page owner tree
-
diff --git a/NEWS b/NEWS
index 87bcc6d..fa2b2b3 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,102 @@
 Version history:
 ------- -------
+2.7.2 - 26 November 2017
+
+    The Gnucash Development Team is pleased to release Gnucash 2.7.2,
+    the third release of an unstable series leading to Gnucash 2.8.0.
+
+    This release is UNSTABLE and SHOULD NOT BE USED in production.
+    See the KNOWN PROBLEMS list at the bottom of the announcement.
+
+    This release changes file locations, binding APIs, report options,
+    and can make your data file no longer compatible with previous
+    versions. See https://wiki.gnucash.org/wiki/UpdateNotes for
+    details.
+
+New Features For Users:
+    No new features this time, but a raft of fixes and improvements!
+
+The following bugs are fixed only in unstable/master:
+    Bug 734865 - Assign as Payment... can silently 'unpay' a payed invoice
+       * if the selected transaction is already linked to an existing
+         payment, the payment dialog will present this payment again
+         (same partner, post-to account, same selected document(s), same
+         amount, memo, and transfer account).
+       * if the selected transaction is not linked to an existing business
+         transaction the logic will make a best guess as to whether the
+         payment should be for a customer or vendor.
+       * in both situations if the existing transaction has multiple splits
+         that can be considered as transfer (or 'payment') splits the payment
+         dialog can't work with it (it can only deal with one transfer split).
+         In this case the user will be informed that only one valid transfer
+         split will be retained and the others ignored.
+       * the other thing the payment dialog can't handle are APAR type splits
+         that are not associated to a lot at all. In case of transactions not
+         part of a business transaction they will be silently ignored on the
+         assumptions these were manually entered transactions with the
+         intention to be linked to business transactions. On the other hand
+         if such a split is part of a transaction that is also linked to a
+         business payment already, a warning will be issued these splits will
+         be removed from the new payment.
+    Bug 778692 - Assign as payment should work for employee expense vouchers
+       * if gnucash can deduce a partner from the transaction
+         that partner will be proposed this works for all transactions
+         that are part of a business transaction already and will
+         correctly detect pre-existing customer, vendor and employee
+         payments
+       * if no partner can be deduced gnucash will assume the
+         transaction to be a vendor or customer payment based on
+         the sign
+       * in all cases the user can change the partner type in the
+         payment window that's presented to any of customer, vendor
+         or employee to correct gnucash' suggestion.
+    Bug 784623 - GNUCash does not work with sql backend.
+        Wherin the problem is that MySQL's TIMESTAMP has a date range of
+        1970-01-01 00:00:01 to 2038-01-19 03:14:07 and is unable to handle
+        time_t of 0. MySQL's TIMESTAMP also assumes that input is in the
+        server's timezone and adjusts it to UTC. GnuCash has already done
+        that conversion.
+    Bug 789608 - Compilation problems when linking libraries.
+    Bug 789928 - FTBFS with libdbi 0.9.0-5 on Debian.
+        This one required handling a new error condition.
+    Bug 790550 - FTBFS: missing __init__.py
+
+
+Other repairs not marked as bugs in git:
+
+    SQL parameter quoting is corrected in the backend so that only string
+    parameters are quoted. This caused trouble when trying to store SQL NULL;
+    the string 'NULL' is different from the value NULL.
+
+    SQL table versions weren't set consistently and a bogus version test could
+    cause some tables to be not loaded.
+
+    Better, more targeted handling of MySQL's penchant for setting
+    date-time fields to "0000-00-00 00:00:00" if it doesn't like the
+    input. This should be much less common thanks to fixing Bug
+    784623.
+
+    Major repairs to the "Dense Calendar" date selector.
+
+    Fix colors on graph reports so that the selections work and the defaults
+    are no longer transparent.
+
+    Two large batches of styling fixes for Gtk3 from Bob Fewell.
+
+    Fix the guile-compiled path in the environment file so that
+    GnuCash can start on Windows.
+
+    Convert the graphical reports to use GnuCash's rational numbers instead of
+    doubles for better accuracy.
+
+
+KNOWN PROBLEMS:
+
+    On Microsoft Windows starting the AQBanking Setup Wizard crashes GnuCash.
+
+    test-import-bayes built with autotools intermittently fails at
+    line 381, where the returned value is 1 instead of the expected 6.
+
 2.7.1 - 29 October 2017
 
     The Gnucash Development Team is pleased to release Gnucash 2.7.1,
diff --git a/configure.ac b/configure.ac
index a725f93..d1a680b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,7 +20,7 @@ dnl Process this file with autoconf to produce a configure script.
 
 # Autoconf initialization
 AC_PREREQ(2.60)
-AC_INIT([GnuCash], [2.7.1], [https://bugzilla.gnome.org/page.cgi?id=browse.html&product=GnuCash], , [http://www.gnucash.org/])
+AC_INIT([GnuCash], [2.7.2], [https://bugzilla.gnome.org/page.cgi?id=browse.html&product=GnuCash], , [http://www.gnucash.org/])
 AC_CONFIG_HEADERS(config.h)
 AC_CONFIG_SRCDIR(libgnucash/engine/Transaction.h)
 AC_CONFIG_MACRO_DIR([macros])

commit 13657ee1bb8f70db510b44c0d1b9e4843b2ee1eb
Merge: 50874d8 0d8112b
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Nov 25 15:35:24 2017 -0800

    Merge branch 'maint' into unstable

diff --cc .gitignore
index d668621,86b62c9..9db59d0
--- a/.gitignore
+++ b/.gitignore
@@@ -71,160 -76,175 +71,161 @@@ po/POTFILE
  po/POTFILES.in
  po/gnucash.pot
  po/stamp-it
+ po/glossary/gnc-glossary.pot
  py-compile
 -src/app-utils/gnucash
 -src/app-utils/sw_app_utils.py
 -src/app-utils/test/test-exp-parser
 -src/app-utils/test/test-link-module
 -src/app-utils/test/test-print-parse-amount
 -src/app-utils/test/test-print-queries
 -src/app-utils/test/test-scm-query-string
 -src/app-utils/test/test-sx
 -src/backend/dbi/test/test-dbi
 -src/backend/dbi/test/test-dbi-basic
 -src/backend/dbi/test/test-dbi-business
 -src/backend/dbi/test/test-load-backend
 -src/backend/sql/test/test-column-types
 -src/backend/sql/test/test-sqlbe
 -src/bin/gnucash-launcher
 -src/backend/xml/test/test-date-converting
 -src/backend/xml/test/test-dom-converters1
 -src/backend/xml/test/test-kvp-frames
 -src/backend/xml/test/test-load-backend
 -src/backend/xml/test/test-load-example-account
 -src/backend/xml/test/test-load-xml2
 -src/backend/xml/test/test-save-in-lang
 -src/backend/xml/test/test-string-converters
 -src/backend/xml/test/test-xml-account
 -src/backend/xml/test/test-xml-commodity
 -src/backend/xml/test/test-xml-pricedb
 -src/backend/xml/test/test-xml-transaction
 -src/backend/xml/test/test-xml2-is-file
 -src/bin/environment
 -src/bin/gnucash
 -src/bin/gnucash-bin
 -src/bin/gnucash-ddd
 -src/bin/gnucash-env
 -src/bin/gnucash-gdb
 -src/bin/gnucash-make-guids
 -src/bin/gnucash-setup-env
 -src/bin/gnucash-valgrind
 -src/bin/overrides/gnucash-build-env
 -src/bin/overrides/gnucash-env
 -src/bin/overrides/guile
 -src/bin/update-gnucash-gconf
 -src/business/business-core/gnucash
 -src/business/business-core/test/test-address
 -src/business/business-core/test/test-business
 -src/business/business-core/test/test-customer
 -src/business/business-core/test/test-employee
 -src/business/business-core/test/test-job
 -src/business/business-core/test/test-load-module
 -src/business/business-core/test/test-vendor
 -src/business/business-gnome/gnucash
 -src/business/business-reports/gnucash
 -src/business/business-utils/gnucash
 -src/business/dialog-tax-table/gnucash
 -src/calculation/test/test-link
 -src/core-utils/gnc-scm-info.h
 -src/core-utils/gnc-version.h
 -src/core-utils/gncla-dir.h
 -src/core-utils/gnucash
 -src/core-utils/sw_core_utils.py
 -src/core-utils/test/test-gnc-uri-utils
 -src/core-utils/test/test-resolve-file-path
 -src/doc/doxygen.cfg
 -src/doc/doxygen.log
 -src/doc/design/gnucash-design.info
 -src/doc/design/mdate-sh
 -src/doc/design/stamp-vti
 -src/doc/design/texinfo.tex
 -src/doc/design/version.texi
 -src/doc/html/
 -src/engine/gncla-dir.h
 -src/engine/gnucash
 -src/engine/iso-4217-currencies.c
 -src/engine/test/test-account-object
 -src/engine/test/test-book-merge
 -src/engine/test/test-commodities
 -src/engine/test/test-date
 -src/engine/test/test-group-vs-book
 -src/engine/test/test-guid
 -src/engine/test/test-link
 -src/engine/test/test-load-engine
 -src/engine/test/test-lots
 -src/engine/test/test-numeric
 -src/engine/test/test-object
 -src/engine/test/test-period
 -src/engine/test/test-query
 -src/engine/test/test-querynew
 -src/engine/test/test-recurrence
 -src/engine/test/test-recursive
 -src/engine/test/test-scm-query
 -src/engine/test/test-split-vs-account
 -src/engine/test/test-transaction-reversal
 -src/engine/test/test-transaction-voiding
 -src/engine/test/test-address
 -src/engine/test/test-business
 -src/engine/test/test-customer
 -src/engine/test/test-employee
 -src/engine/test/test-engine
 -src/engine/test/test-job
 -src/engine/test/test-vendor
 -src/gnc-module/gnucash
 -src/gnc-module/test/test-agedver
 -src/gnc-module/test/test-dynload
 -src/gnc-module/test/test-incompatdep
 -src/gnc-module/test/test-load-c
 -src/gnc-module/test/test-modsysver
 -src/gnome-utils/gnc-svninfo.h
 -src/gnome-utils/gnc-version.h
 -src/gnome-utils/gnucash
 -src/gnome-utils/test/test-gnc-dialog
 -src/gnome-utils/test/test-gnc-recurrence
 -src/gnome-utils/test/test-link-module
 -src/gnome/gnucash.desktop
 -src/gnome/gnucash.desktop.in
 -src/import-export/ofx/test/test-link
 -src/import-export/qif-import/gnucash
 -src/import-export/qif-import/qif-import
 -src/import-export/qif-import/test/test-link
 -src/import-export/test/test-import-parse
 -src/import-export/test/test-link
 -src/libqof/backend/file/qsf-dir.h
 -src/libqof/qof/qofla-dir.h
 -src/libqof/qof/test-qofmath
 -src/libqof/qof/test/test-qof
 -src/optional/gtkmm/test/test-gtkmm
 -src/optional/python-bindings/.py-links
 -src/optional/python-bindings/gnucash/
 -src/optional/python-bindings/gnucash_core.c
 -src/optional/python-bindings/gnucash_core_c.py
 -src/optional/python-bindings/sqlite3test
 -src/pixmaps/128x128/
 -src/pixmaps/16x16
 -src/pixmaps/22x22
 -src/pixmaps/24x24
 -src/pixmaps/256x256/
 -src/pixmaps/32x32
 -src/pixmaps/48x48
 -src/pixmaps/64x64/
 -src/pixmaps/96x96/
 -src/pixmaps/gnucash-icon-16x16.png
 -src/pixmaps/gnucash-icon-32x32.png
 -src/pixmaps/scalable
 -src/python/.py-links
 -src/python/gnucash/python/init.py
 -src/quotes/gnc-fq-check
 -src/quotes/gnc-fq-helper
 -src/quotes/gnc-fq-update
 -src/register/ledger-core/test/test-link-module
 -src/register/register-core/test/test-link-module
 -src/register/register-gnome/test/test-link-module
 -src/report/business-reports/gnucash
 -src/report/locale-specific/us/gnucash
 -src/report/locale-specific/us/test/test-link-module
 -src/report/report-gnome/gnucash
 -src/report/report-gnome/test/test-link-module
 -src/report/report-system/gnucash
 -src/report/report-system/test/test-link-module
 -src/report/standard-reports/gnucash
 -src/report/stylesheets/gnucash
 -src/report/utility-reports/gnucash
 -src/scm/build-config.scm
 -src/scm/gnucash
 -src/swig-runtime.h
 -src/tax/us/gnucash
 -src/tax/us/test/test-link-module
 -src/test-core/gnucash/
 -src/test-core/test_stuff.py
 -src/test-core/unittest_support.py
 +bindings/python/.py-links
 +bindings/python/gnucash/
 +bindings/python/gnucash_core.c
 +bindings/python/gnucash_core_c.py
 +bindings/python/sqlite3test
 +common/swig-runtime.h
 +common/test-core/gnucash/
 +common/test-core/test_stuff.py
 +common/test-core/unittest_support.py
 +data/pixmaps/128x128/
 +data/pixmaps/16x16
 +data/pixmaps/22x22
 +data/pixmaps/24x24
 +data/pixmaps/256x256/
 +data/pixmaps/32x32
 +data/pixmaps/48x48
 +data/pixmaps/64x64/
 +data/pixmaps/96x96/
 +data/pixmaps/gnucash-icon-16x16.png
 +data/pixmaps/gnucash-icon-32x32.png
 +data/pixmaps/scalable
 +libgnucash/app-utils/calculation/test/test-link
 +libgnucash/app-utils/gnucash
 +libgnucash/app-utils/sw_app_utils.py
 +libgnucash/app-utils/test/test-exp-parser
 +libgnucash/app-utils/test/test-link-module
 +libgnucash/app-utils/test/test-print-parse-amount
 +libgnucash/app-utils/test/test-print-queries
 +libgnucash/app-utils/test/test-scm-query-string
 +libgnucash/app-utils/test/test-sx
 +libgnucash/backend/dbi/test/test-dbi
 +libgnucash/backend/dbi/test/test-dbi-basic
 +libgnucash/backend/dbi/test/test-dbi-business
 +libgnucash/backend/dbi/test/test-load-backend
 +libgnucash/backend/sql/test/test-column-types
 +libgnucash/backend/sql/test/test-sqlbe
 +libgnucash/backend/xml/test/test-date-converting
 +libgnucash/backend/xml/test/test-dom-converters1
 +libgnucash/backend/xml/test/test-kvp-frames
 +libgnucash/backend/xml/test/test-load-backend
 +libgnucash/backend/xml/test/test-load-example-account
 +libgnucash/backend/xml/test/test-load-xml2
 +libgnucash/backend/xml/test/test-save-in-lang
 +libgnucash/backend/xml/test/test-string-converters
 +libgnucash/backend/xml/test/test-xml-account
 +libgnucash/backend/xml/test/test-xml-commodity
 +libgnucash/backend/xml/test/test-xml-pricedb
 +libgnucash/backend/xml/test/test-xml-transaction
 +libgnucash/backend/xml/test/test-xml2-is-file
 +libgnucash/core-utils/gnc-vcs-info.h
 +libgnucash/core-utils/gnc-version.h
 +libgnucash/core-utils/gncla-dir.h
 +libgnucash/core-utils/gnucash
 +libgnucash/core-utils/sw_core_utils.py
 +libgnucash/core-utils/test/test-gnc-uri-utils
 +libgnucash/core-utils/test/test-resolve-file-path
 +libgnucash/doc/doxygen.cfg
 +libgnucash/doc/doxygen.log
 +libgnucash/doc/design/gnucash-design.info
 +libgnucash/doc/design/mdate-sh
 +libgnucash/doc/design/stamp-vti
 +libgnucash/doc/design/texinfo.tex
 +libgnucash/doc/design/version.texi
 +libgnucash/doc/html/
 +libgnucash/engine/gncla-dir.h
 +libgnucash/engine/gnucash
 +libgnucash/engine/iso-4217-currencies.c
 +libgnucash/engine/test/gnucash
 +libgnucash/engine/test/test-account-object
 +libgnucash/engine/test/test-address
 +libgnucash/engine/test/test-book-merge
 +libgnucash/engine/test/test-business
 +libgnucash/engine/test/test-commodities
 +libgnucash/engine/test/test-customer
 +libgnucash/engine/test/test-date
 +libgnucash/engine/test/test-employee
 +libgnucash/engine/test/test-engine
 +libgnucash/engine/test/test-group-vs-book
 +libgnucash/engine/test/test-guid
 +libgnucash/engine/test/test-job
 +libgnucash/engine/test/test-link
 +libgnucash/engine/test/test-load-engine
 +libgnucash/engine/test/test-lots
 +libgnucash/engine/test/test-numeric
 +libgnucash/engine/test/test-object
 +libgnucash/engine/test/test-period
 +libgnucash/engine/test/test-query
 +libgnucash/engine/test/test-querynew
 +libgnucash/engine/test/test-qof
 +libgnucash/engine/test/test-recurrence
 +libgnucash/engine/test/test-recursive
 +libgnucash/engine/test/test-scm-query
 +libgnucash/engine/test/test-split-vs-account
 +libgnucash/engine/test/test-transaction-reversal
 +libgnucash/engine/test/test-transaction-voiding
 +libgnucash/engine/test/test-vendor
 +libgnucash/gnc-module/gnucash
 +libgnucash/gnc-module/test/test-agedver
 +libgnucash/gnc-module/test/test-dynload
 +libgnucash/gnc-module/test/test-incompatdep
 +libgnucash/gnc-module/test/test-load-c
 +libgnucash/gnc-module/test/test-modsysver
 +libgnucash/quotes/gnc-fq-check
 +libgnucash/quotes/gnc-fq-helper
 +libgnucash/quotes/gnc-fq-update
 +libgnucash/scm/build-config.scm
 +libgnucash/scm/gnucash
 +libgnucash/tax/us/gnucash
 +libgnucash/tax/us/test/test-link-module
 +gnucash/environment
 +gnucash/gnucash
 +gnucash/gnucash-bin
 +gnucash/gnucash-ddd
 +gnucash/gnucash-env
 +gnucash/gnucash-gdb
 +gnucash/gnucash-launcher
 +gnucash/gnucash-make-guids
 +gnucash/gnucash-setup-env
 +gnucash/gnucash-valgrind
 +gnucash/overrides/gnucash-build-env
 +gnucash/overrides/gnucash-env
 +gnucash/overrides/guile
 +gnucash/gnome/gnucash
 +gnucash/gnome/gnucash.desktop
 +gnucash/gnome/gnucash.desktop.in
 +gnucash/gnome-utils/gnucash
 +gnucash/gnome-utils/gnc-svninfo.h
 +gnucash/gnome-utils/gnc-version.h
 +gnucash/gnome-utils/gnucash
 +gnucash/gnome-utils/test/test-gnc-dialog
 +gnucash/gnome-utils/test/test-gnc-recurrence
 +gnucash/gnome-utils/test/test-link-module
 +gnucash/import-export/ofx/test/test-link
 +gnucash/import-export/qif-import/gnucash
 +gnucash/import-export/qif-import/qif-import
 +gnucash/import-export/qif-import/test/test-link
 +gnucash/import-export/test/test-import-parse
 +gnucash/import-export/test/test-link
 +gnucash/python/.py-links
 +gnucash/python/gnucash/python/init.py
 +gnucash/register/ledger-core/test/test-link-module
 +gnucash/register/register-core/test/test-link-module
 +gnucash/register/register-gnome/test/test-link-module
 +gnucash/report/business-reports/gnucash
 +gnucash/report/locale-specific/us/gnucash
 +gnucash/report/locale-specific/us/test/test-link-module
 +gnucash/report/report-gnome/gnucash
 +gnucash/report/report-gnome/test/test-link-module
 +gnucash/report/report-system/gnucash
 +gnucash/report/report-system/test/test-link-module
 +gnucash/report/standard-reports/gnucash
 +gnucash/report/stylesheets/gnucash
 +gnucash/report/utility-reports/gnucash
  stamp-h1
  swig-*.c
  test-driver
diff --cc bindings/python/sqlite3test.c
index 4dad870,0000000..08f22b3
mode 100644,000000..100644
--- a/bindings/python/sqlite3test.c
+++ b/bindings/python/sqlite3test.c
@@@ -1,38 -1,0 +1,40 @@@
 +/********************************************************************\
 + * 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 <config.h>
 +#include "qofsession.h"
- 
++#define TESTFILE "/tmp/blah.gnucash"
 +int main()
 +{
++    const char* testurl = "sqlite3://" TESTFILE;
 +    qof_log_init();
 +    qof_init();
 +    gnc_module_system_init();
 +    char * no_args[1] = { NULL };
 +    gnc_engine_init(0, no_args);
 +
 +    QofSession * s = qof_session_new();
-     qof_session_begin(s, "sqlite3:///tmp/blah.gnucash", 0, 1, 1);
++    qof_session_begin(s, testurl, 0, 1, 0);
 +    qof_session_load(s, NULL);
 +    qof_session_save(s, NULL);
 +    qof_session_end(s);
++    unlink(TESTFILE);
 +    return 0;
 +}
diff --cc cmake/CMakeLists.txt
index e832570,089a8ba..bce5e3e
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@@ -21,15 -19,15 +19,15 @@@ SET(schema-targets csv-exp-gschema csv-
  IF (WITH_AQBANKING)
    LIST(APPEND schema-targets aqb-gschema)
  ENDIF (WITH_AQBANKING)
--    
++
  IF (WITH_OFX)
    LIST(APPEND schema-targets ofx-gschema)
  ENDIF (WITH_OFX)
--    
- SET(SCHEMA_DIRECTORY ${DATADIR_BUILD}/glib-2.0/schemas)
++
+ SET(SCHEMA_BUILD_DIR ${DATADIR_BUILD}/glib-2.0/schemas)
  ADD_CUSTOM_COMMAND(
-   OUTPUT ${SCHEMA_DIRECTORY}/gschemas.compiled
-   COMMAND ${CMAKE_COMMAND_TMP} ${GLIB_COMPILE_SCHEMAS} ${SCHEMA_DIRECTORY}
+   OUTPUT ${SCHEMA_BUILD_DIR}/gschemas.compiled
+   COMMAND ${CMAKE_COMMAND_TMP} ${GLIB_COMPILE_SCHEMAS} ${SCHEMA_BUILD_DIR}
    DEPENDS ${schema-targets}
  )
  
diff --cc libgnucash/backend/dbi/gnc-dbisqlresult.cpp
index 4115a11,0000000..61f1664
mode 100644,000000..100644
--- a/libgnucash/backend/dbi/gnc-dbisqlresult.cpp
+++ b/libgnucash/backend/dbi/gnc-dbisqlresult.cpp
@@@ -1,191 -1,0 +1,191 @@@
 +/********************************************************************
 + * gnc-dbisqlresult.cpp: Encapsulate libdbi dbi_result              *
 + *                                                                  *
 + * Copyright 2016 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 <guid.hpp>
 +extern "C"
 +{
 +#include <config.h>
 +#include <gnc-locale-utils.h>
 +#include <dbi/dbi.h>
 +/* For direct access to dbi data structs, sadly needed for datetime */
 +#include <dbi/dbi-dev.h>
 +}
 +#include <gnc-datetime.hpp>
 +#include "gnc-dbisqlresult.hpp"
 +#include "gnc-dbisqlconnection.hpp"
 +
 +static QofLogModule log_module = G_LOG_DOMAIN;
 +
 +#if LIBDBI_VERSION >= 900
 +#define HAVE_LIBDBI_TO_LONGLONG 1
 +#else
 +#define HAVE_LIBDBI_TO_LONGLONG 0
 +#endif
 +
 +GncDbiSqlResult::~GncDbiSqlResult()
 +{
 +    int status = dbi_result_free (m_dbi_result);
 +
 +    if (status == 0)
 +        return;
 +
 +    PERR ("Error %d in dbi_result_free() result.", m_conn->dberror() );
 +    qof_backend_set_error (m_conn->qbe(), ERR_BACKEND_SERVER_ERR);
 +}
 +
 +int
 +GncDbiSqlResult::dberror() const noexcept
 +{
 +    return m_conn->dberror();
 +}
 +
 +GncSqlRow&
 +GncDbiSqlResult::begin()
 +{
 +
 +    if (m_dbi_result == nullptr ||
 +        dbi_result_get_numrows(m_dbi_result) == 0)
 +        return m_sentinel;
 +    int status = dbi_result_first_row(m_dbi_result);
 +    if (status)
 +        return m_row;
 +    int error = dberror(); //
 +
 +    if (error != DBI_ERROR_BADIDX) //otherwise just an empty result set
 +    {
 +        PERR ("Error %d in dbi_result_first_row()", dberror());
 +        qof_backend_set_error (m_conn->qbe(), ERR_BACKEND_SERVER_ERR);
 +    }
 +    return m_sentinel;
 +}
 +
 +uint64_t
 +GncDbiSqlResult::size() const noexcept
 +{
 +    return dbi_result_get_numrows(m_dbi_result);
 +}
 +/* --------------------------------------------------------- */
 +
 +GncSqlRow&
 +GncDbiSqlResult::IteratorImpl::operator++()
 +{
 +    int status = dbi_result_next_row (m_inst->m_dbi_result);
 +    if (status)
 +        return m_inst->m_row;
 +    int error = m_inst->dberror();
 +    if (error == DBI_ERROR_BADIDX || error == 0) //ran off the end of the results
 +        return m_inst->m_sentinel;
 +    PERR("Error %d incrementing results iterator.", error);
 +    qof_backend_set_error (m_inst->m_conn->qbe(), ERR_BACKEND_SERVER_ERR);
 +    return m_inst->m_sentinel;
 +}
 +
 +int64_t
 +GncDbiSqlResult::IteratorImpl::get_int_at_col(const char* col) const
 +{
 +    auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col);
 +    if(type != DBI_TYPE_INTEGER)
 +        throw (std::invalid_argument{"Requested integer from non-integer column."});
 +    return dbi_result_get_longlong (m_inst->m_dbi_result, col);
 +}
 +
 +float
 +GncDbiSqlResult::IteratorImpl::get_float_at_col(const char* col) const
 +{
 +    auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col);
 +    auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col);
 +    if(type != DBI_TYPE_DECIMAL ||
 +       (attrs & DBI_DECIMAL_SIZEMASK) != DBI_DECIMAL_SIZE4)
 +        throw (std::invalid_argument{"Requested float from non-float column."});
 +    gnc_push_locale (LC_NUMERIC, "C");
 +    auto retval =  dbi_result_get_float(m_inst->m_dbi_result, col);
 +    gnc_pop_locale (LC_NUMERIC);
 +    return retval;
 +}
 +
 +double
 +GncDbiSqlResult::IteratorImpl::get_double_at_col(const char* col) const
 +{
 +    auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col);
 +    auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col);
 +    if(type != DBI_TYPE_DECIMAL ||
 +       (attrs & DBI_DECIMAL_SIZEMASK) != DBI_DECIMAL_SIZE8)
 +        throw (std::invalid_argument{"Requested double from non-double column."});
 +    gnc_push_locale (LC_NUMERIC, "C");
 +    auto retval =  dbi_result_get_double(m_inst->m_dbi_result, col);
 +    gnc_pop_locale (LC_NUMERIC);
 +    return retval;
 +}
 +
 +std::string
 +GncDbiSqlResult::IteratorImpl::get_string_at_col(const char* col) const
 +{
 +    auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col);
 +    auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col);
 +    if(type != DBI_TYPE_STRING)
 +        throw (std::invalid_argument{"Requested string from non-string column."});
 +    gnc_push_locale (LC_NUMERIC, "C");
 +    auto strval = dbi_result_get_string(m_inst->m_dbi_result, col);
 +    if (strval == nullptr)
 +    {
 +        gnc_pop_locale (LC_NUMERIC);
 +        throw (std::invalid_argument{"Column empty."});
 +    }
 +    auto retval =  std::string{strval};
 +    gnc_pop_locale (LC_NUMERIC);
 +    return retval;
 +}
 +time64
 +GncDbiSqlResult::IteratorImpl::get_time64_at_col (const char* col) const
 +{
 +    auto result = (dbi_result_t*) (m_inst->m_dbi_result);
 +    auto type = dbi_result_get_field_type (result, col);
 +    auto attrs = dbi_result_get_field_attribs (result, col);
 +    if (type != DBI_TYPE_DATETIME)
 +        throw (std::invalid_argument{"Requested time64 from non-time64 column."});
 +    gnc_push_locale (LC_NUMERIC, "C");
 +#if HAVE_LIBDBI_TO_LONGLONG
 +    /* A less evil hack than the one required by libdbi-0.8, but
 +     * still necessary to work around the same bug.
 +     */
 +    auto retval = dbi_result_get_as_longlong(result, col);
 +#else
 +    /* A seriously evil hack to work around libdbi bug #15
 +     * https://sourceforge.net/p/libdbi/bugs/15/. When libdbi
 +     * v0.9 is widely available this can be replaced with
 +     * dbi_result_get_as_longlong.
 +     * Note: 0.9 is available in Debian Jessie and Fedora 21.
 +     */
 +    auto row = dbi_result_get_currow (result);
 +    auto idx = dbi_result_get_field_idx (result, col) - 1;
 +    time64 retval = result->rows[row]->field_values[idx].d_datetime;
++#endif //HAVE_LIBDBI_TO_LONGLONG
 +    if (retval < MINTIME || retval > MAXTIME)
 +        retval = 0;
- #endif //HAVE_LIBDBI_TO_LONGLONG
 +    gnc_pop_locale (LC_NUMERIC);
 +    return retval;
 +}
 +
 +
 +/* --------------------------------------------------------- */
 +
diff --cc libgnucash/backend/sql/gnc-sql-column-table-entry.cpp
index 7a0548c,0000000..3c23a89
mode 100644,000000..100644
--- a/libgnucash/backend/sql/gnc-sql-column-table-entry.cpp
+++ b/libgnucash/backend/sql/gnc-sql-column-table-entry.cpp
@@@ -1,742 -1,0 +1,742 @@@
 +/********************************************************************
 + * gnc-sql-column-table-entry.cpp: Implement GncSqlColumnTableEntry *
 + *                                                                  *
 + * Copyright 2016 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 <qof.h>
 +}
 +#include <sstream>
 +#include <iomanip>
 +#include <gnc-datetime.hpp>
 +#include "gnc-sql-backend.hpp"
 +#include "gnc-sql-object-backend.hpp"
 +#include "gnc-sql-column-table-entry.hpp"
 +#include "gnc-sql-result.hpp"
 +
 +static QofLogModule log_module = G_LOG_DOMAIN;
 +
 +/* ================================================================= */
 +static gpointer
 +get_autoinc_id (void* object, const QofParam* param)
 +{
 +    // Just need a 0 to force a new autoinc value
 +    return (gpointer)0;
 +}
 +
 +static void
 +set_autoinc_id (void* object, void* item)
 +{
 +    // Nowhere to put the ID
 +}
 +
 +
 +QofAccessFunc
 +GncSqlColumnTableEntry::get_getter (QofIdTypeConst obj_name) const noexcept
 +{
 +    QofAccessFunc getter;
 +
 +    g_return_val_if_fail (obj_name != NULL, NULL);
 +
 +    if (m_flags & COL_AUTOINC)
 +    {
 +        getter = get_autoinc_id;
 +    }
 +    else if (m_qof_param_name != NULL)
 +    {
 +        getter = qof_class_get_parameter_getter (obj_name, m_qof_param_name);
 +    }
 +    else
 +    {
 +        getter = m_getter;
 +    }
 +
 +    return getter;
 +}
 +
 +QofSetterFunc
 +GncSqlColumnTableEntry::get_setter(QofIdTypeConst obj_name) const noexcept
 +{
 +    QofSetterFunc setter = nullptr;
 +    if (m_flags & COL_AUTOINC)
 +    {
 +        setter = set_autoinc_id;
 +    }
 +    else if (m_qof_param_name != nullptr)
 +    {
 +        g_assert (obj_name != NULL);
 +        setter = qof_class_get_parameter_setter (obj_name, m_qof_param_name);
 +    }
 +    else
 +    {
 +        setter = m_setter;
 +    }
 +    return setter;
 +}
 +
 +void
 +GncSqlColumnTableEntry::add_objectref_guid_to_query (QofIdTypeConst obj_name,
 +                                                     const void* pObject,
 +                                                     PairVec& vec) const noexcept
 +{
 +    auto inst = get_row_value_from_object<QofInstance*>(obj_name, pObject);
 +    if (inst == nullptr) return;
 +    auto guid = qof_instance_get_guid (inst);
 +    if (guid != nullptr)
 +        vec.emplace_back (std::make_pair (std::string{m_col_name},
 +                                          quote_string(guid_to_string(guid))));
 +}
 +
 +void
 +GncSqlColumnTableEntry::add_objectref_guid_to_table (ColVec& vec) const noexcept
 +{
 +    GncSqlColumnInfo info{*this, BCT_STRING, GUID_ENCODING_LENGTH, FALSE};
 +    vec.emplace_back(std::move(info));
 +}
 +
 +
 +/* ----------------------------------------------------------------- */
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_STRING>::load (const GncSqlBackend* sql_be,
 +                                             GncSqlRow& row,
 +                                             QofIdTypeConst obj_name,
 +                                             gpointer pObject) const noexcept
 +{
 +    g_return_if_fail (pObject != NULL);
 +    g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
 +
 +    try
 +    {
 +        auto s = row.get_string_at_col (m_col_name);
 +        set_parameter(pObject, s.c_str(), get_setter(obj_name), m_gobj_param_name);
 +    }
 +    catch (std::invalid_argument) {}
 +}
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_STRING>::add_to_table(ColVec& vec) const noexcept
 +{
 +    GncSqlColumnInfo info{*this, BCT_STRING, m_size, TRUE};
 +    vec.emplace_back(std::move(info));
 +}
 +
 +/* char is unusual in that we get a pointer but don't deref it to pass
 + * it to operator<<().
 + */
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_STRING>::add_to_query(QofIdTypeConst obj_name,
 +                                                    const gpointer pObject,
 +                                                    PairVec& vec) const noexcept
 +{
 +    auto s = get_row_value_from_object<char*>(obj_name, pObject);
 +
 +    if (s != nullptr)
 +    {
 +        std::ostringstream stream;
 +        stream << s;
 +        vec.emplace_back (std::make_pair (std::string{m_col_name},
 +                                          quote_string(stream.str())));
 +        return;
 +    }
 +}
 +
 +/* ----------------------------------------------------------------- */
 +typedef gint (*IntAccessFunc) (const gpointer);
 +typedef void (*IntSetterFunc) (const gpointer, gint);
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_INT>::load (const GncSqlBackend* sql_be,
 +                                          GncSqlRow& row,
 +                                          QofIdTypeConst obj_name,
 +                                          gpointer pObject) const noexcept
 +{
 +
 +    g_return_if_fail (pObject != NULL);
 +    g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
 +
 +    auto val = row.get_int_at_col(m_col_name);
 +    set_parameter(pObject, val,
 +                  reinterpret_cast<IntSetterFunc>(get_setter(obj_name)), m_gobj_param_name);
 +}
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_INT>::add_to_table(ColVec& vec) const noexcept
 +{
 +    GncSqlColumnInfo info{*this, BCT_INT, 0, FALSE};
 +    vec.emplace_back(std::move(info));
 +}
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_INT>::add_to_query(QofIdTypeConst obj_name,
 +                                                 const gpointer pObject,
 +                                                 PairVec& vec) const noexcept
 +{
 +    add_value_to_vec<int>(obj_name, pObject, vec);
 +}
 +
 +/* ----------------------------------------------------------------- */
 +typedef gboolean (*BooleanAccessFunc) (const gpointer);
 +typedef void (*BooleanSetterFunc) (const gpointer, gboolean);
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_BOOLEAN>::load (const GncSqlBackend* sql_be,
 +                                              GncSqlRow& row,
 +                                              QofIdTypeConst obj_name,
 +                                              gpointer pObject)
 +    const noexcept
 +{
 +    g_return_if_fail (pObject != NULL);
 +    g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
 +
 +    auto val = row.get_int_at_col (m_col_name);
 +    set_parameter(pObject, val,
 +                  reinterpret_cast<BooleanSetterFunc>(get_setter(obj_name)),
 +                  m_gobj_param_name);
 +}
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_BOOLEAN>::add_to_table(ColVec& vec) const noexcept
 +{
 +    GncSqlColumnInfo info{*this, BCT_INT, 0, FALSE};
 +    vec.emplace_back(std::move(info));
 +}
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_BOOLEAN>::add_to_query(QofIdTypeConst obj_name,
 +                                                    const gpointer pObject,
 +                                                    PairVec& vec) const noexcept
 +{
 +    add_value_to_vec<int>(obj_name, pObject, vec);
 +}
 +
 +/* ----------------------------------------------------------------- */
 +typedef gint64 (*Int64AccessFunc) (const gpointer);
 +typedef void (*Int64SetterFunc) (const gpointer, gint64);
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_INT64>::load (const GncSqlBackend* sql_be,
 +                                            GncSqlRow& row,
 +                                            QofIdTypeConst obj_name,
 +                                            gpointer pObject)
 +    const noexcept
 +{
 +    g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
 +
 +    auto val = row.get_int_at_col (m_col_name);
 +    set_parameter(pObject, val,
 +                  reinterpret_cast<Int64SetterFunc>(get_setter(obj_name)),
 +                  m_gobj_param_name);
 +}
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_INT64>::add_to_table(ColVec& vec) const noexcept
 +{
 +
 +    GncSqlColumnInfo info{*this, BCT_INT64, 0, FALSE};
 +    vec.emplace_back(std::move(info));
 +}
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_INT64>::add_to_query(QofIdTypeConst obj_name,
 +                                                   const gpointer pObject,
 +                                                   PairVec& vec) const noexcept
 +{
 +    add_value_to_vec<int64_t>(obj_name, pObject, vec);
 +}
 +/* ----------------------------------------------------------------- */
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_DOUBLE>::load (const GncSqlBackend* sql_be,
 +                                             GncSqlRow& row,
 +                                             QofIdTypeConst obj_name,
 +                                             gpointer pObject)
 +    const noexcept
 +{
 +    g_return_if_fail (pObject != NULL);
 +    g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
 +    double val;
 +    try
 +    {
 +        val = static_cast<double>(row.get_int_at_col(m_col_name));
 +    }
 +    catch (std::invalid_argument)
 +    {
 +        try
 +        {
 +            val = static_cast<double>(row.get_float_at_col(m_col_name));
 +        }
 +        catch (std::invalid_argument)
 +        {
 +            try
 +            {
 +                val = row.get_double_at_col(m_col_name);
 +            }
 +            catch (std::invalid_argument)
 +            {
 +                val = 0.0;
 +            }
 +        }
 +    }
 +    set_parameter(pObject, val, get_setter(obj_name), m_gobj_param_name);
 +}
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_DOUBLE>::add_to_table(ColVec& vec) const noexcept
 +{
 +    GncSqlColumnInfo info{*this, BCT_DOUBLE, 0, FALSE};
 +    vec.emplace_back(std::move(info));
 +}
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_DOUBLE>::add_to_query(QofIdTypeConst obj_name,
 +                                                    const gpointer pObject,
 +                                                    PairVec& vec) const noexcept
 +{
 +    add_value_to_vec<double*>(obj_name, pObject, vec);
 +}
 +
 +/* ----------------------------------------------------------------- */
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_GUID>::load (const GncSqlBackend* sql_be,
 +                                           GncSqlRow& row,
 +                                           QofIdTypeConst obj_name,
 +                                           gpointer pObject)
 +    const noexcept
 +{
 +
 +    GncGUID guid;
 +    const GncGUID* pGuid;
 +
 +    g_return_if_fail (pObject != NULL);
 +    g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
 +
 +    std::string str;
 +    try
 +    {
 +        str = row.get_string_at_col(m_col_name);
 +    }
 +    catch (std::invalid_argument)
 +    {
 +        return;
 +    }
 +    if (string_to_guid (str.c_str(), &guid))
 +        set_parameter(pObject, &guid, get_setter(obj_name), m_gobj_param_name);
 +}
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_GUID>::add_to_table(ColVec& vec) const noexcept
 +{
 +    GncSqlColumnInfo info{*this, BCT_STRING, GUID_ENCODING_LENGTH, FALSE};
 +    vec.emplace_back(std::move(info));
 +}
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_GUID>::add_to_query(QofIdTypeConst obj_name,
 +                                                  const gpointer pObject,
 +                                                  PairVec& vec) const noexcept
 +{
 +    auto s = get_row_value_from_object<GncGUID*>(obj_name, pObject);
 +
 +    if (s != nullptr)
 +    {
 +
 +        vec.emplace_back (std::make_pair (std::string{m_col_name},
 +                                          quote_string(guid_to_string(s))));
 +        return;
 +    }
 +}
 +/* ----------------------------------------------------------------- */
 +typedef Timespec (*TimespecAccessFunc) (const gpointer);
 +typedef void (*TimespecSetterFunc) (const gpointer, Timespec*);
 +
 +#define TIMESPEC_COL_SIZE (4+3+3+3+3+3)
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_TIMESPEC>::load (const GncSqlBackend* sql_be,
 +                                               GncSqlRow& row,
 +                                               QofIdTypeConst obj_name,
 +                                               gpointer pObject) const noexcept
 +{
 +
 +    Timespec ts = {0, 0};
 +    gboolean isOK = FALSE;
 +
 +
 +    g_return_if_fail (pObject != NULL);
 +    g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
 +
 +    try
 +    {
 +        auto val = row.get_time64_at_col(m_col_name);
 +        timespecFromTime64 (&ts, val);
 +    }
 +    catch (std::invalid_argument)
 +    {
 +        try
 +        {
 +            constexpr size_t datelen = 14;
 +            auto val = row.get_string_at_col(m_col_name);
-             if (val.length() == datelen)
++            if (val.length() == datelen && val != "0000-00-00 00:00:00")
 +            {
 +                using std::stoi;
 +#ifdef HAVE_STRUCT_TM_GMTOFF
 +                const struct tm tm
 +                {stoi(val.substr(12, 2)), stoi(val.substr(10, 2)),
 +                 stoi(val.substr(8, 2)), stoi(val.substr(6, 2)),
 +                 stoi(val.substr(4, 2)) - 1, stoi(val.substr(0, 4)) - 1900,
 +                        0, 0, 0, 0, nullptr};
 +#else
 +                const struct tm tm
 +                {stoi(val.substr(12, 2)), stoi(val.substr(10, 2)),
 +                 stoi(val.substr(8, 2)), stoi(val.substr(6, 2)),
 +                 stoi(val.substr(4, 2)) - 1, stoi(val.substr(0, 4)) -1900,
 +                 0, 0, 0};
 +#endif
 +
 +                GncDateTime time(tm);
 +                ts.tv_sec = static_cast<time64>(time);
 +            }
 +            else
 +            {
 +                GncDateTime time(val);
 +                ts.tv_sec = static_cast<time64>(time);
 +            }
 +        }
 +        catch (std::invalid_argument)
 +        {
 +            return;
 +        }
 +    }
 +    set_parameter(pObject, &ts,
 +                  reinterpret_cast<TimespecSetterFunc>(get_setter(obj_name)),
 +                  m_gobj_param_name);
 + }
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_TIMESPEC>::add_to_table(ColVec& vec) const noexcept
 +{
 +    GncSqlColumnInfo info{*this, BCT_DATETIME, TIMESPEC_COL_SIZE, FALSE};
 +    vec.emplace_back(std::move(info));
 +}
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_TIMESPEC>::add_to_query(QofIdTypeConst obj_name,
 +                                                      const gpointer pObject,
 +                                                      PairVec& vec) const noexcept
 +{
 +    TimespecAccessFunc ts_getter;
 +    Timespec ts;
 +/* Can't use get_row_value_from_object because g_object_get returns a
 + * Timespec* and the getter returns a Timespec. Will be fixed by the
 + * replacement of timespecs with time64s.
 + */
 +    g_return_if_fail (obj_name != NULL);
 +    g_return_if_fail (pObject != NULL);
 +
 +    if (m_gobj_param_name != NULL)
 +    {
 +        Timespec* pts;
 +        g_object_get (pObject, m_gobj_param_name, &pts, NULL);
 +        ts = *pts;
 +    }
 +    else
 +    {
 +        ts_getter = (TimespecAccessFunc)get_getter (obj_name);
 +        g_return_if_fail (ts_getter != NULL);
 +        ts = (*ts_getter) (pObject);
 +    }
 +
 +    GncDateTime time(ts.tv_sec);
 +    vec.emplace_back (std::make_pair (std::string{m_col_name},
 +                                      time.format_zulu ("'%Y-%m-%d %H:%M:%S'")));
 +}
 +
 +/* ----------------------------------------------------------------- */
 +#define DATE_COL_SIZE 8
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_GDATE>::load (const GncSqlBackend* sql_be,
 +                                            GncSqlRow& row,
 +                                            QofIdTypeConst obj_name,
 +                                            gpointer pObject) const noexcept
 +{
 +    g_return_if_fail (pObject != NULL);
 +    g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
 +    if (row.is_col_null(m_col_name))
 +        return;
 +    GDate date;
 +    g_date_clear (&date, 1);
 +    try
 +    {
 +        /* timespec_to_gdate applies the tz, and gdates are saved
 +         * as ymd, so we don't want that.
 +         */
 +        auto time = row.get_time64_at_col(m_col_name);
 +        auto tm = gnc_gmtime(&time);
 +        g_date_set_dmy(&date, tm->tm_mday,
 +                       static_cast<GDateMonth>(tm->tm_mon + 1),
 +                       tm->tm_year + 1900);
 +        free(tm);
 +    }
 +    catch (std::invalid_argument)
 +    {
 +        try
 +        {
 +            std::string str = row.get_string_at_col(m_col_name);
 +            if (str.empty()) return;
 +            auto year = static_cast<GDateYear>(stoi (str.substr (0,4)));
 +            auto month = static_cast<GDateMonth>(stoi (str.substr (4,2)));
 +            auto day = static_cast<GDateDay>(stoi (str.substr (6,2)));
 +
 +            if (year != 0 || month != 0 || day != (GDateDay)0)
 +                g_date_set_dmy(&date, day, month, year);
 +
 +        }
 +        catch (std::invalid_argument)
 +        {
 +            return;
 +        }
 +    }
 +    set_parameter(pObject, &date, get_setter(obj_name), m_gobj_param_name);
 +}
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_GDATE>::add_to_table(ColVec& vec) const noexcept
 +{
 +    GncSqlColumnInfo info{*this,  BCT_DATE, DATE_COL_SIZE, FALSE};
 +    vec.emplace_back(std::move(info));
 +}
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_GDATE>::add_to_query(QofIdTypeConst obj_name,
 +                                                   const gpointer pObject,
 +                                                   PairVec& vec) const noexcept
 +{
 +    GDate *date = get_row_value_from_object<GDate*>(obj_name, pObject);
 +
 +    if (date && g_date_valid (date))
 +    {
 +        std::ostringstream buf;
 +        buf << std::setfill ('0') << std::setw (4) << g_date_get_year (date) <<
 +            std::setw (2) << g_date_get_month (date) <<
 +            std::setw (2) << static_cast<int>(g_date_get_day (date));
 +        vec.emplace_back (std::make_pair (std::string{m_col_name},
 +                                          quote_string(buf.str())));
 +        return;
 +    }
 +}
 +
 +/* ----------------------------------------------------------------- */
 +typedef gnc_numeric (*NumericGetterFunc) (const gpointer);
 +typedef void (*NumericSetterFunc) (gpointer, gnc_numeric*);
 +
 +static const EntryVec numeric_col_table =
 +{
 +    gnc_sql_make_table_entry<CT_INT64>("num", 0, COL_NNUL, "guid"),
 +    gnc_sql_make_table_entry<CT_INT64>("denom", 0, COL_NNUL, "guid")
 +};
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_NUMERIC>::load (const GncSqlBackend* sql_be,
 +                                              GncSqlRow& row,
 +                                              QofIdTypeConst obj_name,
 +                                              gpointer pObject) const noexcept
 +{
 +
 +
 +    g_return_if_fail (pObject != NULL);
 +    g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
 +    gnc_numeric n;
 +    try
 +    {
 +        auto buf = g_strdup_printf ("%s_num", m_col_name);
 +        auto num = row.get_int_at_col (buf);
 +        g_free (buf);
 +        buf = g_strdup_printf ("%s_denom", m_col_name);
 +        auto denom = row.get_int_at_col (buf);
 +        n = gnc_numeric_create (num, denom);
 +        g_free (buf);
 +    }
 +    catch (std::invalid_argument)
 +    {
 +        return;
 +    }
 +    set_parameter(pObject, &n,
 +                  reinterpret_cast<NumericSetterFunc>(get_setter(obj_name)),
 +                  m_gobj_param_name);
 +}
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_NUMERIC>::add_to_table(ColVec& vec) const noexcept
 +{
 +
 +    for (auto const& subtable_row : numeric_col_table)
 +    {
 +        gchar* buf = g_strdup_printf("%s_%s", m_col_name,
 +                                     subtable_row->m_col_name);
 +        GncSqlColumnInfo info(buf, BCT_INT64, 0, false, false,
 +                              m_flags & COL_PKEY, m_flags & COL_NNUL);
 +        g_free (buf);
 +        vec.emplace_back(std::move(info));
 +    }
 +}
 +
 +template<> void
 +GncSqlColumnTableEntryImpl<CT_NUMERIC>::add_to_query(QofIdTypeConst obj_name,
 +                                                     const gpointer pObject,
 +                                                     PairVec& vec) const noexcept
 +{
 +/* We can't use get_row_value_from_object for the same reason as Timespec. */
 +    NumericGetterFunc getter;
 +    gnc_numeric n;
 +
 +    g_return_if_fail (obj_name != NULL);
 +    g_return_if_fail (pObject != NULL);
 +
 +    if (m_gobj_param_name != nullptr)
 +    {
 +        gnc_numeric* s;
 +        g_object_get (pObject, m_gobj_param_name, &s, NULL);
 +        n = *s;
 +    }
 +    else
 +    {
 +        getter = reinterpret_cast<NumericGetterFunc>(get_getter (obj_name));
 +        if (getter != NULL)
 +        {
 +            n = (*getter) (pObject);
 +        }
 +        else
 +        {
 +            n = gnc_numeric_zero ();
 +        }
 +    }
 +
 +    std::ostringstream buf;
 +    std::string num_col{m_col_name};
 +    std::string denom_col{m_col_name};
 +    num_col += "_num";
 +    denom_col += "_denom";
 +    buf << gnc_numeric_num (n);
 +    vec.emplace_back (std::make_pair (num_col, buf.str ()));
 +    buf.str ("");
 +    buf << gnc_numeric_denom (n);
 +    vec.emplace_back (denom_col, buf.str ());
 +}
 +
 +static void
 +_retrieve_guid_ (gpointer pObject,  gpointer pValue)
 +{
 +    GncGUID* pGuid = (GncGUID*)pObject;
 +    GncGUID* guid = (GncGUID*)pValue;
 +
 +    g_return_if_fail (pObject != NULL);
 +    g_return_if_fail (pValue != NULL);
 +
 +    memcpy (pGuid, guid, sizeof (GncGUID));
 +}
 +
 +// Table to retrieve just the guid
 +static EntryVec guid_table
 +{
 +    gnc_sql_make_table_entry<CT_GUID>("guid", 0, 0, nullptr, _retrieve_guid_)
 +};
 +
 +const GncGUID*
 +gnc_sql_load_guid (const GncSqlBackend* sql_be, GncSqlRow& row)
 +{
 +    static GncGUID guid;
 +
 +    g_return_val_if_fail (sql_be != NULL, NULL);
 +
 +    gnc_sql_load_object (sql_be, row, NULL, &guid, guid_table);
 +
 +    return &guid;
 +}
 +
 +void
 +gnc_sql_load_object (const GncSqlBackend* sql_be, GncSqlRow& row,
 +                     QofIdTypeConst obj_name, gpointer pObject,
 +                     const EntryVec& table)
 +{
 +    QofSetterFunc setter;
 +
 +    g_return_if_fail (sql_be != NULL);
 +    g_return_if_fail (pObject != NULL);
 +
 +    for (auto const& table_row : table)
 +    {
 +        table_row->load (sql_be, row, obj_name, pObject);
 +    }
 +}
 +
 +uint_t
 +gnc_sql_append_guids_to_sql (std::stringstream& sql,
 +                             const InstanceVec& instances)
 +{
 +    char guid_buf[GUID_ENCODING_LENGTH + 1];
 +
 +    for (auto inst : instances)
 +    {
 +        (void)guid_to_string_buff (qof_instance_get_guid (inst), guid_buf);
 +
 +        if (inst != *(instances.begin()))
 +        {
 +            sql << ",";
 +        }
 +        sql << "'" << guid_buf << "'";
 +    }
 +
 +    return instances.size();
 +}
 +
 +/* This is necessary for 64-bit builds because g++ complains
 + * that reinterpret_casting a void* (64 bits) to an int (32 bits)
 + * loses precision, so we have to explicitly dispose of the precision.
 + * FIXME: We shouldn't be storing ints in ptrs in the first place.
 + */
 +#ifdef __LP64__
 +template <> int
 +GncSqlColumnTableEntry::get_row_value_from_object<int>(QofIdTypeConst obj_name,
 +                                                       const void* pObject,
 +                                                       std::false_type) const
 +{
 +    g_return_val_if_fail(obj_name != nullptr && pObject != nullptr, 0);
 +    int result = 0;
 +    if (m_gobj_param_name != nullptr)
 +        g_object_get(const_cast<void*>(pObject), m_gobj_param_name, &result,
 +		     nullptr);
 +    else
 +    {
 +        QofAccessFunc getter = get_getter(obj_name);
 +        if (getter != nullptr)
 +        {
 +            auto value = ((getter)(const_cast<void*>(pObject), nullptr));
 +            result = reinterpret_cast<uint64_t>(value) &
 +                UINT64_C(0x00000000FFFFFFFF);
 +        }
 +    }
 +    return result;
 +}
 +#endif
diff --cc libgnucash/engine/gnc-date.cpp
index 4ea2a9b,0000000..e124135
mode 100644,000000..100644
--- a/libgnucash/engine/gnc-date.cpp
+++ b/libgnucash/engine/gnc-date.cpp
@@@ -1,1757 -1,0 +1,1745 @@@
 +/********************************************************************\
 + * gnc-date.cpp -- C interface for date and time                    *
 + *                                                                  *
 + * Copyright 1997 Robin D. Clark <rclark at cs.hmc.edu>                *
 + * Copyright 1998-2000, 2003 Linas Vepstas <linas at linas.org>        *
 + * Copyright (C) 2005 David Hampton <hampton at employees.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   *
 + * 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                   *
 + *                                                                  *
 +\********************************************************************/
 +
 +#define __EXTENSIONS__
 +extern "C"
 +{
 +
 +#include <config.h>
 +#include <glib.h>
 +#include <libintl.h>
 +#include <stdlib.h>
 +#include "platform.h"
 +#include "qof.h"
 +
 +#ifdef HAVE_LANGINFO_D_FMT
 +# include <langinfo.h>
 +#endif
 +#ifndef HAVE_STRPTIME
 +#include <strptime.h>
 +#endif
 +#ifdef G_OS_WIN32
 +#  include <windows.h>
 +#endif
 +}
 +
 +#include <cinttypes>
 +
 +#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
 +
 +#ifdef HAVE_LANGINFO_D_FMT
 +#  define GNC_D_FMT (nl_langinfo (D_FMT))
 +#  define GNC_D_T_FMT (nl_langinfo (D_T_FMT))
 +#  define GNC_T_FMT (nl_langinfo (T_FMT))
 +#elif defined(G_OS_WIN32)
 +#  define GNC_D_FMT (qof_win32_get_time_format(QOF_WIN32_PICTURE_DATE))
 +#  define GNC_T_FMT (qof_win32_get_time_format(QOF_WIN32_PICTURE_TIME))
 +#  define GNC_D_T_FMT (qof_win32_get_time_format(QOF_WIN32_PICTURE_DATETIME))
 +#else
 +#  define GNC_D_FMT "%Y-%m-%d"
 +#  define GNC_D_T_FMT "%Y-%m-%d %r"
 +#  define GNC_T_FMT "%r"
 +#endif
 +
- /* t < MINTIME is probably from a bad conversion from t 0 to
-  * 0000-00-00, so restore it to the Unix Epoch. t anywhere near
-  * MAXTIME is obviously an error, but we don't want to crash with a
-  * bad date-time so just clamp it to MAXTIME.
-  */
- static inline time64
- clamp_time(time64 t)
- {
-     return  t < MINTIME ? 0 : t > MAXTIME ? MAXTIME : t;
- }
- 
 +const char *gnc_default_strftime_date_format =
 +#ifdef G_OS_WIN32
 +    /* The default date format for use with strftime in Win32. */
 +    N_("%B %#d, %Y")
 +#else
 +    /* The default date format for use with strftime in other OS. */
 +    /* Translators: call "man strftime" for possible values. */
 +    N_("%B %e, %Y")
 +#endif
 +    ;
 +
 +/* This is now user configured through the gnome options system() */
 +static QofDateFormat dateFormat = QOF_DATE_FORMAT_LOCALE;
 +static QofDateFormat prevQofDateFormat = QOF_DATE_FORMAT_LOCALE;
 +
 +static QofDateCompletion dateCompletion = QOF_DATE_COMPLETION_THISYEAR;
 +static int dateCompletionBackMonths = 6;
 +
 +/* This static indicates the debugging module that this .o belongs to. */
 +static QofLogModule log_module = QOF_MOD_ENGINE;
 +
 +/****************** Posix Replacement Functions ***************************/
 +void
 +gnc_tm_free (struct tm* time)
 +{
 +    free(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;
 +}
 +
 +struct tm*
 +gnc_localtime_r (const time64 *secs, struct tm* time)
 +{
 +    try
 +    {
 +        *time = static_cast<struct tm>(GncDateTime(*secs));
 +        return time;
 +    }
 +    catch(std::invalid_argument)
 +    {
 +        return NULL;
 +    }
 +}
 +
 +static void
 +normalize_time_component (int *inner, int *outer, unsigned int divisor,
 +                          int base)
 +{
 +     while (*inner < base)
 +     {
 +          --(*outer);
 +          *inner += divisor;
 +     }
 +     while (*inner > static_cast<gint>(divisor))
 +     {
 +          ++(*outer);
 +          *inner -= divisor;
 +     }
 +}
 +
 +static void
 +normalize_month(int *month, int *year)
 +{
 +    ++(*month);
 +    normalize_time_component(month, year, 12, 1);
 +    --(*month);
 +}
 +
 +static void
 +normalize_struct_tm (struct tm* time)
 +{
 +     gint year = time->tm_year + 1900;
 +     gint last_day;
 +
 +     /* Gregorian_date throws if it gets an out-of-range year
 +      * so clamp year into gregorian_date's range.
 +      */
 +     if (year < 1400) year += 1400;
 +     if (year > 9999) year %= 10000;
 +
 +     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_month (&(time->tm_mon), &year);
 +
 +     // 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;
 +     }
 +     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_year = year - 1900;
 +}
 +
 +struct tm*
 +gnc_gmtime (const time64 *secs)
 +{
 +    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)
 +{
 +    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)
 +{
 +    try
 +    {
 +        normalize_struct_tm(time);
 +        return static_cast<time64>(GncDateTime(*time));
 +    }
 +    catch(std::invalid_argument)
 +    {
 +        return 0;
 +    }
 +}
 +
 +char*
 +gnc_ctime (const time64 *secs)
 +{
-     return gnc_print_time64(clamp_time(*secs), "%a %b %d %H:%M:%S %Y");
++    return gnc_print_time64(*secs, "%a %b %d %H:%M:%S %Y");
 +}
 +
 +time64
 +gnc_time (time64 *tbuf)
 +{
 +    GncDateTime gncdt;
 +    auto time = static_cast<time64>(gncdt);
 +    if (tbuf != NULL)
 +        *tbuf = time;
 +    return time;
 +}
 +
 +gdouble
 +gnc_difftime (const time64 secs1, const time64 secs2)
 +{
 +    return (double)secs1 - (double)secs2;
 +}
 +
 +/****************************************************************************/
 +
 +const char*
 +gnc_date_dateformat_to_string(QofDateFormat format)
 +{
 +    switch (format)
 +    {
 +    case QOF_DATE_FORMAT_US:
 +        return "us";
 +    case QOF_DATE_FORMAT_UK:
 +        return "uk";
 +    case QOF_DATE_FORMAT_CE:
 +        return "ce";
 +    case QOF_DATE_FORMAT_ISO:
 +        return "iso";
 +    case QOF_DATE_FORMAT_UTC:
 +        return "utc";
 +    case QOF_DATE_FORMAT_LOCALE:
 +        return "locale";
 +    case QOF_DATE_FORMAT_CUSTOM:
 +        return "custom";
 +    case QOF_DATE_FORMAT_UNSET:
 +        return "unset";
 +    default:
 +        return NULL;
 +    }
 +}
 +
 +gboolean
 +gnc_date_string_to_dateformat(const char* fmt_str, QofDateFormat *format)
 +{
 +    if (!fmt_str)
 +        return TRUE;
 +
 +    if (!strcmp(fmt_str, "us"))
 +        *format = QOF_DATE_FORMAT_US;
 +    else if (!strcmp(fmt_str, "uk"))
 +        *format = QOF_DATE_FORMAT_UK;
 +    else if (!strcmp(fmt_str, "ce"))
 +        *format = QOF_DATE_FORMAT_CE;
 +    else if (!strcmp(fmt_str, "utc"))
 +        *format = QOF_DATE_FORMAT_UTC;
 +    else if (!strcmp(fmt_str, "iso"))
 +        *format = QOF_DATE_FORMAT_ISO;
 +    else if (!strcmp(fmt_str, "locale"))
 +        *format = QOF_DATE_FORMAT_LOCALE;
 +    else if (!strcmp(fmt_str, "custom"))
 +        *format = QOF_DATE_FORMAT_CUSTOM;
 +    else if (!strcmp(fmt_str, "unset"))
 +        *format = QOF_DATE_FORMAT_UNSET;
 +    else
 +        return TRUE;
 +
 +    return FALSE;
 +}
 +
 +const char*
 +gnc_date_monthformat_to_string(GNCDateMonthFormat format)
 +{
 +    switch (format)
 +    {
 +    case GNCDATE_MONTH_NUMBER:
 +        return "number";
 +    case GNCDATE_MONTH_ABBREV:
 +        return "abbrev";
 +    case GNCDATE_MONTH_NAME:
 +        return "name";
 +    default:
 +        return NULL;
 +    }
 +}
 +
 +gboolean
 +gnc_date_string_to_monthformat(const char *fmt_str, GNCDateMonthFormat *format)
 +{
 +    if (!fmt_str)
 +        return TRUE;
 +
 +    if (!strcmp(fmt_str, "number"))
 +        *format = GNCDATE_MONTH_NUMBER;
 +    else if (!strcmp(fmt_str, "abbrev"))
 +        *format = GNCDATE_MONTH_ABBREV;
 +    else if (!strcmp(fmt_str, "name"))
 +        *format = GNCDATE_MONTH_NAME;
 +    else
 +        return TRUE;
 +
 +    return FALSE;
 +}
 +
 +char*
 +gnc_print_time64(time64 time, const char* format)
 +{
 +    try
 +    {
 +        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);
 +        strncpy(cstr, sstr.c_str(), sstr.length());
 +        return cstr;
 +    }
 +    catch(std::runtime_error& err)
 +    {
 +        PWARN("Error processing time64 %" PRId64 ": %s", time, err.what());
 +        return nullptr;
 +    }
 +    catch(std::logic_error& err)
 +    {
 +        PWARN("Error processing time64 %" PRId64 ": %s", time, err.what());
 +        return nullptr;
 +    }
 +}
 +
 +/********************************************************************\
 +\********************************************************************/
 +
 +static void
 +timespec_normalize(Timespec *t)
 +{
 +    if (t->tv_nsec > NANOS_PER_SECOND)
 +    {
 +        t->tv_sec += (t->tv_nsec / NANOS_PER_SECOND);
 +        t->tv_nsec = t->tv_nsec % NANOS_PER_SECOND;
 +    }
 +
 +    if (t->tv_nsec < - NANOS_PER_SECOND)
 +    {
 +        t->tv_sec += - (-t->tv_nsec / NANOS_PER_SECOND);
 +        t->tv_nsec = - (-t->tv_nsec % NANOS_PER_SECOND);
 +    }
 +
 +    if (t->tv_sec > 0 && t->tv_nsec < 0)
 +    {
 +        t->tv_sec--;
 +        t->tv_nsec = NANOS_PER_SECOND + t->tv_nsec;
 +    }
 +
 +    if (t->tv_sec < 0 && t->tv_nsec > 0)
 +    {
 +        t->tv_sec++;
 +        t->tv_nsec = - NANOS_PER_SECOND + t->tv_nsec;
 +    }
 +    return;
 +}
 +
 +gboolean
 +timespec_equal (const Timespec *ta, const Timespec *tb)
 +{
 +    Timespec pta, ptb;
 +
 +    if (ta == tb) return TRUE;
 +/* Copy and normalize the copies */
 +    pta = *ta;
 +    ptb = *tb;
 +    timespec_normalize (&pta);
 +    timespec_normalize (&ptb);
 +
 +    if (pta.tv_sec != ptb.tv_sec) return FALSE;
 +    if (pta.tv_nsec != ptb.tv_nsec) return FALSE;
 +    return TRUE;
 +}
 +
 +gint
 +timespec_cmp(const Timespec *ta, const Timespec *tb)
 +{
 +    Timespec pta, ptb;
 +
 +    if (ta == tb) return 0;
 +/* Copy and normalize the copies */
 +    pta = *ta;
 +    ptb = *tb;
 +    timespec_normalize (&pta);
 +    timespec_normalize (&ptb);
 +
 +    if (pta.tv_sec < ptb.tv_sec) return -1;
 +    if (pta.tv_sec > ptb.tv_sec) return 1;
 +    if (pta.tv_nsec < ptb.tv_nsec) return -1;
 +    if (pta.tv_nsec > ptb.tv_nsec) return 1;
 +    return 0;
 +}
 +
 +Timespec
 +timespec_diff(const Timespec *ta, const Timespec *tb)
 +{
 +    Timespec retval;
 +    retval.tv_sec = ta->tv_sec - tb->tv_sec;
 +    retval.tv_nsec = ta->tv_nsec - tb->tv_nsec;
 +    timespec_normalize(&retval);
 +    return retval;
 +}
 +
 +Timespec
 +timespec_abs(const Timespec *t)
 +{
 +    Timespec retval = *t;
 +
 +    timespec_normalize(&retval);
 +    if (retval.tv_sec < 0)
 +    {
 +        retval.tv_sec = - retval.tv_sec;
 +        retval.tv_nsec = - retval.tv_nsec;
 +    }
 +
 +    return retval;
 +}
 +
 +/* Converts any time on a day to midday that day.
 +
 + * given a timepair contains any time on a certain day (local time)
 + * converts it to be midday that day.
 + */
 +Timespec
 +timespecCanonicalDayTime(Timespec t)
 +{
 +    struct tm tm;
 +    Timespec retval;
 +    time64 t_secs = t.tv_sec + (t.tv_nsec / NANOS_PER_SECOND);
 +    gnc_localtime_r(&t_secs, &tm);
 +    gnc_tm_set_day_middle(&tm);
 +    retval.tv_sec = gnc_mktime(&tm);
 +    retval.tv_nsec = 0;
 +    return retval;
 +}
 +
 +/* NB: month is 1-12, year is 0001 - 9999. */
 +int gnc_date_get_last_mday (int month, int year)
 +{
 +    static int last_day_of_month[2][12] =
 +    {
 +        /* non leap */ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
 +        /*   leap   */ {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
 +    };
 +
 +    /* Is this a leap year? */
 +    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];
 +}
 +
 +QofDateFormat qof_date_format_get (void)
 +{
 +    return dateFormat;
 +}
 +
 +void qof_date_format_set(QofDateFormat df)
 +{
 +    if (df >= DATE_FORMAT_FIRST && df <= DATE_FORMAT_LAST)
 +    {
 +        prevQofDateFormat = dateFormat;
 +        dateFormat = df;
 +    }
 +    else
 +    {
 +        /* hack alert - Use a neutral default. */
 +        PERR("non-existent date format set attempted. Setting ISO default");
 +        prevQofDateFormat = dateFormat;
 +        dateFormat = QOF_DATE_FORMAT_ISO;
 +    }
 +
 +    return;
 +}
 +
 +/* set date completion method
 +
 +set dateCompletion to one of QOF_DATE_COMPLETION_THISYEAR (for
 +completing the year to the current calendar year) or
 +QOF_DATE_COMPLETION_SLIDING (for using a sliding 12-month window). The
 +sliding window starts 'backmonth' months before the current month (0-11).
 +checks to make sure it's a legal value
 +
 +param QofDateCompletion: indicates preferred completion method
 +param int: the number of months to go back in time (0-11)
 +
 +return void
 +
 +Globals: dateCompletion dateCompletionBackMonths
 +*/
 +void qof_date_completion_set(QofDateCompletion dc, int backmonths)
 +{
 +    if (dc == QOF_DATE_COMPLETION_THISYEAR ||
 +            dc == QOF_DATE_COMPLETION_SLIDING)
 +    {
 +        dateCompletion = dc;
 +    }
 +    else
 +    {
 +        /* hack alert - Use a neutral default. */
 +        PERR("non-existent date completion set attempted. Setting current year completion as default");
 +        dateCompletion = QOF_DATE_COMPLETION_THISYEAR;
 +    }
 +
 +    if (backmonths < 0)
 +    {
 +        backmonths = 0;
 +    }
 +    else if (backmonths > 11)
 +    {
 +        backmonths = 11;
 +    }
 +    dateCompletionBackMonths = backmonths;
 +
 +    return;
 +}
 +
 +/*
 + qof_date_format_get_string
 + get the date format string for the current format
 + returns: string
 +
 + Globals: dateFormat
 +*/
 +const gchar *qof_date_format_get_string(QofDateFormat df)
 +{
 +    switch (df)
 +    {
 +    case QOF_DATE_FORMAT_US:
 +        return "%m/%d/%Y";
 +    case QOF_DATE_FORMAT_UK:
 +        return "%d/%m/%Y";
 +    case QOF_DATE_FORMAT_CE:
 +        return "%d.%m.%Y";
 +    case QOF_DATE_FORMAT_UTC:
 +        return "%Y-%m-%dT%H:%M:%SZ";
 +    case QOF_DATE_FORMAT_ISO:
 +        return "%Y-%m-%d";
 +    case QOF_DATE_FORMAT_UNSET: // use global
 +        return qof_date_format_get_string (dateFormat);
 +    case QOF_DATE_FORMAT_LOCALE:
 +    default:
 +        break;
 +    };
 +    return GNC_D_FMT;
 +}
 +
 +const gchar *qof_date_text_format_get_string(QofDateFormat df)
 +{
 +    switch (df)
 +    {
 +    case QOF_DATE_FORMAT_US:
 +        return "%b %d, %Y";
 +    case QOF_DATE_FORMAT_UK:
 +    case QOF_DATE_FORMAT_CE:
 +        return "%d %b %Y";
 +    case QOF_DATE_FORMAT_UTC:
 +        return "%Y-%m-%dT%H:%M:%SZ";
 +    case QOF_DATE_FORMAT_ISO:
 +        return "%Y-%b-%d";
 +    case QOF_DATE_FORMAT_UNSET: // use global
 +        return qof_date_text_format_get_string (dateFormat);
 +    case QOF_DATE_FORMAT_LOCALE:
 +    default:
 +        break;
 +    };
 +    return GNC_D_FMT;
 +}
 +
 +size_t
 +qof_print_date_dmy_buff (char * buff, size_t len, int day, int month, int year)
 +{
 +    if (!buff) return 0;
 +    try
 +    {
 +        GncDate date(year, month, day);
 +        std::string str = date.format(qof_date_format_get_string(dateFormat));
 +        strncpy(buff, str.c_str(), len);
 +        if (str.length() >= len)
 +            buff[len - 1] = '\0';
 +    }
 +    catch(std::logic_error& err)
 +    {
 +        PWARN("Error processing year-month-day %d-%d-%d: %s",
 +              year, month, day, err.what());
 +    }
 +    catch(std::runtime_error& err)
 +    {
 +        PWARN("Error processing year-month-day %d-%d-%d: %s",
 +              year, month, day, err.what());
 +    }
 +    return strlen(buff);
 +}
 +
 +size_t
 +qof_print_date_buff (char * buff, size_t len, time64 t)
 +{
 +    if (!buff) return 0;
- 
 +    try
 +    {
-         GncDateTime gncdt(clamp_time(t));
++        GncDateTime gncdt(t);
 +        std::string str = gncdt.format(qof_date_format_get_string(dateFormat));
 +        strncpy(buff, str.c_str(), len);
 +        if (str.length() >= len)
 +            buff[len - 1] = '\0';
 +    }
 +    catch(std::logic_error& err)
 +    {
 +        PWARN("Error processing time64 %" PRId64 ": %s", t, err.what());
 +    }
 +    catch(std::runtime_error& err)
 +    {
 +        PWARN("Error processing time64 %" PRId64 ": %s", t, err.what());
 +    }
 +    return strlen(buff);
 +}
 +
 +size_t
 +qof_print_gdate( char *buf, size_t len, const GDate *gd )
 +{
 +    GDate date;
 +    g_date_clear (&date, 1);
 +    date = *gd;
 +    return qof_print_date_dmy_buff( buf, len,
 +                                    g_date_get_day(&date),
 +                                    g_date_get_month(&date),
 +                                    g_date_get_year(&date) );
 +}
 +
 +char *
 +qof_print_date (time64 t)
 +{
 +    char buff[MAX_DATE_LENGTH];
 +    memset (buff, 0, sizeof (buff));
 +    qof_print_date_buff (buff, MAX_DATE_LENGTH, t);
 +    return g_strdup (buff);
 +}
 +
 +const char *
 +gnc_print_date (Timespec ts)
 +{
 +    static char buff[MAX_DATE_LENGTH];
 +    time64 t;
 +
 +    memset (buff, 0, sizeof (buff));
 +    t = ts.tv_sec + (time64)(ts.tv_nsec / 1000000000.0);
 +
 +    qof_print_date_buff (buff, MAX_DATE_LENGTH, t);
 +
 +    return buff;
 +}
 +
 +/* ============================================================== */
 +
 +/* return the greatest integer <= a/b; works for b > 0 and positive or
 +   negative a. */
 +static int
 +floordiv(int a, int b)
 +{
 +    if (a >= 0)
 +    {
 +        return a / b;
 +    }
 +    else
 +    {
 +        return - ((-a - 1) / b) - 1;
 +    }
 +}
 +
 +/* Convert a string into  day, month and year integers
 +
 +    Convert a string into  day / month / year integers according to
 +    the current dateFormat value.
 +
 +    This function will always parse a single number as the day of
 +    the month, regardless of the ordering of the dateFormat value.
 +    Two numbers will always be parsed as the day and the month, in
 +    the same order that they appear in the dateFormat value.  Three
 +    numbers are parsed exactly as specified in the dateFormat field.
 +
 +    Fully formatted UTC timestamp strings are converted separately.
 +
 +    param   buff - pointer to date string
 +    param     day -  will store day of the month as 1 ... 31
 +    param     month - will store month of the year as 1 ... 12
 +    param     year - will store the year (4-digit)
 +
 +    return TRUE if date appeared to be valid.
 +
 +    Globals: global dateFormat value
 +*/
 +static gboolean
 +qof_scan_date_internal (const char *buff, int *day, int *month, int *year,
 +                        QofDateFormat which_format)
 +{
 +    char *dupe, *tmp, *first_field, *second_field, *third_field;
 +    int iday, imonth, iyear;
 +    int now_day, now_month, now_year;
 +    struct tm *now, utc;
 +    time64 secs;
 +
 +    if (!buff) return(FALSE);
 +
 +    if (which_format == QOF_DATE_FORMAT_UTC)
 +    {
 +        if (strptime(buff, QOF_UTC_DATE_FORMAT, &utc)
 +            || strptime (buff, "%Y-%m-%d", &utc))
 +        {
 +            *day = utc.tm_mday;
 +            *month = utc.tm_mon + 1;
 +            *year = utc.tm_year + 1900;
 +            return TRUE;
 +        }
 +        else
 +        {
 +            return FALSE;
 +        }
 +    }
 +    dupe = g_strdup (buff);
 +
 +    tmp = dupe;
 +    first_field = NULL;
 +    second_field = NULL;
 +    third_field = NULL;
 +
 +    /* Use strtok to find delimiters */
 +    if (tmp)
 +    {
 +        static const char *delims = ".,-+/\\()년월年月 ";
 +
 +        first_field = strtok (tmp, delims);
 +        if (first_field)
 +        {
 +            second_field = strtok (NULL, delims);
 +            if (second_field)
 +            {
 +                third_field = strtok (NULL, delims);
 +            }
 +        }
 +    }
 +
 +    /* today's date */
 +    gnc_time (&secs);
 +    now = gnc_localtime (&secs);
 +    now_day = now->tm_mday;
 +    now_month = now->tm_mon + 1;
 +    now_year = now->tm_year + 1900;
 +    gnc_tm_free (now);
 +
 +    /* set defaults: if day or month appear to be blank, use today's date */
 +    iday = now_day;
 +    imonth = now_month;
 +    iyear = -1;
 +
 +    /* get numeric values */
 +    switch (which_format)
 +    {
 +    case QOF_DATE_FORMAT_LOCALE:
 +        if (buff[0] != '\0')
 +        {
 +            struct tm thetime;
 +            gchar *format = g_strdup (GNC_D_FMT);
 +            gchar *stripped_format = g_strdup (GNC_D_FMT);
 +            gint counter = 0, stripped_counter = 0;
 +
 +            /* strptime can't handle the - format modifier
 +             * let's strip it out of the format before using it
 +             */
 +            while (format[counter] != '\0')
 +            {
 +                stripped_format[stripped_counter] = format[counter];
 +                if ((format[counter] == '%') && (format[counter+1] == '-'))
 +                    counter++;  // skip - format modifier
 +
 +                counter++;
 +                stripped_counter++;
 +            }
 +            stripped_format[stripped_counter] = '\0';
 +            g_free (format);
 +
 +
 +            /* Parse time string. */
 +            memset(&thetime, -1, sizeof(struct tm));
 +            strptime (buff, stripped_format, &thetime);
 +            g_free (stripped_format);
 +
 +            if (third_field)
 +            {
 +                /* Easy.  All three values were parsed. */
 +                iyear = thetime.tm_year + 1900;
 +                iday = thetime.tm_mday;
 +                imonth = thetime.tm_mon + 1;
 +            }
 +            else if (second_field)
 +            {
 +                /* Hard. Two values parsed.  Figure out the ordering. */
 +                if (thetime.tm_year == -1)
 +                {
 +                    /* %m-%d or %d-%m. Don't care. Already parsed correctly. */
 +                    iday = thetime.tm_mday;
 +                    imonth = thetime.tm_mon + 1;
 +                }
 +                else if (thetime.tm_mon != -1)
 +                {
 +                    /* Must be %Y-%m-%d. Reparse as %m-%d.*/
 +                    imonth = atoi(first_field);
 +                    iday = atoi(second_field);
 +                }
 +                else
 +                {
 +                    /* Must be %Y-%d-%m. Reparse as %d-%m. */
 +                    iday = atoi(first_field);
 +                    imonth = atoi(second_field);
 +                }
 +            }
 +            else if (first_field)
 +            {
 +                iday = atoi(first_field);
 +            }
 +        }
 +        break;
 +    case QOF_DATE_FORMAT_UK:
 +    case QOF_DATE_FORMAT_CE:
 +        if (third_field)
 +        {
 +            iday = atoi(first_field);
 +            imonth = atoi(second_field);
 +            iyear = atoi(third_field);
 +        }
 +        else if (second_field)
 +        {
 +            iday = atoi(first_field);
 +            imonth = atoi(second_field);
 +        }
 +        else if (first_field)
 +        {
 +            iday = atoi(first_field);
 +        }
 +        break;
 +    case QOF_DATE_FORMAT_ISO:
 +        if (third_field)
 +        {
 +            iyear = atoi(first_field);
 +            imonth = atoi(second_field);
 +            iday = atoi(third_field);
 +        }
 +        else if (second_field)
 +        {
 +            imonth = atoi(first_field);
 +            iday = atoi(second_field);
 +        }
 +        else if (first_field)
 +        {
 +            iday = atoi(first_field);
 +        }
 +        break;
 +    case QOF_DATE_FORMAT_US:
 +    default:
 +        if (third_field)
 +        {
 +            imonth = atoi(first_field);
 +            iday = atoi(second_field);
 +            iyear = atoi(third_field);
 +        }
 +        else if (second_field)
 +        {
 +            imonth = atoi(first_field);
 +            iday = atoi(second_field);
 +        }
 +        else if (first_field)
 +        {
 +            iday = atoi(first_field);
 +        }
 +        break;
 +    }
 +
 +    g_free (dupe);
 +
 +    if ((12 < imonth) || (31 < iday))
 +    {
 +        /*
 +         * Ack! Thppfft!  Someone just fed this routine a string in the
 +         * wrong date format.  This is known to happen if a register
 +         * window is open when changing the date format.  Try the
 +         * previous date format.  If that doesn't work, see if we can
 +         * exchange month and day. If that still doesn't work,
 +         * bail and give the caller what they asked for (garbage)
 +         * parsed in the new format.
 +         *
 +         * Note: This test cannot detect any format change that only
 +         * swaps month and day field, if the day is 12 or less.  This is
 +         * deemed acceptable given the obscurity of this bug.
 +         */
 +        if ((which_format != prevQofDateFormat) &&
 +                qof_scan_date_internal(buff, day, month, year, prevQofDateFormat))
 +        {
 +            return(TRUE);
 +        }
 +        if ((12 < imonth) && (12 >= iday))
 +        {
 +            int tmp = imonth;
 +            imonth = iday;
 +            iday = tmp;
 +        }
 +        else
 +        {
 +            return FALSE;
 +        }
 +    }
 +
 +    /* if no year was entered, choose a year according to the
 +       dateCompletion preference. If it is
 +       QOF_DATE_COMPLETION_THISYEAR, use the current year, else if it
 +       is QOF_DATE_COMPLETION_SLIDING, use a sliding window that
 +       starts dateCompletionBackMonths before the current month.
 +
 +       We go by whole months, rather than days, because presumably
 +       this is less confusing.
 +    */
 +
 +    if (iyear == -1)
 +    {
 +        if (dateCompletion == QOF_DATE_COMPLETION_THISYEAR)
 +        {
 +            iyear = now_year;  /* use the current year */
 +        }
 +        else
 +        {
 +            iyear = now_year - floordiv(imonth - now_month +
 +                                        dateCompletionBackMonths, 12);
 +        }
 +    }
 +
 +    /* If the year entered is smaller than 100, assume we mean the current
 +       century (and are not revising some roman emperor's books) */
 +    if (iyear < 100)
 +        iyear += ((int) ((now_year + 50 - iyear) / 100)) * 100;
 +
 +    if (year) *year = iyear;
 +    if (month) *month = imonth;
 +    if (day) *day = iday;
 +    return(TRUE);
 +}
 +
 +gboolean
 +qof_scan_date (const char *buff, int *day, int *month, int *year)
 +{
 +    return qof_scan_date_internal(buff, day, month, year, dateFormat);
 +}
 +
 +/* Return the field separator for the current date format
 +return date character
 +*/
 +char dateSeparator (void)
 +{
 +    static char locale_separator = '\0';
 +
 +    switch (dateFormat)
 +    {
 +    case QOF_DATE_FORMAT_CE:
 +        return '.';
 +    case QOF_DATE_FORMAT_ISO:
 +    case QOF_DATE_FORMAT_UTC:
 +        return '-';
 +    case QOF_DATE_FORMAT_US:
 +    case QOF_DATE_FORMAT_UK:
 +    default:
 +        return '/';
 +    case QOF_DATE_FORMAT_LOCALE:
 +        if (locale_separator != '\0')
 +            return locale_separator;
 +        else
 +        {
 +            /* Make a guess */
 +            gchar string[256];
 +            struct tm tm;
 +            time64 secs;
 +            gchar *s;
 +
 +            secs = gnc_time (NULL);
 +            gnc_localtime_r(&secs, &tm);
 +            qof_strftime(string, sizeof(string), GNC_D_FMT, &tm);
 +
 +            for (s = string; *s != '\0'; s++)
 +                if (!isdigit(*s))
 +                    return (locale_separator = *s);
 +        }
 +        break;
 +    }
 +    return '\0';
 +}
 +
 +/* The following functions have Win32 forms in qof-win32.c */
 +#ifndef G_OS_WIN32
 +gchar *
 +qof_time_format_from_utf8(const gchar *utf8_format)
 +{
 +    gchar *retval;
 +    GError *error = NULL;
 +
 +    retval = g_locale_from_utf8(utf8_format, -1, NULL, NULL, &error);
 +
 +    if (!retval)
 +    {
 +        g_warning("Could not convert format '%s' from UTF-8: %s", utf8_format,
 +                  error->message);
 +        g_error_free(error);
 +    }
 +    return retval;
 +}
 +
 +gchar *
 +qof_formatted_time_to_utf8(const gchar *locale_string)
 +{
 +    gchar *retval;
 +    GError *error = NULL;
 +
 +    retval = g_locale_to_utf8(locale_string, -1, NULL, NULL, &error);
 +
 +    if (!retval)
 +    {
 +        g_warning("Could not convert '%s' to UTF-8: %s", locale_string,
 +                  error->message);
 +        g_error_free(error);
 +    }
 +    return retval;
 +}
 +#endif /* G_OS_WIN32 */
 +
 +static gchar *
 +qof_format_time(const gchar *format, const struct tm *tm)
 +{
 +    gchar *locale_format, *tmpbuf, *retval;
 +    gsize tmplen, tmpbufsize;
 +
 +    g_return_val_if_fail(format, 0);
 +    g_return_val_if_fail(tm, 0);
 +
 +    locale_format = qof_time_format_from_utf8(format);
 +    if (!locale_format)
 +        return NULL;
 +
 +    tmpbufsize = MAX(128, strlen(locale_format) * 2);
 +    while (TRUE)
 +    {
 +        tmpbuf = static_cast<gchar*>(g_malloc(tmpbufsize));
 +
 +        /* Set the first byte to something other than '\0', to be able to
 +         * recognize whether strftime actually failed or just returned "".
 +         */
 +        tmpbuf[0] = '\1';
 +        tmplen = strftime(tmpbuf, tmpbufsize, locale_format, tm);
 +
 +        if (tmplen == 0 && tmpbuf[0] != '\0')
 +        {
 +            g_free(tmpbuf);
 +            tmpbufsize *= 2;
 +
 +            if (tmpbufsize > 65536)
 +            {
 +                g_warning("Maximum buffer size for qof_format_time "
 +                          "exceeded: giving up");
 +                g_free(locale_format);
 +
 +                return NULL;
 +            }
 +        }
 +        else
 +        {
 +            break;
 +        }
 +    }
 +    g_free(locale_format);
 +
 +    retval = qof_formatted_time_to_utf8(tmpbuf);
 +    g_free(tmpbuf);
 +
 +    return retval;
 +}
 +
 +gsize
 +qof_strftime(gchar *buf, gsize max, const gchar *format, const struct tm *tm)
 +{
 +    gsize convlen, retval;
 +    gchar *convbuf;
 +
 +    g_return_val_if_fail(buf, 0);
 +    g_return_val_if_fail(max > 0, 0);
 +    g_return_val_if_fail(format, 0);
 +    g_return_val_if_fail(tm, 0);
 +
 +    convbuf = qof_format_time(format, tm);
 +    if (!convbuf)
 +    {
 +        buf[0] = '\0';
 +        return 0;
 +    }
 +
 +    convlen = strlen(convbuf);
 +
 +    if (max <= convlen)
 +    {
 +        /* Ensure only whole characters are copied into the buffer. */
 +        gchar *end = g_utf8_find_prev_char(convbuf, convbuf + max);
 +        g_assert(end != NULL);
 +        convlen = end - convbuf;
 +
 +        /* Return 0 because the buffer isn't large enough. */
 +        retval = 0;
 +    }
 +    else
 +    {
 +        retval = convlen;
 +    }
 +
 +    memcpy(buf, convbuf, convlen);
 +    buf[convlen] = '\0';
 +    g_free(convbuf);
 +
 +    return retval;
 +}
 +
 +/********************************************************************\
 +\********************************************************************/
 +
 +gchar *
 +gnc_date_timestamp (void)
 +{
 +    return gnc_print_time64(gnc_time(nullptr), "%Y%m%d%H%M%S");
 +}
 +
 +/********************************************************************\
 + * iso 8601 datetimes should look like 1998-07-02 11:00:00.68-05
 +\********************************************************************/
 +/* Unfortunately, not all strptime or struct tm implementations
 + * support timezones, so we have to do this with sscanf.
 + */
 +
 +#define ISO_DATE_FORMAT "%d-%d-%d %d:%d:%lf%s"
 +Timespec
 +gnc_iso8601_to_timespec_gmt(const char *cstr)
 +{
 +    time64 time;
 +    if (!cstr) return {0, 0};
 +    try
 +    {
 +        GncDateTime gncdt(cstr);
 +        return {static_cast<time64>(gncdt), 0};
 +    }
 +    catch(std::logic_error& err)
 +    {
 +        PWARN("Error processing %s: %s", cstr, err.what());
 +        return {0, 0};
 +    }
 +    catch(std::runtime_error& err)
 +    {
 +        PWARN("Error processing time64 %s: %s", cstr, err.what());
 +        return {0, 0};
 +    }
 +}
 +
 +/********************************************************************\
 +\********************************************************************/
 +
 +char *
 +gnc_timespec_to_iso8601_buff (Timespec ts, char * buff)
 +{
 +    constexpr size_t max_iso_date_length = 32;
 +    const char* format = "%Y-%m-%d %H:%M:%s %q";
 +
 +    if (! buff) return NULL;
 +    try
 +    {
 +        GncDateTime gncdt(ts.tv_sec);
 +        auto sstr = gncdt.format(format);
 +
 +        memset(buff, 0, sstr.length() + 1);
 +        strncpy(buff, sstr.c_str(), sstr.length());
 +        return buff + sstr.length();
 +    }
 +    catch(std::logic_error& err)
 +    {
 +        PWARN("Error processing time64 %" PRId64 ": %s", ts.tv_sec, err.what());
 +        return buff;
 +    }
 +    catch(std::runtime_error& err)
 +    {
 +        PWARN("Error processing time64 %" PRId64 ": %s", ts.tv_sec, err.what());
 +        return buff;
 +    }
 +}
 +
 +void
 +gnc_timespec2dmy (Timespec t, int *day, int *month, int *year)
 +{
 +    struct tm result;
 +    time64 t_secs = t.tv_sec + (t.tv_nsec / NANOS_PER_SECOND);
 +    gnc_localtime_r(&t_secs, &result);
 +
 +    if (day) *day = result.tm_mday;
 +    if (month) *month = result.tm_mon + 1;
 +    if (year) *year = result.tm_year + 1900;
 +}
 +
 +#define THIRTY_TWO_YEARS 0x3c30fc00LL
 +
 +static Timespec
 +gnc_dmy2timespec_internal (int day, int month, int year, DayPart day_part)
 +{
 +    try
 +    {
 +        auto date = GncDate(year, month, day);
 +        return { static_cast<time64>(GncDateTime (date, day_part)), 0 };
 +    }
 +    catch(const std::logic_error& err)
 +    {
 +        PWARN("Date computation error from Y-M-D %d-%d-%d: %s",
 +              year, month, day, err.what());
 +        return {INT64_MAX, 0};
 +    }
 +    catch(const std::runtime_error& err)
 +    {
 +        PWARN("Date computation error from Y-M-D %d-%d-%d: %s",
 +              year, month, day, err.what());
 +        return {INT64_MAX, 0};
 +    }
 +}
 +
 +Timespec
 +gnc_dmy2timespec (int day, int month, int year)
 +{
 +    return gnc_dmy2timespec_internal (day, month, year, DayPart::start);
 +}
 +
 +Timespec
 +gnc_dmy2timespec_end (int day, int month, int year)
 +{
 +    return gnc_dmy2timespec_internal (day, month, year, DayPart::end);
 +}
 +
 +Timespec
 +gnc_dmy2timespec_neutral (int day, int month, int year)
 +{
 +    return gnc_dmy2timespec_internal (day, month, year, DayPart::neutral);
 +}
 +/********************************************************************\
 +\********************************************************************/
 +void
 +timespecFromTime64 ( Timespec *ts, time64 t )
 +{
-     ts->tv_sec = clamp_time (t);
++    ts->tv_sec = t;
 +    ts->tv_nsec = 0;
 +}
 +
 +Timespec
 +timespec_now()
 +{
 +    Timespec ts;
 +    ts.tv_sec = gnc_time(NULL);
 +    ts.tv_nsec = 0;
 +    return ts;
 +}
 +
 +time64
 +timespecToTime64 (Timespec ts)
 +{
 +    return ts.tv_sec;
 +}
 +
 +/* The GDate setter functions all in the end use g_date_set_time_t,
 + * which in turn relies on localtime and is therefore subject to the
 + * 2038 bug.
 + */
 +GDate timespec_to_gdate (Timespec ts)
 +{
 +    GDate result;
 +
 +    g_date_clear (&result, 1);
 +    GncDateTime time(ts.tv_sec);
 +    auto date = time.date().year_month_day();
 +    g_date_set_dmy (&result, date.day, static_cast<GDateMonth>(date.month),
 +                    date.year);
 +    g_assert(g_date_valid (&result));
 +
 +    return result;
 +}
 +
 +GDate* gnc_g_date_new_today ()
 +{
 +    GncDate gncd;
 +    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));
 +    return result;
 +}void
 +
 +gnc_gdate_set_today (GDate* gd)
 +{
 +    GDate *today = gnc_g_date_new_today ();
 +    g_date_set_julian (gd, g_date_get_julian (today));
 +    g_date_free (today);
 +}
 +
 +void
 +gnc_gdate_set_time64 (GDate* gd, time64 time)
 +{
 +    struct tm tm;
 +    gnc_localtime_r(&time, &tm);
 +    g_date_set_dmy (gd, tm.tm_mday,
 +                    static_cast<GDateMonth>(tm.tm_mon + 1),
 +                    tm.tm_year + 1900);
 +}
 +
 +Timespec gdate_to_timespec (GDate d)
 +{
 +    return gnc_dmy2timespec_neutral (g_date_get_day(&d),
 +                                     g_date_get_month(&d),
 +                                     g_date_get_year(&d));
 +}
 +
 +static void
 +gnc_tm_get_day_start (struct tm *tm, time64 time_val)
 +{
 +    /* Get the equivalent time structure */
 +    if (!gnc_localtime_r(&time_val, tm))
 +        return;
 +    gnc_tm_set_day_start(tm);
 +}
 +
 +static void
 +gnc_tm_get_day_end (struct tm *tm, time64 time_val)
 +{
 +    /* Get the equivalent time structure */
 +    if (!gnc_localtime_r(&time_val, tm))
 +        return;
 +    gnc_tm_set_day_end(tm);
 +}
 +
 +time64
 +gnc_time64_get_day_start (time64 time_val)
 +{
 +    struct tm tm;
 +    time64 new_time;
 +
 +    gnc_tm_get_day_start(&tm, time_val);
 +    new_time = gnc_mktime(&tm);
 +    return new_time;
 +}
 +
 +time64
 +gnc_time64_get_day_end (time64 time_val)
 +{
 +    struct tm tm;
 +    time64 new_time;
 +
 +    gnc_tm_get_day_end(&tm, time_val);
 +    new_time = gnc_mktime(&tm);
 +    return new_time;
 +}
 +
 +/* ======================================================== */
 +
 +void
 +gnc_tm_get_today_start (struct tm *tm)
 +{
 +    gnc_tm_get_day_start(tm, time(NULL));
 +}
 +
 +void
 +gnc_tm_get_today_end (struct tm *tm)
 +{
 +    gnc_tm_get_day_end(tm, time(NULL));
 +}
 +
 +time64
 +gnc_time64_get_today_start (void)
 +{
 +    struct tm tm;
 +
 +    gnc_tm_get_day_start(&tm, time(NULL));
 +    return gnc_mktime(&tm);
 +}
 +
 +time64
 +gnc_time64_get_today_end (void)
 +{
 +    struct tm tm;
 +
 +    gnc_tm_get_day_end(&tm, time(NULL));
 +    return gnc_mktime(&tm);
 +}
 +
 +void
 +gnc_dow_abbrev(gchar *buf, int buf_len, int dow)
 +{
 +    struct tm my_tm;
 +    int i;
 +
 +    memset(buf, 0, buf_len);
 +    memset(&my_tm, 0, sizeof(struct tm));
 +    my_tm.tm_wday = dow;
 +    i = qof_strftime(buf, buf_len, "%a", &my_tm);
 +    buf[i] = 0;
 +}
 +
 +/* *******************************************************************
 + *  GValue handling
 + ********************************************************************/
 +static gpointer
 +timespec_boxed_copy_func( gpointer in_timespec )
 +{
 +    Timespec* newvalue;
 +
 +    newvalue = static_cast<Timespec*>(g_malloc (sizeof (Timespec)));
 +    memcpy( newvalue, in_timespec, sizeof( Timespec ) );
 +
 +    return newvalue;
 +}
 +
 +static void
 +timespec_boxed_free_func( gpointer in_timespec )
 +{
 +    g_free( in_timespec );
 +}
 +
 +GType
 +timespec_get_type( void )
 +{
 +    static GType type = 0;
 +
 +    if ( type == 0 )
 +    {
 +        type = g_boxed_type_register_static( "timespec",
 +                                             timespec_boxed_copy_func,
 +                                             timespec_boxed_free_func );
 +    }
 +    return type;
 +}
 +
 +Testfuncs*
 +gnc_date_load_funcs (void)
 +{
 +    Testfuncs *tf = g_slice_new (Testfuncs);
 +    tf->timespec_normalize = timespec_normalize;
 +    return tf;
 +}
 +
 +/* ================================================= */
 +
 +gboolean
 +gnc_gdate_equal(gconstpointer gda, gconstpointer gdb)
 +{
 +    return (g_date_compare( (GDate*)gda, (GDate*)gdb ) == 0 ? TRUE : FALSE);
 +}
 +
 +guint
 +gnc_gdate_hash( gconstpointer gd )
 +{
 +    gint val = (g_date_get_year( (GDate*)gd ) * 10000)
 +               + (g_date_get_month( (GDate*)gd ) * 100)
 +               + g_date_get_day( (GDate*)gd );
 +    return g_int_hash( &val );
 +}
 +
 +/* ================================================= */
 +
 +time64
 +gnc_time64_get_day_start_gdate (const GDate *date)
 +{
 +    struct tm stm;
 +    time64 secs;
 +
 +    /* First convert to a 'struct tm' */
 +    g_date_to_struct_tm (date, &stm);
 +
 +    /* Then convert to number of seconds */
 +    secs = gnc_mktime (&stm);
 +    return secs;
 +}
 +
 +time64
 +gnc_time64_get_day_end_gdate (const GDate *date)
 +{
 +    struct tm stm;
 +    time64 secs;
 +
 +    /* First convert to a 'struct tm' */
 +    g_date_to_struct_tm(date, &stm);
 +
 +    /* Force to th last second of the day */
 +    stm.tm_hour = 23;
 +    stm.tm_min = 59;
 +    stm.tm_sec = 59;
 +    stm.tm_isdst = -1;
 +
 +    /* Then convert to number of seconds */
 +    secs = gnc_mktime (&stm);
 +    return secs;
 +}
 +
 +/* ================================================= */
 +
 +void
 +gnc_gdate_set_month_start (GDate *date)
 +{
 +    g_date_set_day(date, 1);
 +}
 +
 +/** Convert a GDate to the last day of the month.  This routine has no
 + *  knowledge of how many days are in a month, whether its a leap
 + *  year, etc.  All that information is contained in the glib date
 + *  functions.
 + *
 + *  @param date The GDate to modify.
 + */
 +void
 +gnc_gdate_set_month_end (GDate *date)
 +{
 +    /* First set the start of next month. */
 +    g_date_set_day(date, 1);
 +    g_date_add_months(date, 1);
 +
 +    /* Then back up one day */
 +    g_date_subtract_days(date, 1);
 +}
 +
 +/** Convert a GDate to the first day of the prebvious month.  This
 + *  routine has no knowledge of how many days are in a month, whether
 + *  its a leap year, etc.  All that information is contained in the
 + *  glib date functions.
 + *
 + *  @param date The GDate to modify.
 + */
 +void
 +gnc_gdate_set_prev_month_start (GDate *date)
 +{
 +    g_date_set_day(date, 1);
 +    g_date_subtract_months(date, 1);
 +}
 +
 +/** Convert a GDate to the last day of the prebvious month.  This
 + *  routine has no knowledge of how many days are in a month, whether
 + *  its a leap year, etc.  All that information is contained in the
 + *  glib date functions.
 + *
 + *  @param date The GDate to modify.
 + */
 +void
 +gnc_gdate_set_prev_month_end (GDate *date)
 +{
 +    /* This will correctly handle the varying month lengths */
 +    g_date_set_day(date, 1);
 +    g_date_subtract_days(date, 1);
 +}
 +
 +/* ================================================= */
 +
 +void
 +gnc_gdate_set_quarter_start (GDate *date)
 +{
 +    gint months;
 +
 +    /* Set the date to the first day of the specified month. */
 +    g_date_set_day(date, 1);
 +
 +    /* Back up 0-2 months */
 +    months = (g_date_get_month(date) - G_DATE_JANUARY) % 3;
 +    g_date_subtract_months(date, months);
 +}
 +
 +void
 +gnc_gdate_set_quarter_end (GDate *date)
 +{
 +    gint months;
 +
 +    /* Set the date to the first day of the specified month. */
 +    g_date_set_day(date, 1);
 +
 +    /* Add 1-3 months to get the first day of the next quarter.*/
 +    months = (g_date_get_month(date) - G_DATE_JANUARY) % 3;
 +    g_date_add_months(date, 3 - months);
 +
 +    /* Now back up one day */
 +    g_date_subtract_days(date, 1);
 +}
 +
 +void
 +gnc_gdate_set_prev_quarter_start (GDate *date)
 +{
 +    gnc_gdate_set_quarter_start(date);
 +    g_date_subtract_months(date, 3);
 +}
 +
 +void
 +gnc_gdate_set_prev_quarter_end (GDate *date)
 +{
 +    gnc_gdate_set_quarter_end(date);
 +    g_date_subtract_months(date, 3);
 +}
 +
 +/* ================================================= */
 +
 +void
 +gnc_gdate_set_year_start (GDate *date)
 +{
 +    g_date_set_month(date, G_DATE_JANUARY);
 +    g_date_set_day(date, 1);
 +}
 +
 +void
 +gnc_gdate_set_year_end (GDate *date)
 +{
 +    g_date_set_month(date, G_DATE_DECEMBER);
 +    g_date_set_day(date, 31);
 +}
 +
 +void
 +gnc_gdate_set_prev_year_start (GDate *date)
 +{
 +    gnc_gdate_set_year_start(date);
 +    g_date_subtract_years(date, 1);
 +}
 +
 +void
 +gnc_gdate_set_prev_year_end (GDate *date)
 +{
 +    gnc_gdate_set_year_end(date);
 +    g_date_subtract_years(date, 1);
 +}
 +
 +/* ================================================= */
 +
 +void
 +gnc_gdate_set_fiscal_year_start (GDate *date,
 +                                 const GDate *fy_end)
 +{
 +    GDate temp;
 +    gboolean new_fy;
 +
 +    g_return_if_fail(date);
 +    g_return_if_fail(fy_end);
 +
 +    /* Compute the FY end that occurred this CY */
 +    temp = *fy_end;
 +    g_date_set_year(&temp, g_date_get_year(date));
 +
 +    /* Has it already passed? */
 +    new_fy = (g_date_compare(date, &temp) > 0);
 +
 +    /* Set start date */
 +    *date = temp;
 +    g_date_add_days(date, 1);
 +    if (!new_fy)
 +        g_date_subtract_years(date, 1);
 +}
 +
 +void
 +gnc_gdate_set_fiscal_year_end (GDate *date,
 +                               const GDate *fy_end)
 +{
 +    GDate temp;
 +    gboolean new_fy;
 +
 +    g_return_if_fail(date);
 +    g_return_if_fail(fy_end);
 +
 +    /* Compute the FY end that occurred this CY */
 +    temp = *fy_end;
 +    g_date_set_year(&temp, g_date_get_year(date));
 +
 +    /* Has it already passed? */
 +    new_fy = (g_date_compare(date, &temp) > 0);
 +
 +    /* Set end date */
 +    *date = temp;
 +    if (new_fy)
 +        g_date_add_years(date, 1);
 +}
 +
 +void
 +gnc_gdate_set_prev_fiscal_year_start (GDate *date,
 +                                      const GDate *fy_end)
 +{
 +    g_return_if_fail(date);
 +    g_return_if_fail(fy_end);
 +
 +    gnc_gdate_set_fiscal_year_start(date, fy_end);
 +    g_date_subtract_years(date, 1);
 +}
 +
 +void
 +gnc_gdate_set_prev_fiscal_year_end (GDate *date,
 +                                    const GDate *fy_end)
 +{
 +    g_return_if_fail(date);
 +    g_return_if_fail(fy_end);
 +
 +    gnc_gdate_set_fiscal_year_end(date, fy_end);
 +    g_date_subtract_years(date, 1);
 +}
diff --cc libgnucash/engine/gnc-date.h
index aaff8d4,0000000..46ca0c4
mode 100644,000000..100644
--- a/libgnucash/engine/gnc-date.h
+++ b/libgnucash/engine/gnc-date.h
@@@ -1,872 -1,0 +1,872 @@@
 +/********************************************************************
 + *            gnc-date.h (to be renamed qofdate.h)
 + *
 + *  Copyright (C) 1997 Robin D. Clark <rclark at cs.hmc.edu>
 + *  Copyright (C) 1998-2000, 2003 Linas Vepstas <linas at linas.org>
 + *  Copyright  2005  Neil Williams <linux at codehelp.co.uk>
 + *  Copyright (C) 2005 David Hampton <hampton at employees.org>
 + *  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   *
 + * 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                   *
 +\********************************************************************/
 +/** @addtogroup Date
 +    Utility functions to handle date and time (adjusting, getting
 +    the current date, printing the date and time, etc.)
 +
 +    Overall, this file is quite a mess.  Note, however, that other
 +    applications, besides just GnuCash, use this file.  In particular,
 +    GnoTime (gttr.sourcefore.net) uses this file, and this file is
 +    formally a part of QOF (qof.sourceforge.net).
 +
 +    An important note about time-keeping:  The general goal of any
 +    program that works with numeric time values SHOULD BE to always
 +    stores and use UNIVERSAL TIME internally.  Universal time is the
 +    'one true time' that is independent of one's location on planet
 +    Earth.  It is measured in seconds from midnight January 1, 1970
 +    in localtime-Greenwich (GMT).  If one wants to display the local
 +    time, then the display-print routine should make all final
 +    tweaks to print the local time.   The local time *must not* be
 +    kept as a numeric value anywhere in the program.   If one wants
 +    to parse a user's input string as if it were local time, then
 +    the output of the parse routine MUST BE universal time.
 +    A sane program must never ever store (to file or db) a time
 +    that is not Universal Time.  Break these rules, and you will
 +    rue the day...
 +
 +    \warning HACK ALERT -- the scan and print routines should probably be moved
 +    to somewhere else. The engine really isn't involved with things
 +    like printing formats. This is needed mostly by the GUI and so on.
 +    If a file-io backend needs date handling, it should do it itself,
 +    instead of depending on the routines here.
 +
 +    (to be renamed qofdate.h in libqof2.)
 +
 +    @author Copyright (C) 1997 Robin D. Clark <rclark at cs.hmc.edu>
 +    @author Copyright (C) 1998-2001,2003 Linas Vepstas <linas at linas.org>
 +*/
 +
 +/** @{
 +    @file gnc-date.h
 +    @brief Date and Time handling routines
 +*/
 +
 +#ifndef GNC_DATE_H
 +#define GNC_DATE_H
 +#ifdef __cplusplus
 +extern "C"
 +{
 +#endif
 + 
 +#include <glib-object.h>
 +#include <time.h>
- #include <stdint.h>
++
 +/**
 + * Many systems, including Microsoft Windows and BSD-derived Unixes
 + * like Darwin, are retaining the int-32 typedef for time_t. Since
 + * this stops working in 2038, we define our own:
 + */
 +typedef gint64 time64;
 +
 +/** The Timespec is just like the unix 'struct timespec'
 + * except that we use a 64-bit unsigned int to
 + * store the seconds.  This should adequately cover dates in the
 + * distant future as well as the distant past, as long as they're not
 + * more than a couple dozen times the age of the universe
 + * Values of this type can range from -9,223,372,036,854,775,808 to
 + * 9,223,372,036,854,775,807.
 + */
 +typedef struct timespec64 Timespec;
 +
 +/** @name GValue
 +  @{
 +*/
 +GType timespec_get_type( void );
 +#define GNC_TYPE_TIMESPEC (timespec_get_type ())
 +
 +/** @} */
 +/** The default date format for use with strftime. */
 +extern const char *gnc_default_strftime_date_format;
 +
 +/** The maximum length of a string created by the date printers */
 +#define MAX_DATE_LENGTH 34
 +/** Constants *******************************************************/
 +/** \brief UTC date format string.
 +
 +Time zone independent, date and time inclusive, as used in the QSF backend.
 +The T and Z characters are from xsd:dateTime format in coordinated universal time, UTC.
 +You can reproduce the string from the GNU/Linux command line using the date utility:
 +date -u +%Y-%m-%dT%H:M:SZ = 2004-12-12T23:39:11Z The datestring must be time zone independent
 +and include all specified fields. Remember to use gmtime() NOT localtime()!
 +*/
 +
 +#define QOF_UTC_DATE_FORMAT     "%Y-%m-%dT%H:%M:%SZ"
 +
 +/** Enum for determining a date format */
 +typedef enum
 +{
 +    QOF_DATE_FORMAT_US,       /**< United states: mm/dd/yyyy */
 +    QOF_DATE_FORMAT_UK,       /**< Britain: dd/mm/yyyy */
 +    QOF_DATE_FORMAT_CE,       /**< Continental Europe: dd.mm.yyyy */
 +    QOF_DATE_FORMAT_ISO,      /**< ISO: yyyy-mm-dd */
 +    QOF_DATE_FORMAT_LOCALE,   /**< Take from locale information */
 +    QOF_DATE_FORMAT_UTC,      /**< UTC: 2004-12-12T23:39:11Z */
 +    QOF_DATE_FORMAT_CUSTOM,   /**< Used by the check printing code */
 +    QOF_DATE_FORMAT_UNSET     /**< No Fancy Date Format, use Global */
 +} QofDateFormat;
 +
 +#define DATE_FORMAT_FIRST QOF_DATE_FORMAT_US
 +#define DATE_FORMAT_LAST  QOF_DATE_FORMAT_UTC
 +
 +/** Enum for date completion modes (for dates entered without year) */
 +typedef enum
 +{
 +    QOF_DATE_COMPLETION_THISYEAR, /**< use current year */
 +    QOF_DATE_COMPLETION_SLIDING,  /**< use sliding 12-month window */
 +} QofDateCompletion;
 +
 +/** \deprecated qof_date_format_get_format has been replaced
 +by qof_date_text_format_get_string */
 +#define qof_date_format_get_format qof_date_text_format_get_string
 +
 +/**
 + * This is how to format the month, as a number, an abbreviated string,
 + * or the full name.
 + */
 +typedef enum
 +{
 +    GNCDATE_MONTH_NUMBER,
 +    GNCDATE_MONTH_ABBREV,
 +    GNCDATE_MONTH_NAME
 +} GNCDateMonthFormat;
 +
 +/* Replacements for POSIX functions which use time_t. Time_t is still
 + * 32 bits in Microsoft Windows, Apple OSX, and some BSD versions even
 + * when the rest of the system is 64-bits, as well as all 32-bit
 + * 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 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
 + * are seconds before that moment).
 + *  \return A struct tm*, allocated on the heap. Must be freed with gnc_tm_free().
 + *  The time is adjusted for the current local time zone.
 + */
 +struct tm* gnc_localtime (const time64 *secs);
 +
 +/** \brief fill out a time struct from a 64-bit time value adjusted for the current time zone.
 + *  \param secs: Seconds since 00:00:01 UTC 01 January 1970 (negative values
 + * are seconds before that moment)
 + *  \param time: A struct tm* for the function to fill.
 + *  The time is adjusted for the current local time zone.
 + */
 +struct tm* gnc_localtime_r (const time64 *secs, struct tm* time);
 +
 +/** \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
 + * are seconds before that moment)
 + *  \return A struct tm*, allocated on the heap. Must be freed with gnc_tm_free()
 + *  The time is UTC.
 + */
 +struct tm* gnc_gmtime (const time64 *secs);
 +
 +/** \brief calculate seconds from the epoch given a time struct
 + *  \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).
 + */
 +time64 gnc_mktime (struct tm* time);
 +
 +/** \brief calculate seconds from the epoch given a time struct
 + *  \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).
 + */
 +time64 gnc_timegm (struct tm* time);
 +
 +/** \brief Return a string representation of a date from a 64-bit time value
 + *  \param secs: Seconds since 00:00:01 UTC 01 January 1970 (negative values
 + * are seconds before that moment)
 + * \return A string, which must be freed with g_free(), representing the date
 + * in the following format:
 + *       Thu Nov 24 18:22:48 1986\n\0
 + * This is equivalent to the strftime format %a %b %H:%M:%S %Y.
 + */
 +gchar* gnc_ctime (const time64 *secs);
 +
 +/** \brief get the current local 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 (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)
 + *  \param secs2: The second time value, in Seconds since
 + * 00:00:01 UTC 01 January 1970 (negative values are seconds before that moment)
 + *  \return The difference in seconds between secs1 and secs2. If secs2 is
 + * later than secs1 the value will be negative.
 + */
 +gdouble gnc_difftime (const time64 secs1, const time64 secs2);
 +
 +/** \brief free a struct tm* created with gnc_localtime() or gnc_gmtime()
 + * \param time: The struct tm* to be freed.
 + */
 +void gnc_tm_free (struct tm* time);
 +
 +/** \name String / DateFormat conversion. */
 +//@{
 +
 +/** \brief The string->value versions return FALSE on success and TRUE on failure */
 +const gchar* gnc_date_dateformat_to_string(QofDateFormat format);
 +
 +/** \brief Converts the date format to a printable string.
 +
 +Note the reversed return values!
 + at return FALSE on success, TRUE on failure.
 +*/
 +gboolean gnc_date_string_to_dateformat(const gchar* format_string,
 +                                       QofDateFormat *format);
 +
 +const gchar* gnc_date_monthformat_to_string(GNCDateMonthFormat format);
 +
 +/** \brief Converts the month format to a printable string.
 +
 +Note the reversed return values!
 + at return FALSE on success, TRUE on failure.
 +*/
 +gboolean gnc_date_string_to_monthformat(const gchar *format_string,
 +                                        GNCDateMonthFormat *format);
 +
 +/** \brief print a time64 as a date string per format
 + * \param time The time64 to print
 + * \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);
 +
 +// @}
 +
 +/** @name GDate time64 setters
 + *    @{ */
 +/** 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);
 +
 +/** Set a GDate to the current day
 + * @param gd The date to act on
 + */
 +void gnc_gdate_set_today (GDate* gd);
 +
 +/** Set a GDate to a time64
 + * @param gd the date to act on
 + * @param time the time to set it to.
 + */
 +void gnc_gdate_set_time64 (GDate* gd, time64 time);
 +
 +/** @} */
 +
 +/* Datatypes *******************************************************/
 +
 +/** \brief Use a 64-bit unsigned int timespec
 + *
 + * struct timespec64 is just like the unix 'struct timespec' except
 + * that we use a 64-bit
 + * unsigned int to store the seconds.  This should adequately cover
 + * dates in the distant future as well as the distant past, as long as
 + * they're not more than a couple dozen times the age of the universe.
 + * Values of this type can range from -9,223,372,036,854,775,808 to
 + * 9,223,372,036,854,775,807.
 + */
 +
 +#ifndef SWIG   /* swig 1.1p5 can't hack the long long type */
 +struct timespec64
 +{
 +    time64 tv_sec;
 +    glong tv_nsec;
 +};
 +#endif /* SWIG */
 +
 +
 +
 +/* Prototypes ******************************************************/
 +
 +/** \name Timespec functions */
 +// @{
 +/** strict equality */
 +gboolean timespec_equal(const Timespec *ta, const Timespec *tb);
 +
 +/** comparison:  if (ta < tb) -1; else if (ta > tb) 1; else 0; */
 +gint      timespec_cmp(const Timespec *ta, const Timespec *tb);
 +
 +/** difference between ta and tb, results are normalized
 + * ie tv_sec and tv_nsec of the result have the same size
 + * abs(result.tv_nsec) <= 1000000000 */
 +Timespec timespec_diff(const Timespec *ta, const Timespec *tb);
 +
 +/** absolute value, also normalized */
 +Timespec timespec_abs(const Timespec *t);
 +
 +/** convert a timepair on a certain day (localtime) to
 + * the timepair representing midday on that day. Watch out - this is *not* the
 + * first second of the day, which is returned by various other functions
 + * returning a Timespec. */
 +Timespec timespecCanonicalDayTime(Timespec t);
 +
 +/** Returns the current clock time as a Timespec, taken from time(2). */
 +Timespec timespec_now (void);
 +
 +/** Turns a time64 into a Timespec */
 +void timespecFromTime64 (Timespec *ts, time64 t );
 +
 +/** Turns a Timespec into a time64 */
 +time64 timespecToTime64 (Timespec ts);
 +
 +/** Turns a Timespec into a GDate */
 +GDate timespec_to_gdate (Timespec ts);
 +
 +/** Turns a GDate into a Timespec, returning the first second of the day  */
 +Timespec gdate_to_timespec (GDate d);
 +
 +/** Convert a day, month, and year to a Timespec, returning the first second of the day */
 +Timespec gnc_dmy2timespec (gint day, gint month, gint year);
 +
 +/** Same as gnc_dmy2timespec, but last second of the day */
 +Timespec gnc_dmy2timespec_end (gint day, gint month, gint year);
 +
 +/** Converts a day, month, and year to a Timespec representing 11:00:00 UTC
 + *  11:00:00 UTC falls on the same time in almost all timezones, the exceptions
 + *  being the +13, +14, and -12 timezones used by countries along the
 + *  International Date Line. Since users in those timezones would see dates
 + *  immediately change by one day, the function checks the current timezone for
 + *  those changes and adjusts the UTC time so that the date will be consistent.
 + */
 +Timespec gnc_dmy2timespec_neutral (gint day, gint month, gint year);
 +
 +/** The gnc_iso8601_to_timespec_gmt() routine converts an ISO-8601 style
 + *    date/time string to Timespec.  Please note that ISO-8601 strings
 + *    are a representation of Universal Time (UTC), and as such, they
 + *    'store' UTC.  To make them human readable, they show time zone
 + *    information along with a local-time string.  But fundamentally,
 + *    they *are* UTC.  Thus, this routine takes a UTC input, and
 + *    returns a UTC output.
 + *
 + *    For example: 1998-07-17 11:00:00.68-0500
 + *    is 680 milliseconds after 11 o'clock, central daylight time
 + *    It is also 680 milliseconds after 16:00:00 hours UTC.
 + *    \return The universal time.
 + *
 + * XXX Caution: this routine does not handle strings that specify
 + * times before January 1 1970.
 + */
 +Timespec gnc_iso8601_to_timespec_gmt(const gchar *);
 +
 +/** The gnc_timespec_to_iso8601_buff() routine takes the input
 + *    UTC Timespec value and prints it as an ISO-8601 style string.
 + *    The buffer must be long enough to contain the NULL-terminated
 + *    string (32 characters + NUL).  This routine returns a pointer
 + *    to the null terminator (and can thus be used in the 'stpcpy'
 + *    metaphor of string concatenation).
 + *
 + *    Please note that ISO-8601 strings are a representation of
 + *    Universal Time (UTC), and as such, they 'store' UTC.  To make them
 + *    human readable, they show time zone information along with a
 + *    local-time string.  But fundamentally, they *are* UTC.  Thus,
 + *    this routine takes a UTC input, and returns a UTC output.
 + *
 + *    The string generated by this routine uses the local time zone
 + *    on the machine on which it is executing to create the time string.
 + */
 +gchar * gnc_timespec_to_iso8601_buff (Timespec ts, gchar * buff);
 +
 +/** Set the proleptic Gregorian day, month, and year from a Timespec
 + * \param ts: input timespec
 + * \param day: output day, 1 - 31
 + * \param month: output month, 1 - 12
 + * \param year: output year, 0001 - 9999 CE
 + */
 +void gnc_timespec2dmy (Timespec ts, gint *day, gint *month, gint *year);
 +
 +// @}
 +
 +/* ======================================================== */
 +
 +/** \name QofDateFormat functions */
 +// @{
 +/** The qof_date_format_get routine returns the date format that
 + *  the date printing will use when printing a date, and the scanning
 + *  routines will assume when parsing a date.
 + * @returns: the one of the enumerated date formats.
 + */
 +QofDateFormat qof_date_format_get(void);
 +
 +/**
 + * The qof_date_format_set() routine sets date format to one of
 + *    US, UK, CE, OR ISO.  Checks to make sure it's a legal value.
 + *    Args: QofDateFormat: enumeration indicating preferred format
 + */
 +void qof_date_format_set(QofDateFormat df);
 +
 +/** This function returns a strftime formatting string for printing an
 + *  all numeric date (e.g. 2005-09-14).  The string returned is based
 + *  upon the location specified.
 + *
 + *  @param df The date style (us, uk, iso, etc) that should be provided.
 + *
 + *  @return A formatting string that will print a date in the
 + *  requested style  */
 +const gchar *qof_date_format_get_string(QofDateFormat df);
 +
 +/** This function returns a strftime formatting string for printing a
 + *  date using words and numbers (e.g. 2005-September-14).  The string
 + *  returned is based upon the location specified.
 + *
 + *  @param df The date style (us, uk, iso, etc) that should be provided.
 + *
 + *  @return A formatting string that will print a date in the
 + *  requested style  */
 +const gchar *qof_date_text_format_get_string(QofDateFormat df);
 +// @}
 +
 +/* ======================================================== */
 +
 +/**
 + * The qof_date_completion_set() routing sets the date completion method to
 + *    one of QOF_DATE_COMPLETION_THISYEAR (for completing the year to
 + *    the current calendar year) or QOF_DATE_COMPLETION_SLIDING (for
 + *    using a sliding 12-month window). The sliding window starts
 + *    'backmonth' months before the current month (0-11) */
 +void qof_date_completion_set(QofDateCompletion dc, int backmonths);
 +
 +/** dateSeparator
 + *    Return the field separator for the current date format
 + *
 + * Args:   none
 + *
 + * Return: date character
 + *
 + * Globals: global dateFormat value
 + */
 +gchar dateSeparator(void);
 +
 +/* ======================================================== */
 +
 +/** \name Date Printing/Scanning functions
 + */
 +// @{
 +/**
 + * \warning HACK ALERT -- the scan and print routines should probably
 + * be moved to somewhere else. The engine really isn't involved with
 + * things like printing formats. This is needed mostly by the GUI and
 + * so on.  If a file-io thing needs date handling, it should do it
 + * itself, instead of depending on the routines here.
 + */
 +
 +/* qof_format_time takes a format specification in UTF-8 and a broken-down time,
 + *  tries to call strftime with a sufficiently large buffer and, if successful,
 + *  return a newly allocated string in UTF-8 for the printing result.
 + *
 + *  @param format A format specification in UTF-8.
 + *
 + *  @param tm A broken-down time.
 + *
 + *  @return A newly allocated string on success, or NULL otherwise.
 + */
 +/* gchar *qof_format_time(const gchar *format, const struct tm *tm); */
 +
 +/** qof_strftime calls qof_format_time to print a given time and afterwards tries
 + *  to put the result into a buffer of fixed size.
 + *
 + *  @param buf A buffer.
 + *
 + *  @param max The size of buf in bytes.
 + *
 + *  @param format A format specification in UTF-8.
 + *
 + *  @param tm A broken-down time.
 + *
 + *  @return The number of characters written, not include the null byte, if the
 + *  complete string, including the null byte, fits into the buffer.  Otherwise 0.
 + */
 +gsize qof_strftime(gchar *buf, gsize max, const gchar *format,
 +                   const struct tm *tm);
 +
 +/** qof_print_date_dmy_buff
 + *    Convert a date as day / month / year integers into a localized string
 + *    representation
 + *
 + * Args:   buff - pointer to previously allocated character array; its size
 + *                must be at lease MAX_DATE_LENTH bytes.
 + *         len - length of the buffer, in bytes.
 + *         day - day of the month as 1 ... 31
 + *         month - month of the year as 1 ... 12
 + *         year - year (4-digit)
 + *
 + * Returns: number of characters printed
 + *
 + * Globals: global dateFormat value
 + **/
 +size_t qof_print_date_dmy_buff (gchar * buff, size_t buflen, int day, int month, int year);
 +
 +/** Convenience: calls through to qof_print_date_dmy_buff(). **/
 +size_t qof_print_date_buff (char * buff, size_t buflen, time64 secs);
 +
 +/** Convenience; calls through to qof_print_date_dmy_buff(). **/
 +size_t qof_print_gdate(char *buf, size_t bufflen, const GDate *gd);
 +
 +/** Convenience; calls through to qof_print_date_dmy_buff().
 + *  Return: string, which should be freed when no longer needed.
 + * **/
 +char * qof_print_date (time64 secs);
 +
 +/** Convenience; calls through to qof_print_date_dmy_buff().
 + *  Return: static global string.
 + *  \warning This routine is not thread-safe, because it uses a single
 + *      global buffer to store the return value.  Use qof_print_date_buff()
 + *      or qof_print_date() instead.
 + * **/
 +const char * gnc_print_date(Timespec ts);
 +
 +/* ------------------------------------------------------------------ */
 +/* time printing utilities */
 +
 +/**
 + *    Returns the number of bytes printed.
 + */
 +
 +size_t qof_print_date_time_buff (char * buff, size_t len, time64 secs);
 +
 +/** qof_scan_date
 + *    Convert a string into  day / month / year integers according to
 + *    the current dateFormat value.
 + *
 + * Args:   buff - pointer to date string
 + *         day -  will store day of the month as 1 ... 31
 + *         month - will store month of the year as 1 ... 12
 + *         year - will store the year (4-digit)
 + *
 + * Return: TRUE if the string seemed to be a valid date; else FALSE.
 + *
 + * Globals: uses global dateFormat value to assist in parsing.
 + */
 +gboolean qof_scan_date (const char *buff, int *day, int *month, int *year);
 +
 +// @}
 +
 +/* ======================================================== */
 +
 +/** \name Date Start/End Adjustment routines
 + * Given a time value, adjust it to be the beginning or end of that day.
 + */
 +// @{
 +
 +/** The gnc_tm_set_day_start() inline routine will set the appropriate
 + *  fields in the struct tm to indicate the first second of that day.
 + *  This routine assumes that the contents of the data structure is
 + *  already in normalized form. */
 +static inline
 +void gnc_tm_set_day_start (struct tm *tm)
 +{
 +    /* First second of the day */
 +    g_return_if_fail (tm != NULL);
 +    tm->tm_hour = 0;
 +    tm->tm_min = 0;
 +    tm->tm_sec = 0;
 +    tm->tm_isdst = -1;
 +}
 +
 +/** The gnc_tm_set_day_middle() inline routine will set the appropriate
 + *  fields in the struct tm to indicate noon of that day.  This
 + *  routine assumes that the contents of the data structure is already
 + *  in normalized form.*/
 +static inline
 +void gnc_tm_set_day_middle (struct tm *tm)
 +{
 +    /* First second of the day */
 +    g_return_if_fail (tm != NULL);
 +    tm->tm_hour = 12;
 +    tm->tm_min = 0;
 +    tm->tm_sec = 0;
 +    tm->tm_isdst = -1;
 +}
 +
 +/** The gnc_tm_set_day_end() inline routine will set the appropriate
 + *  fields in the struct tm to indicate the last second of that day.
 + *  This routine assumes that the contents of the data structure is
 + *  already in normalized form.*/
 +static inline
 +void gnc_tm_set_day_end (struct tm *tm)
 +{
 +    /* Last second of the day */
 +    g_return_if_fail (tm != NULL);
 +    tm->tm_hour = 23;
 +    tm->tm_min = 59;
 +    tm->tm_sec = 59;
 +    tm->tm_isdst = -1;
 +}
 +
 +/** The gnc_time64_get_day_start() routine will take the given time in
 + *  seconds and adjust it to the last second of that day. */
 +time64 gnc_time64_get_day_start(time64 time_val);
 +
 +/** The gnc_time64_get_day_end() routine will take the given time in
 + *  seconds and adjust it to the last second of that day. */
 +time64 gnc_time64_get_day_end(time64 time_val);
 +
 +/** Get the numerical last date of the month. (28, 29, 30, 31) */
 +int gnc_date_get_last_mday (int month, int year);
 +
 +// @}
 +
 +/* ======================================================== */
 +
 +/** \name Today's Date */
 +// @{
 +/** The gnc_tm_get_today_start() routine takes a pointer to a struct
 + *  tm and fills it in with the first second of the today. */
 +void   gnc_tm_get_today_start(struct tm *tm);
 +
 +/** The gnc_tm_get_today_end() routine takes a pointer to a struct
 + *  tm and fills it in with the last second of the today. */
 +void   gnc_tm_get_today_end(struct tm *tm);
 +
 +/** The gnc_time64_get_today_start() routine returns a time64 value
 + *  corresponding to the first second of today. */
 +time64 gnc_time64_get_today_start(void);
 +
 +/** The gnc_time64_get_today_end() routine returns a time64 value
 + *  corresponding to the last second of today. */
 +time64 gnc_time64_get_today_end(void);
 +
 +/** \brief Make a timestamp in YYYYMMDDHHMMSS format.
 + *  @return A pointer to the generated string.
 + *  @note The caller owns this buffer and must g_free it when done. */
 +char * gnc_date_timestamp (void);
 +
 +#define MIN_BUF_LEN 10
 +/**
 + * Localized DOW abbreviation.
 + * @param buf_len at least MIN_BUF_LEN
 + * @param dow struct tm semantics: 0=sunday .. 6=saturday
 + **/
 +void gnc_dow_abbrev(gchar *buf, int buf_len, int dow);
 +
 +//@}
 +
 +/* ======================================================== */
 +
 +/** \name GDate hash table support */
 +// @{
 +
 +/** Compares two GDate*'s for equality; useful for using GDate*'s as
 + *  GHashTable keys. */
 +gint gnc_gdate_equal(gconstpointer gda, gconstpointer gdb);
 +
 +
 +/** Provides a "hash" of a GDate* value; useful for using GDate*'s as
 + *  GHashTable keys. */
 +guint gnc_gdate_hash( gconstpointer gd );
 +
 +//@}
 +
 +/* ======================================================== */
 +
 +/** \name GDate to time64 conversions */
 +// @{
 +
 +/** The gnc_time64_get_day_start() routine will take the given time in
 + *  GLib GDate format and adjust it to the first second of that day.
 + */
 +time64 gnc_time64_get_day_start_gdate (const GDate *date);
 +
 +/** The gnc_time64_get_day_end() routine will take the given time in
 + *  GLib GDate format and adjust it to the last second of that day.
 + */
 +time64 gnc_time64_get_day_end_gdate (const GDate *date);
 +
 +//@}
 +
 +/* ======================================================== */
 +
 +/** \name Date Manipulation */
 +// @{
 +
 +/** This function modifies a GDate to set it to the first day of the
 + *  month in which it falls.  For example, if this function is called
 + *  with a date of 2003-09-24 the date will be modified to 2003-09-01.
 + *
 + *  @param date The GDate to modify. */
 +void gnc_gdate_set_month_start (GDate *date);
 +
 +
 +/** This function modifies a GDate to set it to the last day of the
 + *  month in which it falls.  For example, if this function is called
 + *  with a date of 2003-09-24 the date will be modified to 2003-09-30.
 + *
 + *  @param date The GDate to modify. */
 +void gnc_gdate_set_month_end (GDate *date);
 +
 +
 +/** This function modifies a GDate to set it to the first day of the
 + *  month prior to the one in which it falls.  For example, if this
 + *  function is called with a date of 2003-09-24 the date will be
 + *  modified to 2003-08-01.
 + *
 + *  @param date The GDate to modify. */
 +void gnc_gdate_set_prev_month_start (GDate *date);
 +
 +
 +/** This function modifies a GDate to set it to the last day of the
 + *  month prior to the one in which it falls.  For example, if this
 + *  function is called with a date of 2003-09-24 the date will be
 + *  modified to 2003-08-31.
 + *
 + *  @param date The GDate to modify. */
 +void gnc_gdate_set_prev_month_end (GDate *date);
 +
 +
 +/** This function modifies a GDate to set it to the first day of the
 + *  quarter in which it falls.  For example, if this function is called
 + *  with a date of 2003-09-24 the date will be modified to 2003-09-01.
 + *
 + *  @param date The GDate to modify. */
 +void gnc_gdate_set_quarter_start (GDate *date);
 +
 +
 +/** This function modifies a GDate to set it to the last day of the
 + *  quarter in which it falls.  For example, if this function is called
 + *  with a date of 2003-09-24 the date will be modified to 2003-12-31.
 + *
 + *  @param date The GDate to modify. */
 +void gnc_gdate_set_quarter_end (GDate *date);
 +
 +
 +/** This function modifies a GDate to set it to the first day of the
 + *  quarter prior to the one in which it falls.  For example, if this
 + *  function is called with a date of 2003-09-24 the date will be
 + *  modified to 2003-06-01.
 + *
 + *  @param date The GDate to modify. */
 +void gnc_gdate_set_prev_quarter_start (GDate *date);
 +
 +
 +/** This function modifies a GDate to set it to the last day of the
 + *  quarter prior to the one in which it falls.  For example, if this
 + *  function is called with a date of 2003-09-24 the date will be
 + *  modified to 2003-07-31.
 + *
 + *  @param date The GDate to modify. */
 +void gnc_gdate_set_prev_quarter_end (GDate *date);
 +
 +
 +/** This function modifies a GDate to set it to the first day of the
 + *  year in which it falls.  For example, if this function is called
 + *  with a date of 2003-09-24 the date will be modified to 2003-01-01.
 + *
 + *  @param date The GDate to modify. */
 +void gnc_gdate_set_year_start (GDate *date);
 +
 +
 +/** This function modifies a GDate to set it to the last day of the
 + *  year in which it falls.  For example, if this function is called
 + *  with a date of 2003-09-24 the date will be modified to 2003-12-31.
 + *
 + *  @param date The GDate to modify. */
 +void gnc_gdate_set_year_end (GDate *date);
 +
 +
 +/** This function modifies a GDate to set it to the first day of the
 + *  year prior to the one in which it falls.  For example, if this
 + *  function is called with a date of 2003-09-24 the date will be
 + *  modified to 2002-01-01.
 + *
 + *  @param date The GDate to modify. */
 +void gnc_gdate_set_prev_year_start (GDate *date);
 +
 +
 +/** This function modifies a GDate to set it to the last day of the
 + *  year prior to the one in which it falls.  For example, if this
 + *  function is called with a date of 2003-09-24 the date will be
 + *  modified to 2002-12-31.
 + *
 + *  @param date The GDate to modify. */
 +void gnc_gdate_set_prev_year_end (GDate *date);
 +
 +
 +/** This function modifies a GDate to set it to the first day of the
 + *  fiscal year in which it falls.  For example, if this function is
 + *  called with a date of 2003-09-24 and a fiscal year ending July
 + *  31st, the date will be modified to 2003-08-01.
 + *
 + *  @param date The GDate to modify.
 + *
 + *  @param year_end A GDate containing the last month and day of the
 + *  fiscal year.  The year field of this argument is ignored. */
 +void gnc_gdate_set_fiscal_year_start (GDate *date, const GDate *year_end);
 +
 +
 +/** This function modifies a GDate to set it to the last day of the
 + *  fiscal year in which it falls.  For example, if this function is
 + *  called with a date of 2003-09-24 and a fiscal year ending July
 + *  31st, the date will be modified to 2004-07-31.
 + *
 + *  @param date The GDate to modify.
 + *
 + *  @param year_end A GDate containing the last month and day of the
 + *  fiscal year.  The year field of this argument is ignored. */
 +void gnc_gdate_set_fiscal_year_end (GDate *date, const GDate *year_end);
 +
 +
 +/** This function modifies a GDate to set it to the first day of the
 + *  fiscal year prior to the one in which it falls.  For example, if
 + *  this function is called with a date of 2003-09-24 and a fiscal
 + *  year ending July 31st, the date will be modified to 2002-08-01.
 + *
 + *  @param date The GDate to modify.
 + *
 + *  @param year_end A GDate containing the last month and day of the
 + *  fiscal year.  The year field of this argument is ignored. */
 +void gnc_gdate_set_prev_fiscal_year_start (GDate *date, const GDate *year_end);
 +
 +
 +/** This function modifies a GDate to set it to the last day of the
 + *  fiscal year prior to the one in which it falls.  For example, if
 + *  this function is called with a date of 2003-09-24 and a fiscal
 + *  year ending July 31st, the date will be modified to 2003-07-31.
 + *
 + *  @param date The GDate to modify.
 + *
 + *  @param year_end A GDate containing the last month and day of the
 + *  fiscal year.  The year field of this argument is ignored. */
 +void gnc_gdate_set_prev_fiscal_year_end (GDate *date, const GDate *year_end);
 +
 +//@}
 +
 +//@}
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* GNC_DATE_H */
diff --cc libgnucash/engine/test/test-gnc-date.c
index 8e31d5d,0000000..616909f
mode 100644,000000..100644
--- a/libgnucash/engine/test/test-gnc-date.c
+++ b/libgnucash/engine/test/test-gnc-date.c
@@@ -1,2281 -1,0 +1,2272 @@@
 +/********************************************************************
 + * 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   *
 + * 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, you can retrieve it from        *
 + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html            *
 + * or 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                   *
 + ********************************************************************/
 +#ifdef __cplusplus
 +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 */
 +
 +#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
 +
 +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 = (INT64_C(3600) * (INT64_C(24) * INT64_C(365) + 6)) * (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, 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
 +    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[9];
 +} 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)};
 +    f->test[4] = (TimeMap){1257, 07, 02, INT64_MAX}; /*invalid year*/
 +    f->test[5] = (TimeMap){2017, 02, 29, INT64_MAX}; /*invalid day*/
 +    f->test[6] = (TimeMap){2017, 02, 33, INT64_MAX}; /*invalid day*/
 +    f->test[7] = (TimeMap){2017, 13, 29, INT64_MAX}; /*invalid month*/
 +    f->test[8] = (TimeMap){2017, 03, 16, INT64_C(1489622400)};
 +}
 +
 +static void
 +setup_neutral(FixtureB *f, gconstpointer pData)
 +{
 +    f->test[0] = (TimeMap){1999, 7, 21, INT64_C(932554740)};
 +    f->test[1] = (TimeMap){1918, 3, 31, INT64_C(-1633266060)};
 +    f->test[2] = (TimeMap){1918, 4, 1, INT64_C(-1633179660)};
 +    f->test[3] = (TimeMap){2057, 11, 20, INT64_C(2773479540)};
 +    f->test[4] = (TimeMap){1257, 07, 02, INT64_MAX};
 +    f->test[5] = (TimeMap){2017, 02, 29, INT64_MAX};
 +    f->test[6] = (TimeMap){2017, 02, 33, INT64_MAX};
 +    f->test[7] = (TimeMap){2017, 13, 29, INT64_MAX};
 +    f->test[8] = (TimeMap){2017, 03, 16, INT64_C(1489661940)};
 +}
 +
 +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)};
 +    f->test[4] = (TimeMap){1257, 07, 02, INT64_MAX};
 +    f->test[5] = (TimeMap){2017, 02, 29, INT64_MAX};
 +    f->test[6] = (TimeMap){2017, 02, 33, INT64_MAX};
 +    f->test[7] = (TimeMap){2017, 13, 29, INT64_MAX};
 +    f->test[8] = (TimeMap){2017, 03, 16, INT64_C(1489708799)};
 +}
 +
 +void test_suite_gnc_date ( void );
 +static GTimeZone *tz;
 +#define MAXTIME INT64_C(253402214400)
 +#define MINTIME INT64_C(-17987443200)
 +
 +/* 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[] = {-15767956734LL, -1123692LL, 432761LL,
 +                      723349832LL, 887326459367LL,
 +                      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]);
 +        time_t tsecs;
 +        struct tm* ans;
 +        if (secs[ind] > max_secs)
 +        {
 +            g_assert (time == NULL);
 +            continue;
 +        }
 +        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);
 +        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, ==, ans->tm_gmtoff);
 +#endif
 +        gnc_tm_free (time);
 +    }
 +}
 +
 +static void
 +test_gnc_gmtime (void)
 +{
 +    time64 secs[6] = {-15767956734LL, -1123692LL, 432761LL,
 +                      723349832LL, 887326459367LL, 1175964426LL
 +                     };
 +    struct tm answers[6] =
 +    {
 +#ifdef HAVE_STRUCT_TM_GMTOFF
 +        { 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, 96, 0, 0, NULL },
 +#else
 +        { 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, 96, 0 },
 +#endif
 +    };
 +    guint ind;
 +    for (ind = 0; ind < G_N_ELEMENTS (secs); ind++)
 +    {
 +        struct tm* time = gnc_gmtime (&secs[ind]);
 +        if ((secs[ind] > max_secs))
 +        {
 +            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);
 +        g_assert_cmpint (time->tm_hour, ==, answers[ind].tm_hour);
 +        g_assert_cmpint (time->tm_min, ==, answers[ind].tm_min);
 +        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, ==, -1);
 +#ifdef HAVE_STRUCT_TM_GMTOFF
 +        g_assert_cmpint (time->tm_gmtoff, ==, 0);
 +#endif
 +        gnc_tm_free (time);
 +    }
 +}
 +
 +static void
 +test_gnc_mktime (void)
 +{
 +    time64 ans[5] =
 +        { -15752870334LL, -1123692LL, 432761LL, 723349832LL, 1175964426LL};
 +
 +    struct tm time[5] =
 +    {
 +#ifdef HAVE_STRUCT_TM_GMTOFF
 +        { 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, -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 },
 +        { 6, 47, 16, 7, 3, 107, 0, 0, -1 },
 +#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]);
 +#if !PLATFORM(WINDOWS)
 +	//The timezone database uses local time for some
 +	//timezones before 1900, which screws up the offset.
 +	if (time[ind].tm_year < 0)
 +            continue;
 +#endif
 +        g_assert_cmpint (secs, ==, ans[ind] - offset);
 +
 +    }
 +}
 +
 +/* In addition to computing a time offset from a struct tm, mktime is
 + * supposed to normalize struct tms with out-of-range values. This
 + * second test exercises that facility in gnc_mktime.
 + */
 +static void
 +test_gnc_mktime_normalization (void)
 +{
 +    time64 ans = 723349832LL;
 +
 +    struct tm normal_time =
 +#ifdef HAVE_STRUCT_TM_GMTOFF
 +    {
 +        32, 30, 2, 3, 11, 92, 0, 0, -1, 0, NULL
 +    };
 +#else
 +    {
 +        32, 30, 2, 3, 11, 92, 0, 0, -1
 +    };
 +#endif
 +
 +    struct tm time[4] =
 +    {
 +#ifdef HAVE_STRUCT_TM_GMTOFF
 +        { 92, -31, 27, -29, 24, 91, 0, 0, -1, 0, NULL },
 +        { -28, 91, -47, 35, -2, 93, 0, 0, -1, 0, NULL },
 +        { -28, 91, -47, 66, -3, 93, 0, 0, -1, 0, NULL },
 +        { -28, 91, -47, 35, -26, 95, 0, 0, -1, 0, NULL },
 +#else
 +        { 92, -31, 27, -29, 24, 91, 0, 0, -1 },
 +        { -28, 91, -47, 35, -2, 93, 0, 0, -1 },
 +        { -28, 91, -47, 66, -3, 93, 0, 0, -1 },
 +        { -28, 91, -47, 35, -26, 95, 0, 0, -1 },
 +#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]);
 +
 +        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);
 +        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 - offset);
 +    }
 +}
 +
 +static void
 +test_gnc_ctime (void)
 +{
 +    time64 secs[5] = {-15767956734LL, -1123692LL, 432761LL,
 +                      723349832LL, 1175964426LL
 +                     };
 +    guint ind;
 +    for (ind = 0; ind < G_N_ELEMENTS (secs); ind++)
 +    {
 +	time_t time;
 +	char *datestr;
 +	char check_str[80];
 +        if (secs[ind] < INT32_MIN)
 +            continue;
 +        time = (time_t)secs[ind];
 +        datestr = gnc_ctime (&secs[ind]);
 +	strftime (check_str, 80, "%a %b %d %H:%M:%S %Y", localtime(&time));
 +        g_assert_cmpstr (datestr, ==, check_str);
 +        g_free (datestr);
 +    }
 +}
 +
 +static void
 +test_gnc_time (void)
 +{
 +    time64 secs1, secs2;
 +    secs1 = gnc_time (&secs2);
 +    g_assert_cmpint (secs1, ==, secs2);
 +    g_assert_cmpint (secs1, ==, time(0));
 +}
 +
 +/* gnc_difftime and gnc_tm_free are just too simple to bother testing. */
 +
 +/* gnc_date_dateformat_to_string
 +const char *gnc_default_strftime_date_format =
 +const char*
 +gnc_date_dateformat_to_string(QofDateFormat format)// C: 1  Local: 0:0:0
 +*/
 +
 +static void
 +test_gnc_date_dateformat_to_string (void)
 +{
 +    g_assert_cmpstr (gnc_date_dateformat_to_string (QOF_DATE_FORMAT_US), ==, "us");
 +    g_assert_cmpstr (gnc_date_dateformat_to_string (QOF_DATE_FORMAT_UK), ==, "uk");
 +    g_assert_cmpstr (gnc_date_dateformat_to_string (QOF_DATE_FORMAT_CE), ==, "ce");
 +    g_assert_cmpstr (gnc_date_dateformat_to_string (QOF_DATE_FORMAT_ISO), ==, "iso");
 +    g_assert_cmpstr (gnc_date_dateformat_to_string (QOF_DATE_FORMAT_UTC), ==, "utc");
 +    g_assert_cmpstr (gnc_date_dateformat_to_string (QOF_DATE_FORMAT_LOCALE), ==, "locale");
 +    g_assert_cmpstr (gnc_date_dateformat_to_string (QOF_DATE_FORMAT_CUSTOM), ==, "custom");
 +    g_assert_cmpstr (gnc_date_dateformat_to_string (QOF_DATE_FORMAT_UNSET), ==, "unset");
 +
 +}
 +/* gnc_date_string_to_dateformat
 +gboolean
 +gnc_date_string_to_dateformat(const char* fmt_str, QofDateFormat *format)// C: 3 in 3  Local: 0:0:0
 +*/
 +static void
 +test_gnc_date_string_to_dateformat (void)
 +{
 +    QofDateFormat fmt = 123;
 +    g_assert (gnc_date_string_to_dateformat (NULL, &fmt));
 +    g_assert_cmpint (fmt, ==, 123);
 +    g_assert (!gnc_date_string_to_dateformat ("us", &fmt));
 +    g_assert_cmpint (fmt, ==, QOF_DATE_FORMAT_US);
 +    g_assert (!gnc_date_string_to_dateformat ("uk", &fmt));
 +    g_assert_cmpint (fmt, ==, QOF_DATE_FORMAT_UK);
 +    g_assert (!gnc_date_string_to_dateformat ("ce", &fmt));
 +    g_assert_cmpint (fmt, ==, QOF_DATE_FORMAT_CE);
 +    g_assert (!gnc_date_string_to_dateformat ("iso", &fmt));
 +    g_assert_cmpint (fmt, ==, QOF_DATE_FORMAT_ISO);
 +    g_assert (!gnc_date_string_to_dateformat ("utc", &fmt));
 +    g_assert_cmpint (fmt, ==, QOF_DATE_FORMAT_UTC);
 +    g_assert (!gnc_date_string_to_dateformat ("locale", &fmt));
 +    g_assert_cmpint (fmt, ==, QOF_DATE_FORMAT_LOCALE);
 +    g_assert (!gnc_date_string_to_dateformat ("custom", &fmt));
 +    g_assert_cmpint (fmt, ==, QOF_DATE_FORMAT_CUSTOM);
 +    g_assert (!gnc_date_string_to_dateformat ("unset", &fmt));
 +    g_assert_cmpint (fmt, ==, QOF_DATE_FORMAT_UNSET);
 +    fmt = 123;
 +    g_assert (gnc_date_string_to_dateformat ("", &fmt));
 +    g_assert_cmpint (fmt, ==, 123);
 +    g_assert (gnc_date_string_to_dateformat ("foo", &fmt));
 +    g_assert_cmpint (fmt, ==, 123);
 +
 +}
 +/* gnc_date_monthformat_to_string
 +const char*
 +gnc_date_monthformat_to_string(GNCDateMonthFormat format)// C: 1  Local: 0:0:0
 +*/
 +static void
 +test_gnc_date_monthformat_to_string (void)
 +{
 +    g_assert_cmpstr (gnc_date_monthformat_to_string (GNCDATE_MONTH_NUMBER), ==, "number");
 +    g_assert_cmpstr (gnc_date_monthformat_to_string (GNCDATE_MONTH_ABBREV), ==, "abbrev");
 +    g_assert_cmpstr (gnc_date_monthformat_to_string (GNCDATE_MONTH_NAME), ==, "name");
 +    g_assert (gnc_date_monthformat_to_string (93) == NULL);
 +}
 +/* gnc_date_string_to_monthformat
 +gboolean
 +gnc_date_string_to_monthformat(const char *fmt_str, GNCDateMonthFormat *format)// C: 1  Local: 0:0:0
 +*/
 +static void
 +test_gnc_date_string_to_monthformat (void)
 +{
 +    GNCDateMonthFormat fmt = 123;
 +    g_assert (gnc_date_string_to_monthformat (NULL, &fmt));
 +    g_assert_cmpint (fmt, ==, 123);
 +    g_assert (!gnc_date_string_to_monthformat ("number", &fmt));
 +    g_assert_cmpint (fmt, ==, GNCDATE_MONTH_NUMBER);
 +    g_assert (!gnc_date_string_to_monthformat ("abbrev", &fmt));
 +    g_assert_cmpint (fmt, ==, GNCDATE_MONTH_ABBREV);
 +    g_assert (!gnc_date_string_to_monthformat ("name", &fmt));
 +    g_assert_cmpint (fmt, ==, GNCDATE_MONTH_NAME);
 +    fmt = 123;
 +    g_assert (gnc_date_string_to_monthformat ("", &fmt));
 +    g_assert_cmpint (fmt, ==, 123);
 +    g_assert (gnc_date_string_to_monthformat ("foo", &fmt));
 +    g_assert_cmpint (fmt, ==, 123);
 +}
 +
 +static void
 +test_gnc_setlocale (int category, gchar *locale)
 +{
 +    gchar *suffixes[] = {"utf8", "UTF-8"};
 +    guint i;
 +    /* Msys defines a different set of locales */
 +#ifdef G_OS_WIN32
 +    if (g_strcmp0 (locale, "en_US") == 0
 +            && setlocale (category, "English_US"))
 +        return;
 +    if (g_strcmp0 (locale, "en_GB") == 0
 +            && setlocale (category, "English_UK"))
 +        return;
 +    if (g_strcmp0 (locale, "fr_FR") == 0
 +            && setlocale (category, "French_France"))
 +        return;
 +
 +#endif
 +    if (setlocale (category, locale) != NULL)
 +        return;
 +
 +    for (i = 0; i < G_N_ELEMENTS (suffixes); i++)
 +    {
 +        gchar * modlocale = g_strdup_printf ("%s.%s", locale, suffixes[i]);
 +        gchar *localeval = setlocale (category, modlocale);
 +        g_free (modlocale);
 +        if (localeval != NULL)
 +            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.");
 +    g_assert_not_reached ();
 +}
 +/* timespec_normalize
 +static void
 +timespec_normalize(Timespec *t)// Local: 2:0:0
 +*/
 +static void
 +test_timespec_normalize (void)
 +{
 +    const int offset = 4396432;
 +    const int factor = 2;
 +    int base = 50;
 +    Timespec t = { base, factor * NANOS_PER_SECOND + offset };
 +    Testfuncs *tf = gnc_date_load_funcs ();
 +
 +    tf->timespec_normalize (&t);
 +    g_assert_cmpint (t.tv_sec, ==, base + factor);
 +    g_assert_cmpint (t.tv_nsec, ==, offset);
 +
 +    t.tv_sec = base;
 +    t.tv_nsec = - factor * NANOS_PER_SECOND - offset;
 +    tf->timespec_normalize (&t);
 +    g_assert_cmpint (t.tv_sec, ==, base - factor - 1);
 +    g_assert_cmpint (t.tv_nsec, ==, NANOS_PER_SECOND - offset);
 +
 +    t.tv_sec = - base;
 +    t.tv_nsec = factor * NANOS_PER_SECOND + offset;
 +    tf->timespec_normalize (&t);
 +    g_assert_cmpint (t.tv_sec, ==, - base + factor + 1);
 +    g_assert_cmpint (t.tv_nsec, ==, - NANOS_PER_SECOND + offset);
 +
 +    t.tv_sec = - base;
 +    t.tv_nsec = - factor * NANOS_PER_SECOND - offset;
 +    tf->timespec_normalize (&t);
 +    g_assert_cmpint (t.tv_sec, ==, - base - factor);
 +    g_assert_cmpint (t.tv_nsec, ==, - offset);
 +
 +    g_slice_free (Testfuncs, tf);
 +}
 +
 +
 +/* timespec_equal
 +gboolean
 +timespec_equal (const Timespec *ta, const Timespec *tb)// C: 19 in 8  Local: 0:0:0
 +*/
 +static void
 +test_timespec_equal (void)
 +{
 +    const int sec_per_day = 24 * 3600;
 +    const int sec_per_mo = 30 * sec_per_day;
 +    const time64 sec_per_yr = 365 * sec_per_day;
 +    const int nsec1 = 439652, nsec2 = 132794892, nsec3 = 1132794892;
 +    const time64 secs1 = 23 * sec_per_yr + 5 * sec_per_mo + 11 * sec_per_day;
 +    const time64 secs2 = 21 * sec_per_yr + 11 * sec_per_mo + 19 * sec_per_day;
 +    const time64 secs3 = 72 * sec_per_yr + 2 * sec_per_mo + 26 * sec_per_day;
 +    Timespec ta = { secs1, nsec1 };
 +    Timespec tb = { secs2, nsec2 };
 +    Timespec tc = { secs1, nsec1 };
 +    Timespec td = { secs3, nsec1 };
 +    Timespec te = { secs1, nsec2 };
 +    Timespec tf = { secs2 - 1, nsec3 }; /* When normalized, equal to tb */
 +
 +    g_assert (timespec_equal (&ta, &ta));
 +    g_assert (timespec_equal (&ta, &tc));
 +    g_assert (!timespec_equal (&ta, &tb));
 +    g_assert (!timespec_equal (&ta, &td));
 +    g_assert (!timespec_equal (&ta, &te));
 +    g_assert (timespec_equal (&tb, &tf));
 +}
 +/* timespec_cmp
 +gint
 +timespec_cmp(const Timespec *ta, const Timespec *tb)// C: 28 in 11  Local: 0:0:0
 +*/
 +static void
 +test_timespec_cmp (void)
 +{
 +    const int sec_per_day = 24 * 3600;
 +    const int sec_per_mo = 30 * sec_per_day;
 +    const time64 sec_per_yr = 365 * sec_per_day;
 +    const int nsec1 = 439652, nsec2 = 132794892, nsec3 = 1132794892;
 +    const time64 secs1 = 23 * sec_per_yr + 5 * sec_per_mo + 11 * sec_per_day;
 +    const time64 secs2 = 21 * sec_per_yr + 11 * sec_per_mo + 19 * sec_per_day;
 +    const time64 secs3 = 72 * sec_per_yr + 2 * sec_per_mo + 26 * sec_per_day;
 +    Timespec ta = { secs1, nsec1 };
 +    Timespec tb = { secs2, nsec2 };
 +    Timespec tc = { secs1, nsec1 };
 +    Timespec td = { secs3, nsec1 };
 +    Timespec te = { secs1, nsec2 };
 +    Timespec tf = { secs2 - 1, nsec3 }; /* When normalized, equal to tb */
 +    Timespec tg = { -secs2, nsec2 };
 +    Timespec th = { secs1, -nsec1 };
 +
 +    g_assert_cmpint (timespec_cmp (&ta, &ta), ==, 0);
 +    g_assert_cmpint (timespec_cmp (&ta, &tc), ==, 0);
 +    g_assert_cmpint (timespec_cmp (&tf, &tb), ==, 0);
 +    g_assert_cmpint (timespec_cmp (&ta, &tb), ==, 1);
 +    g_assert_cmpint (timespec_cmp (&te, &ta), ==, 1);
 +    g_assert_cmpint (timespec_cmp (&td, &ta), ==, 1);
 +    g_assert_cmpint (timespec_cmp (&ta, &te), ==, -1);
 +    g_assert_cmpint (timespec_cmp (&ta, &tg), ==, 1);
 +    g_assert_cmpint (timespec_cmp (&th, &ta), ==, -1);
 +
 +}
 +/* timespec_diff
 +Timespec
 +timespec_diff(const Timespec *ta, const Timespec *tb)// C: 4 in 1  Local: 0:0:0
 +*/
 +static void
 +test_timespec_diff (void)
 +{
 +    const gint sec_per_day = 24 * 3600;
 +    const gint sec_per_mo = 30 * sec_per_day;
 +    const time64 sec_per_yr = 365 * sec_per_day;
 +    const time64 nsec1 = 439652, nsec2 = 132794892, nsec3 = 1132794892;
 +    const time64 secs1 = 23 * sec_per_yr + 5 * sec_per_mo + 11 * sec_per_day;
 +    const time64 secs2 = 21 * sec_per_yr + 11 * sec_per_mo + 19 * sec_per_day;
 +    const time64 secs3 = 72 * sec_per_yr + 2 * sec_per_mo + 26 * sec_per_day;
 +    Timespec ta = { secs1, nsec1 };
 +    Timespec tb = { secs2, nsec2 };
 +    Timespec td = { secs3, nsec1 };
 +    Timespec te = { secs1, nsec2 };
 +    Timespec tf = { secs2 - 1, nsec3 }; /* When normalized, equal to tb */
 +    Timespec tg = { -secs2, nsec2 };
 +    Timespec th = { secs1, -nsec3 };
 +
 +    Timespec tt = timespec_diff (&ta, &ta);
 +
 +    g_assert_cmpint (tt.tv_sec, ==, 0);
 +    g_assert_cmpint (tt.tv_nsec, ==, 0);
 +
 +    tt = timespec_diff (&ta, &tb);
 +    g_assert_cmpint (tt.tv_sec, ==, secs1 - secs2 - 1);
 +    g_assert_cmpint (tt.tv_nsec, ==, nsec1 - nsec2 + NANOS_PER_SECOND);
 +
 +    tt = timespec_diff (&ta, &te);
 +    g_assert_cmpint (tt.tv_sec, ==, 0);
 +    g_assert_cmpint (tt.tv_nsec, ==, nsec1 - nsec2);
 +
 +    tt = timespec_diff (&tb, &tf);
 +    g_assert_cmpint (tt.tv_sec, ==, 0);
 +    g_assert_cmpint (tt.tv_nsec, ==, 0);
 +
 +    tt = timespec_diff (&tf, &th);
 +    if (sizeof (glong) > 4)
 +    {
 +        glong nsec_diff_norm = 2 * nsec3 - 2 * NANOS_PER_SECOND - NANOS_PER_SECOND;
 +        g_assert_cmpint (tt.tv_sec, ==, secs2 - secs1 + 2);
 +        g_assert_cmpint (tt.tv_nsec, ==,  nsec_diff_norm);
 +    }
 +    else
 +    {
 +        g_assert_cmpint (tt.tv_sec, ==, secs2 - secs1 - 3);
 +        g_assert_cmpint (tt.tv_nsec, <, 0); /* Overflow nanosecs */
 +    }
 +    tt = timespec_diff (&tg, &td);
 +    g_assert_cmpint (tt.tv_sec, ==, -secs2 - secs3 + 1);
 +    g_assert_cmpint (tt.tv_nsec, ==, nsec2 - nsec1 - NANOS_PER_SECOND);
 +
 +}
 +/* timespec_abs
 +Timespec
 +timespec_abs(const Timespec *t)// C: 4 in 1  Local: 0:0:0
 +*/
 +static void
 +test_timespec_abs (void)
 +{
 +    const int sec_per_day = 24 * 3600;
 +    const int sec_per_mo = 30 * sec_per_day;
 +    const int sec_per_yr = 365 * sec_per_day;
 +    const int nsec1 = 439652, nsec2 = 132794892, nsec3 = 1132794892;
 +    const time64 secs1 = 23 * sec_per_yr + 5 * sec_per_mo + 11 * sec_per_day;
 +    const time64 secs2 = 21 * sec_per_yr + 11 * sec_per_mo + 19 * sec_per_day;
 +    Timespec ta = { secs1, nsec1 };
 +    Timespec tf = { secs2 - 1, nsec3 }; /* When normalized, equal to tb */
 +    Timespec tg = { -secs2, nsec2 };
 +    Timespec th = { secs1, -nsec1 };
 +
 +    Timespec tt = timespec_abs (&ta);
 +    g_assert_cmpint (tt.tv_sec, ==, secs1);
 +    g_assert_cmpint (tt.tv_nsec, ==, nsec1);
 +
 +    tt = timespec_abs (&tf);
 +    g_assert_cmpint (tt.tv_sec, ==, secs2);
 +    g_assert_cmpint (tt.tv_nsec, ==, nsec2);
 +
 +    tt = timespec_abs (&tg);
 +    g_assert_cmpint (tt.tv_sec, ==, secs2 - 1);
 +    g_assert_cmpint (tt.tv_nsec, ==, NANOS_PER_SECOND - nsec2);
 +
 +    tt = timespec_abs (&th);
 +    g_assert_cmpint (tt.tv_sec, ==, secs1 - 1);
 +    g_assert_cmpint (tt.tv_nsec, ==, NANOS_PER_SECOND - nsec1);
 +
 +}
 +/* timespecCanonicalDayTime
 +Timespec
 +timespecCanonicalDayTime(Timespec t)// C: 12 in 5 SCM: 19 in 10 Local: 0:0:0
 +*/
 +static Timespec
 +compute_noon_of_day (Timespec *ts)
 +{
 +    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;
 +}
 +
 +static void
 +test_timespecCanonicalDayTime (void)
 +{
 +    const int sec_per_day = 24 * 3600;
 +    const int sec_per_mo = 30 * sec_per_day;
 +    const time64 sec_per_yr = 365 * sec_per_day;
 +    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;
 +
 +    Timespec t0 = { secs, 0 };
 +    Timespec ta = { secs1, 0 };
 +    Timespec tb = { secs2, 0 };
 +
 +    Timespec n0 = compute_noon_of_day (&t0);
 +    Timespec na = compute_noon_of_day (&ta);
 +    Timespec nb = compute_noon_of_day (&tb);
 +
 +    Timespec r0 = timespecCanonicalDayTime (t0);
 +    Timespec ra = timespecCanonicalDayTime (ta);
 +    Timespec rb = timespecCanonicalDayTime (tb);
 +
 +    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);
 +
 +}
 +
 +/* gnc_date_get_last_mday
 +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 (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), ==, 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
 +*/
 +/* qof_date_format_set
 +set date format to one of US, UK, CE, ISO OR UTC
 +checks to make sure it's a legal value
 +param QofDateFormat: enumeration indicating preferred format
 +return void
 +Globals: dateFormat
 +void qof_date_format_set(QofDateFormat df)// C: 3 in 2  Local: 0:0:0
 +*/
 +static void
 +test_qof_date_format_set (void)
 +{
 +    gchar *msg = "[qof_date_format_set()] non-existent date format set attempted. Setting ISO default";
 +    gint loglevel = G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL;
 +    gchar *logdomain = "qof.engine";
 +    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);
 +    qof_date_format_set ((QofDateFormat)((guint)DATE_FORMAT_LAST + 97));
 +    g_assert_cmpint (qof_date_format_get (), ==,  QOF_DATE_FORMAT_ISO);
 +    g_assert_cmpint (check.hits, ==,1);
 +
 +    qof_date_format_set (QOF_DATE_FORMAT_UK);
 +    g_assert_cmpint (qof_date_format_get (), ==, QOF_DATE_FORMAT_UK);
 +    g_assert_cmpint (check.hits, ==,1);
 +    g_log_set_default_handler (hdlr, NULL);
 +}
 +/* qof_date_completion_set
 +set dateCompletion to one of QOF_DATE_COMPLETION_THISYEAR (for
 +completing the year to the current calendar year) or
 +QOF_DATE_COMPLETION_SLIDING (for using a sliding 12-month window). The
 +sliding window starts 'backmonth' months before the current month (0-11).
 +checks to make sure it's a legal value
 +param QofDateCompletion: indicates preferred completion method
 +param int: the number of months to go back in time (0-11)
 +return void
 +Globals: dateCompletion dateCompletionBackMonths
 +void qof_date_completion_set(QofDateCompletion dc, int backmonths)// C: 1  Local: 0:0:0
 +*/
 +/* static void
 +test_qof_date_completion_set (void)
 +{
 +}*/
 +/* qof_print_date_dmy_buff
 +size_t
 +qof_print_date_dmy_buff (char * buff, size_t len, int day, int month, int year)// C: 12 in 3  Local: 2:0:0
 +*/
 +
 +#ifdef HAVE_LANGINFO_D_FMT
 +#include <langinfo.h>
 +#  define GNC_D_FMT (nl_langinfo (D_FMT))
 +#  define GNC_D_T_FMT (nl_langinfo (D_T_FMT))
 +#  define GNC_T_FMT (nl_langinfo (T_FMT))
 +#elif defined(G_OS_WIN32)
 +#  define GNC_D_FMT (qof_win32_get_time_format(QOF_WIN32_PICTURE_DATE))
 +#  define GNC_T_FMT (qof_win32_get_time_format(QOF_WIN32_PICTURE_TIME))
 +#  define GNC_D_T_FMT (qof_win32_get_time_format(QOF_WIN32_PICTURE_DATETIME))
 +#else
 +#  define GNC_D_FMT "%Y-%m-%d"
 +#  define GNC_D_T_FMT "%Y-%m-%d %r"
 +#  define GNC_T_FMT "%r"
 +#endif
 +
 +static void tm_set_dmy (struct tm *tm, gint year, gint month, gint mday)
 +{
 +    tm->tm_year = year - 1900;
 +    tm->tm_mon = month - 1;
 +    tm->tm_mday = mday;
 +}
 +
 +static void
 +test_qof_print_date_dmy_buff (void)
 +{
 +    gchar buff[MAX_DATE_LENGTH], t_buff[MAX_DATE_LENGTH];
 +    gchar *locale = g_strdup (setlocale (LC_TIME, NULL));
 +    struct tm tm = { 0, 0, 0, 0, 0, 0, 0, 0, 0
 +#ifdef HAVE_STRUCT_TM_GMTOFF
 +        , 0, 0
 +#endif
 +    };
 +
 +    qof_date_format_set (QOF_DATE_FORMAT_UK);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), 23, 11, 1974), ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, "23/11/1974");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), 2, 2, 1961), ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, "02/02/1961");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), 16, 6, 2045), ==, 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_dmy_buff (buff, sizeof (buff), 23, 11, 1974), ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, "23.11.1974");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), 2, 2, 1961), ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, "02.02.1961");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), 16, 6, 2045), ==, 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_dmy_buff (buff, sizeof (buff), 23, 11, 1974), ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, "11/23/1974");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), 2, 2, 1961), ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, "02/02/1961");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), 16, 6, 2045), ==, 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_dmy_buff (buff, sizeof (buff), 23, 11, 1974), ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, "1974-11-23");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), 2, 2, 1961),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, "1961-02-02");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), 16, 6, 2045),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, "2045-06-16");
 +
 +    qof_date_format_set (QOF_DATE_FORMAT_LOCALE);
 +    test_gnc_setlocale (LC_TIME, "en_US");
 +    tm_set_dmy (&tm, 1974, 11, 23);
 +    strftime(t_buff, MAX_DATE_LENGTH, GNC_D_FMT, &tm);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), tm.tm_mday,
 +                     tm.tm_mon + 1, tm.tm_year + 1900),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, t_buff);
 +
 +
 +    tm_set_dmy (&tm, 1961, 2, 2);
 +    strftime(t_buff, MAX_DATE_LENGTH, GNC_D_FMT, &tm);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), tm.tm_mday,
 +                     tm.tm_mon + 1, tm.tm_year + 1900),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, t_buff);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    tm_set_dmy (&tm, 2045, 6, 16);
 +    strftime(t_buff, MAX_DATE_LENGTH, GNC_D_FMT, &tm);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), tm.tm_mday,
 +                     tm.tm_mon + 1, tm.tm_year + 1900),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, t_buff);
 +
 +    test_gnc_setlocale (LC_TIME, "en_GB");
 +    tm_set_dmy (&tm, 1974, 11, 23);
 +    strftime(t_buff, MAX_DATE_LENGTH, GNC_D_FMT, &tm);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), tm.tm_mday,
 +                     tm.tm_mon + 1, tm.tm_year + 1900),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, t_buff);
 +    tm_set_dmy (&tm, 1961, 2, 2);
 +    strftime(t_buff, MAX_DATE_LENGTH, GNC_D_FMT, &tm);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), tm.tm_mday,
 +                     tm.tm_mon + 1, tm.tm_year + 1900),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, t_buff);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    tm_set_dmy (&tm, 2045, 6, 16);
 +    strftime(t_buff, MAX_DATE_LENGTH, GNC_D_FMT, &tm);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), tm.tm_mday,
 +                     tm.tm_mon + 1, tm.tm_year + 1900),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, t_buff);
 +
 +    test_gnc_setlocale (LC_TIME, "fr_FR");
 +    tm_set_dmy (&tm, 1974, 11, 23);
 +    strftime(t_buff, MAX_DATE_LENGTH, GNC_D_FMT, &tm);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), tm.tm_mday,
 +                     tm.tm_mon + 1, tm.tm_year + 1900),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, t_buff);
 +    tm_set_dmy (&tm, 1961, 2, 2);
 +    strftime(t_buff, MAX_DATE_LENGTH, GNC_D_FMT, &tm);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), tm.tm_mday,
 +                     tm.tm_mon + 1, tm.tm_year + 1900),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, t_buff);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    tm_set_dmy (&tm, 2045, 6, 16);
 +    strftime(t_buff, MAX_DATE_LENGTH, GNC_D_FMT, &tm);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_date_dmy_buff (buff, sizeof (buff), tm.tm_mday,
 +                     tm.tm_mon + 1, tm.tm_year + 1900),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, t_buff);
 +
 +    setlocale (LC_TIME, locale);
 +    g_free (locale);
 +}
 +
 +/* Different distros/OSes define localization date formats. Apple, for
 + * example, uses %d.%m.%Y for fr_FR and %d/%m/%Y for en_GB, while
 + * Debian uses %d/%m/%Y and %d/%m/%y respectively. So to get a test
 + * that works on all of them, we need to check the localized
 + * strftime().
 + *
 + * This is a macro so that the line number in the assert message will
 + * be right.
 + */
 +
 +#define test_assert_localized_timestring(time, datestr)                 \
 +    {                                                                   \
 +        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);                                            \
 +        g_assert_cmpstr (datestr, ==, t_buff);                          \
 +    }
 +
 +
 +/* qof_print_date_buff
 +size_t
 +qof_print_date_buff (char * buff, size_t len, time64 t)// C: 3 in 1  Local: 2:0:0
 +*/
 +static void
 +test_qof_print_date_buff (void)
 +{
 +    gchar buff[MAX_DATE_LENGTH], ans[MAX_DATE_LENGTH];
 +    gchar *locale = g_strdup (setlocale (LC_TIME, NULL));
 +
 +    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), 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), 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), 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), 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), 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), 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), 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), 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), 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), 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), 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), 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), 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), 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), 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), time1),
 +                     ==, strlen (buff));
 +    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), time2),
 +                     ==, strlen (buff));
 +    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), time3),
 +                     ==, strlen (buff));
 +    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), time1),
 +                     ==, strlen (buff));
 +    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), time2),
 +                     ==, strlen (buff));
 +    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), time3),
 +                     ==, strlen (buff));
 +    strftime(ans, MAX_DATE_LENGTH, GNC_D_FMT, &tm3);
 +    g_assert_cmpstr (buff, ==, ans);
 +
 +    setlocale (LC_TIME, locale);
 +    g_free (locale);
 +}
 +/* qof_print_gdate
 +size_t
 +qof_print_gdate( char *buf, size_t len, const GDate *gd )// C: 6 in 5  Local: 0:0:0
 +*/
 +static void
 +test_qof_print_gdate (void)
 +{
 +    gchar buff[MAX_DATE_LENGTH], t_buff[MAX_DATE_LENGTH];
 +    gchar *locale = g_strdup (setlocale (LC_TIME, NULL));
 +    GDate *gd1 = g_date_new_dmy (23, 11, 1974);
 +    GDate *gd2 = g_date_new_dmy (2, 2, 1961);
 +    GDate *gd3 = g_date_new_dmy (16, 6, 2045);
 +
 +    qof_date_format_set (QOF_DATE_FORMAT_UK);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_gdate (buff, sizeof (buff), gd1),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, "23/11/1974");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_gdate (buff, sizeof (buff), gd2),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, "02/02/1961");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_gdate (buff, sizeof (buff), gd3),
 +                     ==, 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_gdate (buff, sizeof (buff), gd1),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, "23.11.1974");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_gdate (buff, sizeof (buff), gd2),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, "02.02.1961");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_gdate (buff, sizeof (buff), gd3),
 +                     ==, 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_gdate (buff, sizeof (buff), gd1),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, "11/23/1974");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_gdate (buff, sizeof (buff), gd2),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, "02/02/1961");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_gdate (buff, sizeof (buff), gd3),
 +                     ==, 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_gdate (buff, sizeof (buff), gd1),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, "1974-11-23");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_gdate (buff, sizeof (buff), gd2),
 +                     ==, strlen (buff));
 +    g_assert_cmpstr (buff, ==, "1961-02-02");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_gdate (buff, sizeof (buff), gd3),
 +                     ==, 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_gdate (buff, sizeof (buff), gd1),
 +                     ==, strlen (buff));
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd1);
 +    g_assert_cmpstr (buff, ==, t_buff);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_gdate (buff, sizeof (buff), gd2),
 +                     ==, strlen (buff));
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd2);
 +    g_assert_cmpstr (buff, ==, t_buff);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_gdate (buff, sizeof (buff), gd3),
 +                     ==, strlen (buff));
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd3);
 +    g_assert_cmpstr (buff, ==, t_buff);
 +
 +    test_gnc_setlocale (LC_TIME, "en_GB");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_gdate (buff, sizeof (buff), gd1),
 +                     ==, strlen (buff));
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd1);
 +    g_assert_cmpstr (buff, ==, t_buff);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_gdate (buff, sizeof (buff), gd2),
 +                     ==, strlen (buff));
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd2);
 +    g_assert_cmpstr (buff, ==, t_buff);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_gdate (buff, sizeof (buff), gd3),
 +                     ==, strlen (buff));
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd3);
 +    g_assert_cmpstr (buff, ==, t_buff);
 +
 +
 +    test_gnc_setlocale (LC_TIME, "fr_FR");
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_gdate (buff, sizeof (buff), gd1),
 +                     ==, strlen (buff));
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd1);
 +    g_assert_cmpstr (buff, ==, t_buff);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_gdate (buff, sizeof (buff), gd2),
 +                     ==, strlen (buff));
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd2);
 +    g_assert_cmpstr (buff, ==, t_buff);
 +    memset ((gpointer)buff, 0, sizeof (buff));
 +    g_assert_cmpint (qof_print_gdate (buff, sizeof (buff), gd3),
 +                     ==, strlen (buff));
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd3);
 +    g_assert_cmpstr (buff, ==, t_buff);
 +
 +    setlocale (LC_TIME, locale);
 +    g_free (locale);
 +    g_date_free (gd1);
 +    g_date_free (gd2);
 +    g_date_free (gd3);
 +}
 +
 +#define test_assert_qof_print_date(time, datestr)  \
 +    {                                              \
 +        gchar *buf = qof_print_date (time);        \
 +        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_free (buf);                              \
 +    }
 +
 +#define test_assert_localized_qof_print_date(time)           \
 +    {                                                        \
 +        gchar *buf = qof_print_date (time);                  \
 +        test_assert_localized_timestring (time, buf);        \
 +        g_free (buf);                                        \
 +    }
 +
 +/* qof_print_date
 +char *
 +qof_print_date (time64 t)// C: 29 in 13  Local: 0:0:0
 +*/
 +static void
 +test_qof_print_date (void)
 +{
 +    gchar *locale = g_strdup (setlocale (LC_TIME, NULL));
 +    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 (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 (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 (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 (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");
 +    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");
 +    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");
 +    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);
 +}
 +/* gnc_print_date
 +const char *
 +gnc_print_date (Timespec ts)// C: 11 in 9 SCM: 166 in 59 Local: 0:0:0
 +*/
 +static void
 +test_gnc_print_date (void)
 +{
 +    gchar t_buff[MAX_DATE_LENGTH];
 +    gchar *locale = g_strdup (setlocale (LC_TIME, NULL));
 +    GDate *gd1 = g_date_new_dmy (23, 11, 1974);
 +    GDate *gd2 = g_date_new_dmy (2, 2, 1961);
 +    GDate *gd3 = g_date_new_dmy (16, 6, 2045);
 +    Timespec tm1 = gdate_to_timespec (*gd1);
 +    Timespec tm2 = gdate_to_timespec (*gd2);
 +    Timespec tm3 = gdate_to_timespec (*gd3);
 +
 +
 +    qof_date_format_set (QOF_DATE_FORMAT_UK);
 +    g_assert_cmpstr (gnc_print_date (tm1), ==, "23/11/1974");
 +    g_assert_cmpstr (gnc_print_date (tm2), ==, "02/02/1961");
 +    g_assert_cmpstr (gnc_print_date (tm3), ==, "16/06/2045");
 +
 +    qof_date_format_set (QOF_DATE_FORMAT_CE);
 +    g_assert_cmpstr (gnc_print_date (tm1), ==, "23.11.1974");
 +    g_assert_cmpstr (gnc_print_date (tm2), ==, "02.02.1961");
 +    g_assert_cmpstr (gnc_print_date (tm3), ==, "16.06.2045");
 +
 +    qof_date_format_set (QOF_DATE_FORMAT_US);
 +    g_assert_cmpstr (gnc_print_date (tm1), ==, "11/23/1974");
 +    g_assert_cmpstr (gnc_print_date (tm2), ==, "02/02/1961");
 +    g_assert_cmpstr (gnc_print_date (tm3), ==, "06/16/2045");
 +
 +    qof_date_format_set (QOF_DATE_FORMAT_ISO);
 +    g_assert_cmpstr (gnc_print_date (tm1), ==, "1974-11-23");
 +    g_assert_cmpstr (gnc_print_date (tm2), ==, "1961-02-02");
 +    g_assert_cmpstr (gnc_print_date (tm3), ==, "2045-06-16");
 +
 +    qof_date_format_set (QOF_DATE_FORMAT_LOCALE);
 +    test_gnc_setlocale (LC_TIME, "en_US");
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd1);
 +    g_assert_cmpstr (gnc_print_date (tm1), ==, t_buff);
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd2);
 +    g_assert_cmpstr (gnc_print_date (tm2), ==, t_buff);
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd3);
 +    g_assert_cmpstr (gnc_print_date (tm3), ==, t_buff);
 +
 +    test_gnc_setlocale (LC_TIME, "en_GB");
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd1);
 +    g_assert_cmpstr (gnc_print_date (tm1), ==, t_buff);
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd2);
 +    g_assert_cmpstr (gnc_print_date (tm2), ==, t_buff);
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd3);
 +    g_assert_cmpstr (gnc_print_date (tm3), ==, t_buff);
 +
 +    test_gnc_setlocale (LC_TIME, "fr_FR");
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd1);
 +    g_assert_cmpstr (gnc_print_date (tm1), ==, t_buff);
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd2);
 +    g_assert_cmpstr (gnc_print_date (tm2), ==, t_buff);
 +    g_date_strftime (t_buff, MAX_DATE_LENGTH, GNC_D_FMT, gd3);
 +    g_assert_cmpstr (gnc_print_date (tm3), ==, t_buff);
 +
 +    setlocale (LC_TIME, locale);
 +    g_free (locale);
 +    g_date_free (gd1);
 +    g_date_free (gd2);
 +    g_date_free (gd3);
 +}
 +/* floordiv
 +static int
 +floordiv(int a, int b)// Local: 1:0:0
 +*/
 +/* static void
 +test_floordiv (void)
 +{
 +}*/
 +/* qof_scan_date_internal
 +qof_scan_date just does passes this through, passing the pre-set QOF_DATE_FORMAT, so we test there rather than exposing this via Testfuncs.
 +qof_scan_date_internal (const char *buff, int *day, int *month, int *year,// Local: 3:0:0
 +*/
 +/* static void
 +test_qof_scan_date_internal (void)
 +{
 +} */
 +/* qof_scan_date
 +gboolean
 +qof_scan_date (const char *buff, int *day, int *month, int *year)// C: 7 in 3  Local: 0:0:0
 +*/
 +static void
 +test_qof_scan_date (void)
 +{
 +    gchar *locale = g_strdup (setlocale (LC_TIME, NULL));
 +    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
 +#endif
 +    };
 +    gnc_localtime_r(&now, &tm);
 +    year = tm.tm_year + 1900;
 +    month = tm.tm_mon + 1;
 +
 +    g_assert (!qof_scan_date (NULL, &day, &mo, &yr));
 +    g_assert_cmpint (day, ==, 0);
 +    g_assert_cmpint (mo, ==, 0);
 +    g_assert_cmpint (yr, ==, 0);
 +
 +    qof_date_format_set (QOF_DATE_FORMAT_UTC);
 +    g_assert (qof_scan_date ("1974-11-23", &day, &mo, &yr));
 +    g_assert_cmpint (day, ==, 23);
 +    g_assert_cmpint (mo, ==, 11);
 +    g_assert_cmpint (yr, ==, 1974);
 +
 +    g_assert (qof_scan_date ("1961-2-2", &day, &mo, &yr));
 +    g_assert_cmpint (day, ==, 2);
 +    g_assert_cmpint (mo, ==, 2);
 +    g_assert_cmpint (yr, ==, 1961);
 +
 +    g_assert (qof_scan_date ("2045-6-16", &day, &mo, &yr));
 +    g_assert_cmpint (day, ==, 16);
 +    g_assert_cmpint (mo, ==, 6);
 +    g_assert_cmpint (yr, ==, 2045);
 +
 +    qof_date_format_set (QOF_DATE_FORMAT_US);
 +    g_assert (qof_scan_date ("11/23/1974", &day, &mo, &yr));
 +    g_assert_cmpint (day, ==, 23);
 +    g_assert_cmpint (mo, ==, 11);
 +    g_assert_cmpint (yr, ==, 1974);
 +
 +    g_assert (qof_scan_date ("2/2/1961", &day, &mo, &yr));
 +    g_assert_cmpint (day, ==, 2);
 +    g_assert_cmpint (mo, ==, 2);
 +    g_assert_cmpint (yr, ==, 1961);
 +
 +    g_assert (qof_scan_date ("6/16/2045", &day, &mo, &yr));
 +    g_assert_cmpint (day, ==, 16);
 +    g_assert_cmpint (mo, ==, 6);
 +    g_assert_cmpint (yr, ==, 2045);
 +
 +    g_assert (qof_scan_date ("11ì›”23ë…„1974", &day, &mo, &yr));
 +    g_assert_cmpint (day, ==, 23);
 +    g_assert_cmpint (mo, ==, 11);
 +    g_assert_cmpint (yr, ==, 1974);
 +
 +    g_assert (qof_scan_date ("11月23年1974", &day, &mo, &yr));
 +    g_assert_cmpint (day, ==, 23);
 +    g_assert_cmpint (mo, ==, 11);
 +    g_assert_cmpint (yr, ==, 1974);
 +
 +    qof_date_completion_set (QOF_DATE_COMPLETION_THISYEAR, 0);
 +
 +    g_assert (qof_scan_date ("11-23", &day, &mo, &yr));
 +    g_assert_cmpint (day, ==, 23);
 +    g_assert_cmpint (mo, ==, 11);
 +    g_assert_cmpint (yr, ==, year);
 +
 +    g_assert (qof_scan_date ("23-11", &day, &mo, &yr));
 +    g_assert_cmpint (day, ==, 23);
 +    g_assert_cmpint (mo, ==, 11);
 +    g_assert_cmpint (yr, ==, year);
 +
 +    if (month < 10) /* Sliding window won't test well after October */
 +    {
 +        qof_date_completion_set (QOF_DATE_COMPLETION_SLIDING, month + 1);
 +
 +        g_assert (qof_scan_date ("12-23", &day, &mo, &yr));
 +        g_assert_cmpint (day, ==, 23);
 +        g_assert_cmpint (mo, ==, 12);
 +        g_assert_cmpint (yr, ==, year - 1);
 +
 +        qof_date_completion_set (QOF_DATE_COMPLETION_THISYEAR, 0);
 +    }
 +
 +    qof_date_format_set (QOF_DATE_FORMAT_UK);
 +    g_assert (qof_scan_date ("23/11/1974", &day, &mo, &yr));
 +    g_assert_cmpint (day, ==, 23);
 +    g_assert_cmpint (mo, ==, 11);
 +    g_assert_cmpint (yr, ==, 1974);
 +
 +    g_assert (qof_scan_date ("2/2/1961", &day, &mo, &yr));
 +    g_assert_cmpint (day, ==, 2);
 +    g_assert_cmpint (mo, ==, 2);
 +    g_assert_cmpint (yr, ==, 1961);
 +
 +    g_assert (qof_scan_date ("16/6/2045", &day, &mo, &yr));
 +    g_assert_cmpint (day, ==, 16);
 +    g_assert_cmpint (mo, ==, 6);
 +    g_assert_cmpint (yr, ==, 2045);
 +
 +    qof_date_format_set (QOF_DATE_FORMAT_LOCALE);
 +    test_gnc_setlocale (LC_TIME, "en_GB");
 +    tm_set_dmy (&tm, 1974, 11, 23);
 +    strftime (buff, MAX_DATE_LENGTH, GNC_D_FMT, &tm);
 +    g_assert (qof_scan_date (buff, &day, &mo, &yr));
 +    g_assert_cmpint (day, ==, tm.tm_mday);
 +    g_assert_cmpint (mo, ==, tm.tm_mon + 1);
 +    g_assert_cmpint (yr, ==, tm.tm_year + 1900);
 +
 +    tm_set_dmy (&tm, 1961,2, 2);
 +    strftime (buff, MAX_DATE_LENGTH, GNC_D_FMT, &tm);
 +    g_assert (qof_scan_date (buff, &day, &mo, &yr));
 +    g_assert_cmpint (day, ==, tm.tm_mday);
 +    g_assert_cmpint (mo, ==, tm.tm_mon + 1);
 +    /* Some locale date formats result in a 2-digit year, which strptime
 +     * interprets as being in the current century.
 +     */
 +    g_assert_cmpint (yr % 100, ==, tm.tm_year % 100);
 +
 +    tm_set_dmy (&tm, 2045, 6, 16);
 +    strftime (buff, MAX_DATE_LENGTH, GNC_D_FMT, &tm);
 +    g_assert (qof_scan_date (buff, &day, &mo, &yr));
 +    g_assert_cmpint (day, ==, tm.tm_mday);
 +    g_assert_cmpint (mo, ==, tm.tm_mon + 1);
 +    g_assert_cmpint (yr, ==, tm.tm_year + 1900);
 +
 +    setlocale (LC_TIME, locale);
 +    g_free (locale);
 +}
 +/* dateSeparator
 +return date character
 +char dateSeparator (void)// C: 1  Local: 0:0:0
 +src/register/register-gnome/datecell-gnome.h
 +*/
 +/* static void
 +test_dateSeparator (void)
 +{
 +}*/
 +/* qof_time_format_from_utf8
 +gchar *
 +qof_time_format_from_utf8(const gchar *utf8_format)// C: 1  Local: 1:0:0
 +*/
 +/* static void
 +test_qof_time_format_from_utf8 (void)
 +{
 +}*/
 +/* qof_formatted_time_to_utf8
 +gchar *
 +qof_formatted_time_to_utf8(const gchar *locale_string)// C: 1  Local: 1:0:0
 +*/
 +/* static void
 +test_qof_formatted_time_to_utf8 (void)
 +{
 +}*/
 +/* qof_format_time
 +static gchar *
 +qof_format_time(const gchar *format, const struct tm *tm)// Local: 1:0:0
 +*/
 +/* static void
 +test_qof_format_time (void)
 +{
 +}*/
 +/* qof_strftime
 +gsize
 +qof_strftime(gchar *buf, gsize max, const gchar *format, const struct tm *tm)// C: 16 in 9  Local: 5:0:0
 +*/
 +/* static void
 +test_qof_strftime (void)
 +{
 +}*/
 +/* gnc_date_timestamp
 +gchar *
 +gnc_date_timestamp (void)// C: 2 in 2  Local: 0:0:0
 +*/
 +static void
 +test_gnc_date_timestamp (void)
 +{
 +    time64 now = gnc_time(NULL);
 +    gchar *timestr = gnc_date_timestamp ();
 +    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_free (timestr);
 +}
 +/* gnc_iso8601_to_timespec_gmt
 +Timespec
 +gnc_iso8601_to_timespec_gmt(const char *str)// C: 6 in 3  Local: 0:0:0
 +*/
 +static gint
 +get_nanoseconds (GDateTime *gdt)
 +{
 +    return g_date_time_get_microsecond (gdt) * 1000;
 +}
 +
 +static void
 +test_gnc_iso8601_to_timespec_gmt (FixtureA *f, gconstpointer pData)
 +{
 +    Timespec t;
 +
 +    t = gnc_iso8601_to_timespec_gmt (NULL);
 +    g_assert_cmpint (t.tv_sec, ==, 0);
 +    g_assert_cmpint (t.tv_nsec, ==, 0);
 +
 +    t = gnc_iso8601_to_timespec_gmt ("");
 +    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");
 +    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, <=, f->ts1.tv_nsec);
 +    g_assert_cmpint (t.tv_nsec + 2000, >=, f->ts1.tv_nsec);
 +#else
 +    g_assert_cmpint (t.tv_nsec, ==, f->ts1.tv_nsec);
 +#endif
 +    t = gnc_iso8601_to_timespec_gmt ("2020-11-07 06:21:19 -05");
 +    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, ==, 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, ==, 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, ==, 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
 +*/
 +static Timespec
 +g_date_time_to_timespec (GDateTime *gdt)
 +{
 +    Timespec t;
 +    t.tv_sec = g_date_time_to_unix (gdt);
 +    t.tv_nsec = g_date_time_get_microsecond (gdt) * 1000;
 +    return t;
 +}
 +
 +#define ISO8601_SIZE MAX_DATE_LENGTH + 4
 +static gchar*
 +format_timestring (Timespec ts, TZOffset tz)
 +{
 +  static const unsigned tzlen = MAX_DATE_LENGTH - 26;
 +    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
 +    strftime(tzbuf, sizeof(tzbuf), "%z", &tm);
 +#endif
 +    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 (FixtureA *f, gconstpointer pData)
 +{
 +
 +    gchar buff[ISO8601_SIZE];
 +    gchar *time_str;
 +    Timespec t = { 0, 0 };
 +    gchar *end;
 +
 +    memset (buff, 0, sizeof buff);
 +
 +    end = gnc_timespec_to_iso8601_buff (t, NULL);
 +    g_assert (end == NULL);
 +
 +    end = gnc_timespec_to_iso8601_buff (f->ts0, buff);
 +    g_assert_cmpint (end - buff, ==, strlen (buff));
 +    time_str = format_timestring (f->ts0, f->off_zulu);
 +    g_assert_cmpstr (buff, ==, time_str);
 +    g_free (time_str);
 +
 +    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);
 +
 +
 +    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);
 +
 +    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);
 +
 +    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);
 +
 +    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);
 +}
 +/* gnc_timespec2dmy
 +void
 +gnc_timespec2dmy (Timespec t, int *day, int *month, int *year)// C: 1  Local: 0:0:0
 +*/
 +static void
 +test_gnc_timespec2dmy (FixtureA *f, gconstpointer pData)
 +{
 +    struct tm tm;
 +    int day, r_day, mo, r_mo, yr, r_yr;
 +
 +
 +    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
 +gnc_dmy2timespec_internal (int day, int month, int year, gboolean start_of_day)// Local: 2:0:0
 +*/
 +/* static void
 +test_gnc_dmy2timespec_internal (void)
 +{
 +}*/
 +/* gnc_dmy2timespec
 +Timespec
 +gnc_dmy2timespec (int day, int month, int year)// C: 8 in 5  Local: 1:0:0
 +*/
 +static void
 +test_gnc_dmy2timespec (FixtureB *f, gconstpointer pData)
 +{
 +    gchar *msg1 = "[qof_dmy2timespec()] Date computation error from Y-M-D 1257-7-2: Time value is outside the supported year range.";
 +    gint loglevel = G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL;
 +    gchar *logdomain = "qof.engine";
 +    TestErrorStruct check = {loglevel, logdomain, msg1, 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 (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);
 +        if (f->test[i].secs == INT64_MAX)
 +            /* We use INT64_MAX as invalid timespec.secs.
 +             * As we can't *add* to the max, we can ignore the tz offset in this case. */
 +            g_assert_cmpint (r_t.tv_sec, ==, INT64_MAX);
 +        else
 +            g_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs + offset);
 +    }
 +    g_log_set_default_handler (hdlr, 0);
 +}
 +/* 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 (FixtureB *f, gconstpointer pData)
 +{
 +    gchar *msg1 = "[qof_dmy2timespec_end()] Date computation error from Y-M-D 1257-7-2: Time value is outside the supported year range.";
 +    gint loglevel = G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL;
 +    gchar *logdomain = "qof.engine";
 +    TestErrorStruct check = {loglevel, logdomain, msg1, 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 (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);
 +        if (f->test[i].secs == INT64_MAX)
 +            /* We use INT64_MAX as invalid timespec.secs.
 +             * As we can't *add* to the max, we can ignore the tz offset in this case. */
 +            g_assert_cmpint (r_t.tv_sec, ==, INT64_MAX);
 +        else
 +            g_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs + offset);
 +    }
 +    g_log_set_default_handler (hdlr, 0);
 +}
 +
 +static GDateTime*
 +offset_adjust(GDateTime *gdt)
 +{
 +     Testfuncs *tf = gnc_date_load_funcs();
 +     GTimeZone *zone = tf->timezone_new_local();
 +     int interval = g_time_zone_find_interval(zone, G_TIME_TYPE_STANDARD,
 +					      g_date_time_to_unix(gdt));
 +     int offset = g_time_zone_get_offset(zone, interval) / 60;
 +     int off_hr = (offset / 60) + (offset % 60 ? (offset < 0 ? -1 : 1) : 0);
 +     int correction = off_hr < -10 ? -10 - off_hr : off_hr > 13 ? 13 - off_hr : 0;
 +     GDateTime* new_gdt = g_date_time_add_hours(gdt, correction);
 +     g_date_time_unref(gdt);
 +     g_slice_free(Testfuncs, tf);
 +     return new_gdt;
 +}
 +
 +/*gnc_dmy2timespec_neutral*/
 +static void
 +test_gnc_dmy2timespec_neutral (FixtureB *f, gconstpointer pData)
 +{
 +    gchar *msg1 = "[qof_dmy2timespec_neutral()] Date computation error from Y-M-D 1257-7-2: Time value is outside the supported year range.";
 +    gint loglevel = G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL;
 +    gchar *logdomain = "qof.engine";
 +    TestErrorStruct check = {loglevel, logdomain, msg1, 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 (int i = 0; i < sizeof(f->test)/sizeof(TimeMap); ++i)
 +    {
 +        Timespec r_t = gnc_dmy2timespec_neutral (f->test[i].day, f->test[i].mon,
 +                                             f->test[i].yr);
 +
 +        g_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs);
 +    }
 +    g_log_set_default_handler (hdlr, 0);
 +}
 +
 +/* gnc_timezone
 +long int
 +gnc_timezone (const struct tm *tm)// C: 5 in 2  Local: 2:0:0
 +*/
 +/* static void
 +test_gnc_timezone (void)
 +{
 +}*/
- /* timespecFromTime64
++/* timespecFromtime64
 +void
- timespecFromTime64( Timespec *ts, time64 t )// C: 22 in 11  Local: 0:0:0
++timespecFromtime64( Timespec *ts, time64 t )// C: 22 in 11  Local: 0:0:0
 +*/
- static void
- test_timespecFromTime64 (void)
- {
-      Timespec ts = {-9999, 0};
-      timespecFromTime64 (&ts, MINTIME - 1);
-      g_assert_cmpint (0, ==, ts.tv_sec);
-      timespecFromTime64 (&ts, MINTIME + 1);
-      g_assert_cmpint (MINTIME + 1, ==, ts.tv_sec);
-      timespecFromTime64 (&ts, MAXTIME + 1);
-      g_assert_cmpint (MAXTIME, ==, ts.tv_sec);
-      timespecFromTime64 (&ts, MAXTIME - 1);
-      g_assert_cmpint (MAXTIME - 1, ==, ts.tv_sec);
- }
++/* static void
++test_timespecFromtime64 (void)
++{
++}*/
 +/* timespec_now
 +Timespec
 +timespec_now()// C: 2 in 2  Local: 0:0:0
 +*/
 +/* static void
 +test_timespec_now (void)
 +{
 +}*/
 +/* timespecTotime64
 +time64
 +timespecTotime64 (Timespec ts)// C: 10 in 6  Local: 1:0:0
 +*/
 +/* static void
 +test_timespecTotime64 (void)
 +{
 +}*/
 +/* timespec_to_gdate
 +GDate timespec_to_gdate (Timespec ts)// C: 5 in 4  Local: 0:0:0
 +*/
 +static void
 +test_timespec_to_gdate (FixtureA *f, gconstpointer pData)
 +{
 +    GDate date1, date2;
 +    struct tm tm;
 +
 +    g_date_clear (&date2, 1);
 +
 +    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 (FixtureB *f, gconstpointer pData)
 +{
 +
 +    gchar *msg = "g_date_set_dmy: assertion 'g_date_valid_dmy (day, m, y)' failed";
 +    gint loglevel = G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL;
 +    gchar *logdomain = G_LOG_DOMAIN;
 +    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 (int i = 0; i < sizeof(f->test)/sizeof(TimeMap); ++i)
 +    {
 +        GDate gd, gd2;
 +        Timespec r_t;
 +        g_date_clear(&gd, 1);
 +        g_date_clear(&gd2, 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);
 +        if (f->test[i].secs < INT64_MAX)
 +        {
 +            gd2 = timespec_to_gdate(r_t);
 +            g_assert (g_date_compare (&gd2, &gd) == 0);
 +        }
 +    }
 +    g_log_set_default_handler (hdlr, 0);
 +}
 +/* gnc_tm_get_day_start
 +static void
 +gnc_tm_get_day_start (struct tm *tm, time64 time_val)// Local: 3:0:0
 +*/
 +/* static void
 +test_gnc_tm_get_day_start (void)
 +{
 +}*/
 +/* gnc_tm_get_day_end
 +static void
 +gnc_tm_get_day_end (struct tm *tm, time64 time_val)// Local: 3:0:0
 +*/
 +/* static void
 +test_gnc_tm_get_day_end (void)
 +{
 +}*/
 +/* gnc_time64_get_day_start
 +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 (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);
 +
 +    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);
 +
 +    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);
 +
 +    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);
 +
 +    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);
 +
 +    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);
 +
 + }
 +/* gnc_time64_get_day_end
 +time64
 +gnc_time64_get_day_end (time64 time_val)// C: 12 in 8  Local: 0:0:0
 +*/
 +static void
 +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);
 +
 +    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);
 +
 +    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);
 +
 +    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);
 +
 +    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);
 +
 +    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);
 +
 +}
 +/* gnc_tm_get_today_start
 +void
 +gnc_tm_get_today_start (struct tm *tm)// C: 3 in 3  Local: 0:0:0
 +*/
 +/* static void
 +test_gnc_tm_get_today_start (void)
 +{
 +}*/
 +// Not Used
 +/* gnc_tm_get_today_end
 +void
 +gnc_tm_get_today_end (struct tm *tm)// Local: 0:0:0
 +*/
 +/* gnc_time64_get_today_start
 +time64
 +gnc_time64_get_today_start (void)// C: 7 in 4  Local: 0:0:0
 +*/
 +/* static void
 +test_gnc_time64_get_today_start (void)
 +{
 +}*/
 +/* gnc_time64_get_today_end
 +time64
 +gnc_time64_get_today_end (void)// C: 8 in 5  Local: 0:0:0
 +*/
 +/* static void
 +test_gnc_time64_get_today_end (void)
 +{
 +}*/
 +/* gnc_dow_abbrev
 +void
 +gnc_dow_abbrev(gchar *buf, int buf_len, int dow)// C: 4 in 2  Local: 0:0:0
 +*/
 +/* static void
 +test_gnc_dow_abbrev (void)
 +{
 +}*/
 +/* timespec_boxed_copy_func
 +static gpointer
 +timespec_boxed_copy_func( gpointer in_timespec )// Local: 0:1:0
 +*/
 +/* static void
 +test_timespec_boxed_copy_func (void)
 +{
 +}*/
 +/* timespec_boxed_free_func
 +static void
 +timespec_boxed_free_func( gpointer in_timespec )// Local: 0:1:0
 +*/
 +/* static void
 +test_timespec_boxed_free_func (void)
 +{
 +}*/
 +// Not Used
 +/* timespec_get_type
 +GType
 +timespec_get_type( void )// Local: 0:0:0
 +*/
 +
 +
 +void
 +test_suite_gnc_date (void)
 +{
 +    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);
 +    GNC_TEST_ADD_FUNC (suitename, "gnc mktime normalization", test_gnc_mktime_normalization);
 +    GNC_TEST_ADD_FUNC (suitename, "gnc ctime", test_gnc_ctime);
 +    GNC_TEST_ADD_FUNC (suitename, "gnc time", test_gnc_time);
 +
 +    GNC_TEST_ADD_FUNC (suitename, "gnc date dateformat to string", test_gnc_date_dateformat_to_string);
 +    GNC_TEST_ADD_FUNC (suitename, "gnc date string to dateformat", test_gnc_date_string_to_dateformat);
 +    GNC_TEST_ADD_FUNC (suitename, "gnc date monthformat to string", test_gnc_date_monthformat_to_string);
 +    GNC_TEST_ADD_FUNC (suitename, "gnc date string to monthformat", test_gnc_date_string_to_monthformat);
 +    GNC_TEST_ADD_FUNC (suitename, "timespec normalize", test_timespec_normalize);
 +    GNC_TEST_ADD_FUNC (suitename, "timespec equal", test_timespec_equal);
 +    GNC_TEST_ADD_FUNC (suitename, "timespec cmp", test_timespec_cmp);
 +    GNC_TEST_ADD_FUNC (suitename, "timespec diff", test_timespec_diff);
 +    GNC_TEST_ADD_FUNC (suitename, "timespec abs", test_timespec_abs);
 +    GNC_TEST_ADD_FUNC (suitename, "timespecCanonicalDayTime", test_timespecCanonicalDayTime);
 +    GNC_TEST_ADD_FUNC (suitename, "date get last mday", test_gnc_date_get_last_mday);
 +    GNC_TEST_ADD_FUNC (suitename, "qof date format set", test_qof_date_format_set);
 +// GNC_TEST_ADD_FUNC (suitename, "qof date completion set", test_qof_date_completion_set);
 +    GNC_TEST_ADD_FUNC (suitename, "qof print date dmy buff", test_qof_print_date_dmy_buff);
 +    GNC_TEST_ADD_FUNC (suitename, "qof print date buff", test_qof_print_date_buff);
 +    GNC_TEST_ADD_FUNC (suitename, "qof print gdate", test_qof_print_gdate);
 +    GNC_TEST_ADD_FUNC (suitename, "qof print date", test_qof_print_date);
 +    GNC_TEST_ADD_FUNC (suitename, "gnc print date", test_gnc_print_date);
 +// GNC_TEST_ADD_FUNC (suitename, "floordiv", test_floordiv);
 +// GNC_TEST_ADD_FUNC (suitename, "qof scan date internal", test_qof_scan_date_internal);
 +    GNC_TEST_ADD_FUNC (suitename, "qof scan date", test_qof_scan_date);
 +// GNC_TEST_ADD_FUNC (suitename, "dateSeparator", test_dateSeparator);
 +// GNC_TEST_ADD_FUNC (suitename, "qof time format from utf8", test_qof_time_format_from_utf8);
 +// GNC_TEST_ADD_FUNC (suitename, "qof formatted time to utf8", test_qof_formatted_time_to_utf8);
 +// 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 (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 (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 (suitename, "gnc dmy2timespec Neutral", FixtureB, NULL, setup_neutral, test_gnc_dmy2timespec_neutral, NULL);
 +// GNC_TEST_ADD_FUNC (suitename, "gnc timezone", test_gnc_timezone);
-     GNC_TEST_ADD_FUNC (suitename, "timespecFromTime64", test_timespecFromTime64);
++// 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 (suitename, "timespec to gdate", FixtureA, NULL, setup, test_timespec_to_gdate, NULL);
 +    GNC_TEST_ADD (suitename, "gdate to timespec", FixtureB, NULL, setup_neutral, 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 (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);
 +// 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 0d8112bfefdcd13134d6a70042d48806b59475f9
Author: Rob Gowin <robgowin at gmail.com>
Date:   Thu Nov 23 10:50:16 2017 -0500

    Bug 790620 - Failed to create file “/usr/share/glib-2.0/schemas/gschemas.compiled.XY789Y”
    
    Changed install rule for gschema.compiled to use a target.

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
index a8651da..089a8ba 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -1,7 +1,5 @@
 # Post install actions go here.
 
-INSTALL(CODE "EXECUTE_PROCESS(COMMAND ${GLIB_COMPILE_SCHEMAS} ${CMAKE_INSTALL_PREFIX}/share/glib-2.0/schemas)")
-
 IF (APPLE)
   INSTALL(CODE "EXECUTE_PROCESS(
                 COMMAND /usr/bin/install_name_tool -add_rpath ${CMAKE_INSTALL_PREFIX}/lib
@@ -16,19 +14,25 @@ IF (${CMAKE_VERSION} VERSION_GREATER 3.1)
 ENDIF()
 
 SET(schema-targets business-gnome-gschema csv-exp-gschema csv-imp-gschema
-    generic-import-gschema gnome-gschema gnome-utils-gschema ofx-gschema qif-imp-gschema)
+    generic-import-gschema gnome-gschema gnome-utils-gschema qif-imp-gschema)
 
 IF (WITH_AQBANKING)
   LIST(APPEND schema-targets aqb-gschema)
 ENDIF (WITH_AQBANKING)
     
-SET(SCHEMA_DIRECTORY ${DATADIR_BUILD}/glib-2.0/schemas)
+IF (WITH_OFX)
+  LIST(APPEND schema-targets ofx-gschema)
+ENDIF (WITH_OFX)
+    
+SET(SCHEMA_BUILD_DIR ${DATADIR_BUILD}/glib-2.0/schemas)
 ADD_CUSTOM_COMMAND(
-  OUTPUT ${SCHEMA_DIRECTORY}/gschemas.compiled
-  COMMAND ${CMAKE_COMMAND_TMP} ${GLIB_COMPILE_SCHEMAS} ${SCHEMA_DIRECTORY}
+  OUTPUT ${SCHEMA_BUILD_DIR}/gschemas.compiled
+  COMMAND ${CMAKE_COMMAND_TMP} ${GLIB_COMPILE_SCHEMAS} ${SCHEMA_BUILD_DIR}
   DEPENDS ${schema-targets}
 )
 
-ADD_CUSTOM_TARGET(compiled-schemas ALL DEPENDS ${SCHEMA_DIRECTORY}/gschemas.compiled)
+ADD_CUSTOM_TARGET(compiled-schemas ALL DEPENDS ${SCHEMA_BUILD_DIR}/gschemas.compiled)
+
+INSTALL(FILES ${SCHEMA_BUILD_DIR}/gschemas.compiled DESTINATION ${DATADIR}/glib-2.0/schemas)
 
 SET_DIST_LIST(cmake_DIST CMakeLists.txt README_CMAKE.txt cmake_uninstall.cmake.in)

commit 1674eb0bd49d38ce9ddde059a59527d6f2400f8a
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Nov 21 13:30:17 2017 -0800

    Fix python build and test errors on Mac.

diff --git a/src/app-utils/CMakeLists.txt b/src/app-utils/CMakeLists.txt
index bda7847..e093b82 100644
--- a/src/app-utils/CMakeLists.txt
+++ b/src/app-utils/CMakeLists.txt
@@ -108,7 +108,7 @@ INSTALL(TARGETS gncmod-app-utils
 IF (WITH_PYTHON)
   ADD_LIBRARY (gncmod-app-utils-python ${app_utils_ALL_SOURCES} ${SWIG_APP_UTILS_PYTHON_C})
 
-  TARGET_LINK_LIBRARIES(gncmod-app-utils-python ${app_utils_ALL_LIBRARIES} ${PYTHON_LIBRARIES})
+  TARGET_LINK_LIBRARIES(gncmod-app-utils-python gncmod-app-utils ${app_utils_ALL_LIBRARIES} ${PYTHON_LIBRARIES})
 
   TARGET_INCLUDE_DIRECTORIES (gncmod-app-utils-python
     PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
diff --git a/src/optional/python-bindings/CMakeLists.txt b/src/optional/python-bindings/CMakeLists.txt
index 92ea1d8..e87c194 100644
--- a/src/optional/python-bindings/CMakeLists.txt
+++ b/src/optional/python-bindings/CMakeLists.txt
@@ -95,7 +95,7 @@ IF(WITH_PYTHON)
     DEPENDS ${SWIG_GNUCASH_CORE_C})
 
   ADD_CUSTOM_TARGET(gnucash-core-c-build ALL
-    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/lib/gnucash/_gnucash_core_c${CMAKE_SHARED_LIBRARY_SUFFIX} ${PYTHON_SYSCONFIG_BUILD}/gnucash
+    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/lib/gnucash/_gnucash_core_c${CMAKE_SHARED_MODULE_SUFFIX} ${PYTHON_SYSCONFIG_BUILD}/gnucash
     DEPENDS gnucash_core_c)
     
 ENDIF()
diff --git a/src/optional/python-bindings/sqlite3test.c b/src/optional/python-bindings/sqlite3test.c
index e22d74b..20d96ae 100644
--- a/src/optional/python-bindings/sqlite3test.c
+++ b/src/optional/python-bindings/sqlite3test.c
@@ -20,9 +20,10 @@
 
 #include "config.h"
 #include "qofsession.h"
-
+#define TESTFILE "/tmp/blah.gnucash"
 int main()
 {
+    const char* testurl = "sqlite3://" TESTFILE;
     qof_log_init();
     qof_init();
     gnc_module_system_init();
@@ -30,9 +31,10 @@ int main()
     gnc_engine_init(0, no_args);
 
     QofSession * s = qof_session_new();
-    qof_session_begin(s, "sqlite3:///tmp/blah.gnucash", 0, 1, 0);
+    qof_session_begin(s, testurl, 0, 1, 0);
     qof_session_load(s, NULL);
     qof_session_save(s, NULL);
     qof_session_end(s);
+    unlink(TESTFILE);
     return 0;
 }

commit af1bc45021aaa9c844a9e204ead402f155835e36
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Nov 19 09:36:44 2017 -0800

    A better way to handle MySQL's 0000-00-00 invalid date indicator.

diff --git a/src/backend/sql/gnc-backend-sql.c b/src/backend/sql/gnc-backend-sql.c
index e9dfc75..7d169d1 100644
--- a/src/backend/sql/gnc-backend-sql.c
+++ b/src/backend/sql/gnc-backend-sql.c
@@ -30,6 +30,7 @@
 #include "config.h"
 
 #include <errno.h>
+#include <stdint.h>
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <glib/gstdio.h>
@@ -1904,27 +1905,43 @@ load_timespec( const GncSqlBackend* be, GncSqlRow* row,
     }
     else
     {
+        /* MySQL's TIMESTAMP type is not compliant with the SQL
+         * standard in that it is valid only from 1970-01-01 00:00:01
+         * to 2038-01-15 23:59:59. Times outside that range are set to
+         * "0000-00-00 00:00:00"; depending on the libdbi version we
+         * may get either the string value or the time64 representing
+         * it. In either case leave the timespec at 0.
+         */
         if ( G_VALUE_HOLDS_INT64( val ) )
         {
-	    timespecFromTime64 (&ts, (time64)(g_value_get_int64 (val)));
-	    isOK = TRUE;
+            const time64 MINTIME = INT64_C(-62135596800);
+            const time64 MAXTIME = INT64_C(253402300799);
+            const time64 t = (time64)(g_value_get_int64 (val));
+            if (t >= MINTIME && t <= MAXTIME)
+            {
+                timespecFromTime64 (&ts, t);
+            }
+            isOK = TRUE;
 	}
 	else if (G_VALUE_HOLDS_STRING (val))
 	{
             const gchar* s = g_value_get_string( val );
             if ( s != NULL )
             {
-                gchar* buf;
-                buf = g_strdup_printf( "%c%c%c%c-%c%c-%c%c %c%c:%c%c:%c%c",
-                                       s[0], s[1], s[2], s[3],
-                                       s[4], s[5],
-                                       s[6], s[7],
-                                       s[8], s[9],
-                                       s[10], s[11],
-                                       s[12], s[13] );
-                ts = gnc_iso8601_to_timespec_gmt( buf );
-                g_free( buf );
-                isOK = TRUE;
+                 if (! g_str_has_prefix (s, "0000-00-00"))
+                 {
+                      gchar* buf;
+                      buf = g_strdup_printf( "%c%c%c%c-%c%c-%c%c %c%c:%c%c:%c%c",
+                                             s[0], s[1], s[2], s[3],
+                                             s[4], s[5],
+                                             s[6], s[7],
+                                             s[8], s[9],
+                                             s[10], s[11],
+                                             s[12], s[13] );
+                      ts = gnc_iso8601_to_timespec_gmt( buf );
+                      g_free( buf );
+                 }
+                 isOK = TRUE;
             }
         }
         else
diff --git a/src/libqof/qof/gnc-date.c b/src/libqof/qof/gnc-date.c
index 3af9be9..1c652de 100644
--- a/src/libqof/qof/gnc-date.c
+++ b/src/libqof/qof/gnc-date.c
@@ -73,17 +73,6 @@
 #  define GNC_T_FMT "%r"
 #endif
 
-/* t < MINTIME is probably from a bad conversion from t 0 to
- * 0000-00-00, so restore it to the Unix Epoch. t anywhere near
- * MAXTIME is obviously an error, but we don't want to crash with a
- * bad date-time so just clamp it to MAXTIME.
- */
-static inline time64
-clamp_time(time64 t)
-{
-    return  t < MINTIME ? 0 : t > MAXTIME ? MAXTIME : t;
-}
-
 const char *gnc_default_strftime_date_format =
 #ifdef G_OS_WIN32
     /* The default date format for use with strftime in Win32. */
@@ -152,7 +141,7 @@ 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 (clamp_time (time));
+    GDateTime *gdt = g_date_time_new_from_unix_utc (time);
     if (gdt)
 	gdt = gnc_g_date_time_adjust_for_dst (gdt, tz);
     return gdt;
@@ -260,7 +249,7 @@ struct tm*
 gnc_localtime_r (const time64 *secs, struct tm* time)
 {
      guint index = 0;
-     GDateTime *gdt = gnc_g_date_time_new_from_unix_local (clamp_time (*secs));
+     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);
@@ -282,7 +271,7 @@ struct tm*
 gnc_gmtime (const time64 *secs)
 {
      struct tm *time;
-     GDateTime *gdt = g_date_time_new_from_unix_utc (clamp_time (*secs));
+     GDateTime *gdt = g_date_time_new_from_unix_utc (*secs);
      g_return_val_if_fail (gdt != NULL, NULL);
      time = g_slice_alloc0 (sizeof (struct tm));
      gnc_g_date_time_fill_struct_tm (gdt, time);
@@ -400,10 +389,10 @@ gnc_timegm (struct tm* time)
 gchar*
 gnc_ctime (const time64 *secs)
 {
-    GDateTime *gdt = gnc_g_date_time_new_from_unix_local (clamp_time (*secs));
-    gchar *string = g_date_time_format (gdt, "%a %b %e %H:%M:%S %Y");
-    g_date_time_unref (gdt);
-    return string;
+     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;
 }
 
 time64
@@ -898,7 +887,7 @@ size_t
 qof_print_date_buff (char * buff, size_t len, time64 t)
 {
     struct tm theTime;
-    time64 bt = clamp_time (t);
+    time64 bt = t;
     size_t actual;
     if (!buff) return 0 ;
     if (!gnc_localtime_r(&bt, &theTime))
@@ -1646,7 +1635,7 @@ gnc_timezone (const struct tm *tm)
 void
 timespecFromTime64 ( Timespec *ts, time64 t )
 {
-    ts->tv_sec = clamp_time (t);
+    ts->tv_sec = t;
     ts->tv_nsec = 0;
 }
 
diff --git a/src/libqof/qof/gnc-date.h b/src/libqof/qof/gnc-date.h
index ad5bcf0..acdbe65 100644
--- a/src/libqof/qof/gnc-date.h
+++ b/src/libqof/qof/gnc-date.h
@@ -70,7 +70,7 @@
 
 #include <glib-object.h>
 #include <time.h>
-#include <stdint.h>
+
 /**
  * Many systems, including Microsoft Windows and BSD-derived Unixes
  * like Darwin, are retaining the int-32 typedef for time_t. Since
@@ -100,8 +100,7 @@ extern const char *gnc_default_strftime_date_format;
 
 /** The maximum length of a string created by the date printers */
 #define MAX_DATE_LENGTH 34
-#define MAXTIME INT64_C(253402300799)
-#define MINTIME INT64_C(-62135596800)
+
 /** Constants *******************************************************/
 /** \brief UTC date format string.
 
diff --git a/src/libqof/qof/test/test-gnc-date.c b/src/libqof/qof/test/test-gnc-date.c
index c54d2f0..acd48f9 100644
--- a/src/libqof/qof/test/test-gnc-date.c
+++ b/src/libqof/qof/test/test-gnc-date.c
@@ -58,17 +58,6 @@ typedef struct
 static _GncDateTime gncdt;
 extern void _gnc_date_time_init (_GncDateTime *);
 
-/* t < MINTIME is probably from a bad conversion from t 0 to
- * 0000-00-00, so restore it to the Unix Epoch. t anywhere near
- * MAXTIME is obviously an error, but we don't want to crash with a
- * bad date-time so just clamp it to MAXTIME.
- */
-static inline time64
-clamp_time(time64 t)
-{
-    return  t < MINTIME ? 0 : t > MAXTIME ? MAXTIME : t;
-}
-
 /* gnc_localtime just creates a tm on the heap and calls
  * gnc_localtime_r with it, so this suffices to test both.
  */
@@ -81,6 +70,18 @@ test_gnc_localtime (void)
                       // difference between g_date_time and tm->tm_wday)
                      };
     guint ind;
+#if defined(__clang__) && __clang_major__ < 6
+#define _func "struct tm *gnc_localtime_r(const time64 *, struct tm *)"
+#else
+#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++)
     {
@@ -111,6 +112,8 @@ 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
@@ -126,23 +129,35 @@ test_gnc_gmtime (void)
         { 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 },
-        { 59, 59, 23, 31, 11, 8099, 5, 365, 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 },
 #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 },
-        { 59, 50, 23, 31, 11, 8099, 5, 365, 0 },
+        { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
         { 6, 47, 16, 7, 3, 107, 6, 97, 0 },
 #endif
     };
     guint ind;
+#if defined(__clang__) && __clang_major__ < 6
+#define _func "struct tm *gnc_gmtime(const time64 *)"
+#else
+#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]);
-        GDateTime *gdt = g_date_time_new_from_unix_utc (clamp_time (secs[ind]));
+        GDateTime *gdt = g_date_time_new_from_unix_utc (secs[ind]);
         if (gdt == NULL)
         {
             g_assert (time == NULL);
@@ -163,6 +178,8 @@ test_gnc_gmtime (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
@@ -2020,23 +2037,14 @@ gnc_timezone (const struct tm *tm)// C: 5 in 2  Local: 2:0:0
 test_gnc_timezone (void)
 {
 }*/
-/* timespecFromTime64
+/* timespecFromtime64
 void
-timespecFromTime64( Timespec *ts, time64 t )// C: 22 in 11  Local: 0:0:0
+timespecFromtime64( Timespec *ts, time64 t )// C: 22 in 11  Local: 0:0:0
 */
-static void
-test_timespecFromTime64 (void)
-{
-     Timespec ts = {-9999, 0};
-     timespecFromTime64 (&ts, MINTIME - 1);
-     g_assert_cmpint (0, ==, ts.tv_sec);
-     timespecFromTime64 (&ts, MINTIME + 1);
-     g_assert_cmpint (MINTIME + 1, ==, ts.tv_sec);
-     timespecFromTime64 (&ts, MAXTIME + 1);
-     g_assert_cmpint (MAXTIME, ==, ts.tv_sec);
-     timespecFromTime64 (&ts, MAXTIME - 1);
-     g_assert_cmpint (MAXTIME - 1, ==, ts.tv_sec);
-}
+/* static void
+test_timespecFromtime64 (void)
+{
+}*/
 /* timespec_now
 Timespec
 timespec_now()// C: 2 in 2  Local: 0:0:0
@@ -2466,7 +2474,7 @@ test_suite_gnc_date (void)
     GNC_TEST_ADD_FUNC (suitename, "gnc dmy2timespec end", test_gnc_dmy2timespec_end);
     GNC_TEST_ADD_FUNC (suitename, "gnc dmy2timespec Neutral", test_gnc_dmy2timespec_neutral);
 // GNC_TEST_ADD_FUNC (suitename, "gnc timezone", test_gnc_timezone);
-    GNC_TEST_ADD_FUNC (suitename, "timespecFromTime64", test_timespecFromTime64);
+// 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);

commit 23f25d74d99c4f2b1b2371e1824fde93ef8127b4
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Nov 19 09:35:08 2017 -0800

    Don't try to unref a NULL GDateTime*.

diff --git a/src/libqof/qof/gnc-date.c b/src/libqof/qof/gnc-date.c
index d0ded97..3af9be9 100644
--- a/src/libqof/qof/gnc-date.c
+++ b/src/libqof/qof/gnc-date.c
@@ -1503,8 +1503,8 @@ gnc_iso8601_to_timespec_gmt(const char *str)
     {
 	time.tv_sec = g_date_time_to_unix (gdt);
 	time.tv_nsec = g_date_time_get_microsecond (gdt) * 1000;
+        g_date_time_unref (gdt);
     }
-    g_date_time_unref (gdt);
     return time;
 }
 

commit ff76db28f5d6de298df29e390c59b2a7bddf6dfa
Author: fell <frank.h.ellenberger at gmail.com>
Date:   Wed Nov 15 03:33:57 2017 +0100

    Add po/glossary/gnc-glossary.pot to .gitignore

diff --git a/.gitignore b/.gitignore
index 005f994..86b62c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -76,6 +76,7 @@ po/POTFILES
 po/POTFILES.in
 po/gnucash.pot
 po/stamp-it
+po/glossary/gnc-glossary.pot
 py-compile
 src/app-utils/gnucash
 src/app-utils/sw_app_utils.py

commit 742064ee8752831003944fea62d01dfdd86bc4bd
Author: fell <frank.h.ellenberger at gmail.com>
Date:   Wed Nov 15 00:36:41 2017 +0100

    Fix a few encodings and Content-* tags in glossary

diff --git a/po/glossary/ca.po b/po/glossary/ca.po
index ec640db..4d22b47 100644
--- a/po/glossary/ca.po
+++ b/po/glossary/ca.po
@@ -13,7 +13,7 @@ msgstr ""
 "Language: ca\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8-bit\n"
+"Content-Transfer-Encoding: 8bit\n"
 
 #. "English Definition (Dear translator: This file will never be visible to the user! It should only serve as a tool for you, the translator. Nothing more.)"
 msgid "Term (Dear translator: This file will never be visible to the user!)"
diff --git a/po/glossary/el.po b/po/glossary/el.po
index c82a3e5..0438419 100644
--- a/po/glossary/el.po
+++ b/po/glossary/el.po
@@ -11,7 +11,7 @@ msgstr ""
 "Language-Team: Greek <nls at tux.hellug.gr>\n"
 "Language: el\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=iso-8859-7\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
 #. "English Definition (Dear translator: This file will never be visible to the user! It should only serve as a tool for you, the translator. Nothing more.)"
@@ -20,37 +20,37 @@ msgstr ""
 
 #. "A detailed record of money spent and received"
 msgid "account"
-msgstr "ëïãáñéáóìüò"
+msgstr "λογαριασμός"
 
 #. "-"
 #, fuzzy
 msgid "account code"
-msgstr "Ëïãáñéáóìüò %d"
+msgstr "Λογαριασμός %d"
 
 #. "the tree view of all accounts"
 #, fuzzy
 msgid "account hierarchy"
-msgstr "éåñáñ÷ßá"
+msgstr "ιεραρχία"
 
 #. "-"
 #, fuzzy
 msgid "account name"
-msgstr "¼íïìá _ëïãáñéáóìïý:"
+msgstr "Όνομα _λογαριασμού:"
 
 #. "The left side of the balance sheet in T account form shows the application of funds in form of assets. Because it contains only assets use assets directly. Complement: Passive. See also: Report Form"
 #, fuzzy
 msgid "account type: Active"
-msgstr "Åßäïò Ðáñáóêçíßïõ:"
+msgstr "Είδος Παρασκηνίου:"
 
 #. "A thing, esp. owned by a person or company, that has value and can be used or sold to pay debts. Dependent on the context you might use 'account type: Active' instead."
 #, fuzzy
 msgid "account type: Asset"
-msgstr "Åßäïò Ðáñáóêçíßïõ:"
+msgstr "Είδος Παρασκηνίου:"
 
 #. "in fact: 'Active & Passive', group aka 'Balance Sheet accounts'; complement of 'Profit & Loss'"
 #, fuzzy
 msgid "account type: Assets & Liabilities"
-msgstr "Åßäïò Ðáñáóêçíßïõ:"
+msgstr "Είδος Παρασκηνίου:"
 
 #. "(esp. US) (Brit = current account) a bank account from which money can be withdrawn without previous notice"
 msgid "account type: checking"
@@ -87,12 +87,12 @@ msgstr ""
 #. "The right side of the balance sheet in T account form shows the source of funds and contains equity & liability. While not common in english, most languages would translate 'equity & liability' with 'passive'. Complement: Active. See also: Report Form Implementation: https://bugzilla.gnome.org/show_bug.cgi?id=421766"
 #, fuzzy
 msgid "account type: Passive"
-msgstr "Åßäïò Ðáñáóêçíßïõ:"
+msgstr "Είδος Παρασκηνίου:"
 
 #. "Group of accounts tracking your success, complement of 'Assets & Liabilities'"
 #, fuzzy
 msgid "account type: Profit & Loss"
-msgstr "Åßäïò Ðáñáóêçíßïõ:"
+msgstr "Είδος Παρασκηνίου:"
 
 #. "1. (US) any type of account that earns interest 2. (Brit) any type of bank account that earns a higher level of interest than a current account or deposit account"
 msgid "account type: saving"
@@ -101,17 +101,17 @@ msgstr ""
 #. "-"
 #, fuzzy
 msgid "account type: Stock"
-msgstr "Åßäïò Ðáñáóêçíßïõ:"
+msgstr "Είδος Παρασκηνίου:"
 
 #. "This account type (new in gnucash-2.4.0) is used when exchanging or trading amounts from one currency into another"
 #, fuzzy
 msgid "account type: trading"
-msgstr "Åßäïò Ðáñáóêçíßïõ:"
+msgstr "Είδος Παρασκηνίου:"
 
 #. "-"
 #, fuzzy
 msgid "account: parent account"
-msgstr "ÄéáöáíÝò ðáñáóêÞíéï"
+msgstr "Διαφανές παρασκήνιο"
 
 #. "-"
 msgid "account: subaccount"
@@ -128,88 +128,88 @@ msgstr ""
 #. "Automated teller machine"
 #, fuzzy
 msgid "action: ATM"
-msgstr "Ôïðïèåóßá: "
+msgstr "Τοποθεσία: "
 
 #. "Transaction was an auto deposit"
 #, fuzzy
 msgid "action: autoDep"
-msgstr "ÂÜóç åíåñãåéþí"
+msgstr "Βάση ενεργειών"
 
 #. "-"
 #, fuzzy
 msgid "action: buy"
-msgstr "Ôïðïèåóßá: "
+msgstr "Τοποθεσία: "
 
 #. "-"
 #, fuzzy
 msgid "action: deposit"
-msgstr "Óçìåßï åéóáãùãÞò"
+msgstr "Σημείο εισαγωγής"
 
 #. "When people can automatically deduct money straight from your account. The reverse of Direct Deposit."
 #, fuzzy
 msgid "action: direct debit"
-msgstr "Áíýðáñêôç óõíÜñôçóç"
+msgstr "Ανύπαρκτη συνάρτηση"
 
 #. "transaction is a distribution (???)"
 #, fuzzy
 msgid "action: dist"
-msgstr "Ëßóôá Åéêïíéäßùí"
+msgstr "Λίστα Εικονιδίων"
 
 #. "transaction is a dividend"
 #, fuzzy
 msgid "action: div"
-msgstr "Ôïðïèåóßá: "
+msgstr "Τοποθεσία: "
 
 #. "-"
 #, fuzzy
 msgid "action: fee"
-msgstr "Ôïðïèåóßá: "
+msgstr "Τοποθεσία: "
 
 #. "transaction comes from interest"
 #, fuzzy
 msgid "action: int"
-msgstr "Ôïðïèåóßá: "
+msgstr "Τοποθεσία: "
 
 # # FIX check!
 #. "-"
 #, fuzzy
 msgid "action: loan"
-msgstr "ÍÞóïò ôïõ Áóåíôéüí"
+msgstr "Νήσος του Ασεντιόν"
 
 #. "see: payment 1."
 #, fuzzy
 msgid "action: payment"
-msgstr "Ï_íüìáôá ÓõíáñôÞóåùí"
+msgstr "Ο_νόματα Συναρτήσεων"
 
 #. "Point of sale"
 #, fuzzy
 msgid "action: POS"
-msgstr "Ôïðïèåóßá: "
+msgstr "Τοποθεσία: "
 
 #. "-"
 #, fuzzy
 msgid "action: rebate"
-msgstr "AëëáãÞ ôìÞìáôïò"
+msgstr "Aλλαγή τμήματος"
 
 #. "-"
 #, fuzzy
 msgid "action: sell"
-msgstr "Ôïðïèåóßá: "
+msgstr "Τοποθεσία: "
 
 #. "-"
 #, fuzzy
 msgid "action: Teller"
-msgstr "ÅðéëïãÝáò ÓõíáñôÞóåùí"
+msgstr "Επιλογέας Συναρτήσεων"
 
 #. "see: transfer 2. (=credit transfer)"
 #, fuzzy
 msgid "action: transfer"
-msgstr "ÂÜóç åíåñãåéþí"
+msgstr "Βάση ενεργειών"
 
 #. "-"
 #, fuzzy
 msgid "action: wire"
-msgstr "¿ñá äçìéïõñãßáò"
+msgstr "Ώρα δημιουργίας"
 
 #. "-"
 msgid "action: withdraw"
@@ -218,12 +218,12 @@ msgstr ""
 #. "A sum of money"
 #, fuzzy
 msgid "amount"
-msgstr "ìÞíáò"
+msgstr "μήνας"
 
 #. "The result of adding several amounts together and then dividing this total by the number of amounts"
 #, fuzzy
 msgid "average"
-msgstr "ÌÝóïò"
+msgstr "Μέσος"
 
 #. "The amount of money that is in one's account"
 msgid "balance (noun)"
@@ -232,17 +232,17 @@ msgstr ""
 #. "A written record of money received and paid out, showing the difference between the two total amounts"
 #, fuzzy
 msgid "balance sheet"
-msgstr "åíåñãü öýëëï"
+msgstr "ενεργό φύλλο"
 
 #. "To arrange for income and spending to be equal"
 #, fuzzy
 msgid "balance, to"
-msgstr "Éóïññïðßá"
+msgstr "Ισορροπία"
 
 #. "-"
 #, fuzzy
 msgid "bank"
-msgstr "Âáèìüò"
+msgstr "Βαθμός"
 
 #. "A written statement of money owed for goods or services supplied. In Gnucash, a 'bill' is a statement that we received (from a vendor), whereas an 'invoice' is one that we sent out (to a customer)."
 msgid "bill"
@@ -276,29 +276,29 @@ msgstr ""
 #. "as Menu Item: Headline for features that are related to small business accounting"
 #, fuzzy
 msgid "business (noun)"
-msgstr "ÌåôáöïñÜ"
+msgstr "Μεταφορά"
 
 #. "Profits made from the sale of investments or property"
 #, fuzzy
 msgid "capital gains"
-msgstr "Ìåñéêþò ðáãùìÝíï ÷éüíé"
+msgstr "Μερικώς παγωμένο χιόνι"
 
 #. "Distinguishing the uppercase and lowercase letters"
 #, fuzzy
 msgid "case sensitive"
-msgstr "ÐåæÜ/êåöáëáßá äéáöÝñïõí"
+msgstr "Πεζά/κεφαλαία διαφέρουν"
 
 #
 #. "Money in coins or notes"
 #, fuzzy
 msgid "cash"
-msgstr "Áðïññßìáôá"
+msgstr "Απορρίματα"
 
 #
 #. "(esp. US) (= cheque) A special printed form on which one writes an order to a bank to pay a sum of money from one's account to another person"
 #, fuzzy
 msgid "check"
-msgstr "¸ëåã÷ïò"
+msgstr "Έλεγχος"
 
 #. "To repair unbalanced transactions and orphan splits in an account tree. Any transactions that have debits != credits will get a balancing split added (pointing to a special new account called 'Imbalance'). Any splits that do not have accounts are put into another special account called 'Orphan'. Formerly known as 'to scrub'."
 msgid "check and repair, to"
@@ -307,13 +307,13 @@ msgstr ""
 #. "To end an application's relationship with an open file so that the application will no longer be able to access the file without opening it again. "
 #, fuzzy
 msgid "close, to"
-msgstr "Êëåßóéìï êáôáãñáöþí"
+msgstr "Κλείσιμο καταγραφών"
 
 #
 #. "An article that is bought and sold. The most general term of what an account keeps track of, e.g. a currency or a stock."
 #, fuzzy
 msgid "commodity"
-msgstr "ÄéÜðñáîç"
+msgstr "Διάπραξη"
 
 #. "e.g. NASDAQ"
 msgid "commodity listing"
@@ -322,7 +322,7 @@ msgstr ""
 #. "the smallest amount of a commodity that's traded (e.g. 1/100 for USD, 1 for most stocks)"
 #, fuzzy
 msgid "commodity option: fraction"
-msgstr "Üäåéá èÝóç óôç âÜóç"
+msgstr "άδεια θέση στη βάση"
 
 #. "e.g. USD, DEM"
 msgid "commodity option: Symbol"
@@ -331,7 +331,7 @@ msgstr ""
 #. "interest which is earned on both the initial deposit and on any interest that has already been earned but left on deposit."
 #, fuzzy
 msgid "compound interests"
-msgstr "Äßêôõï"
+msgstr "Δίκτυο"
 
 #. "(a) A sum of money paid into an account. (b) A record of such a payment. (c) The state of having money in one's bank account."
 msgid "Credit (column in register)"
@@ -339,46 +339,46 @@ msgstr ""
 
 #. "-"
 msgid "Credit Card"
-msgstr "ÐéóôùôéêÞ ÊÜñôá"
+msgstr "Πιστωτική Κάρτα"
 
 #. "A transfer of money direct from one bank account to another, without using a cheque"
 #, fuzzy
 msgid "credit transfer"
-msgstr "Ï ÷ñÞóôçò äéÝêïøå ôçí ìåôáöïñÜ"
+msgstr "Ο χρήστης διέκοψε την μεταφορά"
 
 #. "A document that you give to a client that says you owe money to the client, i.e. the opposite of an invoice"
 #, fuzzy
 msgid "credit note"
-msgstr "Ï ÷ñÞóôçò äéÝêïøå ôçí ìåôáöïñÜ"
+msgstr "Ο χρήστης διέκοψε την μεταφορά"
 
 #. "The system of money used in a country"
 #, fuzzy
 msgid "currency"
-msgstr "_Íüìéóìá"
+msgstr "_Νόμισμα"
 
 # Translation of "custom" sucks!  ("kata paraggelia"???  nah!)
 #. "Custom print format (i.e. according to the user's wishes) as opposed to a template choice."
 msgid "Custom"
-msgstr "ÐñïóáñìïóìÝíï"
+msgstr "Προσαρμοσμένο"
 
 #. "The backend where the data is stored."
 msgid "database"
-msgstr "âÜóç äåäïìÝíùí"
+msgstr "βάση δεδομένων"
 
 #
 #. "A specific numbered day of the month"
 msgid "Date"
-msgstr "Çì/íßá"
+msgstr "Ημ/νία"
 
 #. "DD/MM/YY or MM/DD/YY or something else"
 #, fuzzy
 msgid "date format"
-msgstr "ÌïñöÞ Çì/íßáò"
+msgstr "Μορφή Ημ/νίας"
 
 #. "A range in time that is delimited by two distinct dates."
 #, fuzzy
 msgid "date range"
-msgstr "çìåñïìçíßá áëëáãÞò"
+msgstr "ημερομηνία αλλαγής"
 
 #. "(a) A written note in an account of a sum owed or paid out. (b) A sum withdrawn from an account."
 msgid "Debit (column in register)"
@@ -387,7 +387,7 @@ msgstr ""
 #. "Each option has a default setting that it is shipped with, until the user changes the setting."
 #, fuzzy
 msgid "default"
-msgstr "Åî' ïñéóìïý"
+msgstr "Εξ' ορισμού"
 
 #. "see credit"
 msgid "deposit (in the reconcile dialog)"
@@ -396,32 +396,32 @@ msgstr ""
 #. "The process of something becoming less valuable"
 #, fuzzy
 msgid "depreciation"
-msgstr "¸íôïíç áôìïóöáéñéêÞ êáôáêñÞìíéóç"
+msgstr "Έντονη ατμοσφαιρική κατακρήμνιση"
 
 #. "1. One textfield per transaction. The text in it should describe what the transaction was about. A short descriptive phrase (up to 40 chars) 2. One textfield per account. It is intended to be a longer, 1-5 sentence description of what this account is all about."
 #, fuzzy
 msgid "Description (column in register)"
-msgstr "Ç ðåñéãñáöÞ ðåñéÝ÷åé"
+msgstr "Η περιγραφή περιέχει"
 
 #. "Reductions to a basic price of goods or services. Your language might distinguish between discounts dealing with payments (billing terms) and others (invoice)."
 #, fuzzy
 msgid "discount"
-msgstr "ëïãáñéáóìüò"
+msgstr "λογαριασμός"
 
 #. "Important Buzzword :)"
 #, fuzzy
 msgid "double entry"
-msgstr "äéðëü"
+msgstr "διπλό"
 
 #. "a person who works for somebody or a company in return for wages"
 #, fuzzy
 msgid "employee"
-msgstr "Ðñüôõðï"
+msgstr "Πρότυπο"
 
 #. "1. The money value of a property after all charges on it have been paid. Equity isn't debt, it's a representation of long-term capital (So combining it with liability isn't really very meaningful, except in the balance sheet. 2. (a) The value of the shares issued by  a company. (b) Ordinary stocks and shares that carry no fixed interest."
 #, fuzzy
 msgid "equity"
-msgstr "ÁóöÜëåéá"
+msgstr "Ασφάλεια"
 
 #. "Report that ... FIXME: Add description."
 msgid "equity statement"
@@ -430,26 +430,26 @@ msgstr ""
 #. "A trusted third party that holds a payment or deposit until a transaction is completed. In the US, many mortgage companies set up an escrow account when you get a mortgage.  You pay into the account every month and they disburse amounts out of the escrow to pay for hazard insurance and property taxes. So they are holding funds 'in escrow' to complete the transactions (paying insurance and taxes)."
 #, fuzzy
 msgid "escrow (account)"
-msgstr "ðñïóùñéíÜ"
+msgstr "προσωρινά"
 
 #. "The relation in value between the money used in different countries"
 #, fuzzy
 msgid "exchange rate"
-msgstr "ÅíáëëáãÞ Êåöáëáßá-ÌéêñÜ"
+msgstr "Εναλλαγή Κεφαλαία-Μικρά"
 
 #. "in the account creation dialog??"
 #, fuzzy
 msgid "field"
-msgstr "Ðåäßï"
+msgstr "Πεδίο"
 
 #. "Any piece of information (text, graphics, executable) put together and given a name. All the information you have on the hard drive is arranged as a collection of  files."
 msgid "file"
-msgstr "áñ÷åßï"
+msgstr "αρχείο"
 
 #. "-"
 #, fuzzy
 msgid "file type"
-msgstr "Ôýðïò áñ÷åßïõ:"
+msgstr "Τύπος αρχείου:"
 
 #. "-"
 msgid "financial calculator: interest rate"
@@ -462,18 +462,18 @@ msgstr ""
 #. "An increase in wealth; profit; advantage (See also: capital gains)"
 #, fuzzy
 msgid "gain"
-msgstr "Âñï÷Þ"
+msgstr "Βροχή"
 
 #. "Name of an automatically created account to get imbalanced transactions back in balance"
 #, fuzzy
 msgid "imbalance"
-msgstr "Éóïññïðßá"
+msgstr "Ισορροπία"
 
 #
 #. "Process of extracting data from a non-Gnucash format into a Gnucash file. E.g. QIF Import."
 #, fuzzy
 msgid "import"
-msgstr "ÅéóáãùãÞ"
+msgstr "Εισαγωγή"
 
 #. "Report that ... FIXME: add description. This report used to be called the 'Profit & Loss', but it was renamed on 2004-07-13."
 msgid "income statement"
@@ -482,12 +482,12 @@ msgstr ""
 #. "Money charged for borrowing money, or paid to somebody who invests money"
 #, fuzzy
 msgid "interest"
-msgstr "Äßêôõï"
+msgstr "Δίκτυο"
 
 #. "A list of goods sold or services provided together with the prices charged; see also: a bill. In Gnucash, an 'invoice' is a statement that we sent out (to a customer), whereas a 'bill' is one that we received (from a vendor)."
 #, fuzzy
 msgid "invoice"
-msgstr "áñ÷Üñéïò"
+msgstr "αρχάριος"
 
 #. "In business accounting: Jobs are a mechanism by which you can group multiple invoices or bills that belong to the same customer or vendor. The job describes a (larger) piece of work or a task undertaken on order, for which one or many invoices or bills will be issued."
 msgid "job"
@@ -497,7 +497,7 @@ msgstr ""
 #. "A book in which a bank, business firm, etc. records its financial accounts"
 #, fuzzy
 msgid "ledger"
-msgstr "Åðéêåöáëßäá"
+msgstr "Επικεφαλίδα"
 
 #. "The heading for the right side of the balance sheet. See also: Equity."
 msgid "liabilities/equity"
@@ -506,51 +506,51 @@ msgstr ""
 #. "A sum of money that is lent (by a bank)"
 #, fuzzy
 msgid "loan"
-msgstr "ÊïñåÜôéêá"
+msgstr "Κορεάτικα"
 
 #
 #. "The money lost in business activity"
 #, fuzzy
 msgid "loss"
-msgstr "Êëåßóéìï"
+msgstr "Κλείσιμο"
 
 #. "name of an automatically created account"
 #, fuzzy
 msgid "Lost Accounts"
-msgstr "Ëïãáñéáóìïß"
+msgstr "Λογαριασμοί"
 
 #
 #. "A particular collection of items that were bought in one transaction. A lot is typically formed when the item is bought, and is closed when the item is sold out. Needed e.g. for U.S. tax purposes."
 #, fuzzy
 msgid "Lot"
-msgstr "Ðñoò"
+msgstr "Πρoς"
 
 #
 #. "Combine two books into one (see book)."
 #, fuzzy
 msgid "merge, to"
-msgstr "ÁíáíÝùóç"
+msgstr "Ανανέωση"
 
 #. "The thing that the scatter plot uses to mark each data point"
 #, fuzzy
 msgid "marker"
-msgstr "Ìåãáëýôåñï"
+msgstr "Μεγαλύτερο"
 
 #. "1. Some text annotation, but this meaning isn't used inside gnucash. 2. In the Customer summary report: The ratio of profit vs. sales, i.e. the profit amount divided by the sales amount, shown in percent."
 #, fuzzy
 msgid "markup"
-msgstr "Ìåãáëýôåñï"
+msgstr "Μεγαλύτερο"
 
 #
 #. "The way how more than one window is displayed in GnuCash at the same time. MDI = Multiple Document Interface."
 #, fuzzy
 msgid "MDI modus"
-msgstr "Ñõèìßóåéò MDI"
+msgstr "Ρυθμίσεις MDI"
 
 #. "One textfield per split that should help you remember what this split was about."
 #, fuzzy
 msgid "Memo"
-msgstr "ÌíÞìç"
+msgstr "Μνήμη"
 
 #. "(a) An agreement by which money is lent by a bank for buying a house or other property, the property being the security. (b) A sum of money lent in this way."
 msgid "Mortgage"
@@ -563,28 +563,28 @@ msgstr ""
 #. "(of money) remaining when nothing more is to be taken away"
 #, fuzzy
 msgid "net"
-msgstr "åðüìåíï"
+msgstr "επόμενο"
 
 #. "net total of all assets"
 #, fuzzy
 msgid "net assets"
-msgstr "Óýíïëá ôïðïèåóéþí"
+msgstr "Σύνολα τοποθεσιών"
 
 #
 #. "The total income minus the total expenses of a given time period."
 #, fuzzy
 msgid "net profit"
-msgstr "ÁíÜèåóç ðñïôåñáéüôçôáò"
+msgstr "Ανάθεση προτεραιότητας"
 
 #. "Your net worth is your assets minus your liabilities. If your accounts are balanced, your net worth should equal your equity plus your net profit."
 #, fuzzy
 msgid "net worth"
-msgstr "¸íáò ÌÞíáò"
+msgstr "Ένας Μήνας"
 
 #. "One textfield per transaction that can hold explanatory text about the transaction."
 #, fuzzy
 msgid "notes (register)"
-msgstr "Äåí Þôáí äõíáôÞ ç åããñáöÞ óôï OAF"
+msgstr "Δεν ήταν δυνατή η εγγραφή στο OAF"
 
 #. "Abbreviation for: number; Field in a transaction. If this transaction was done by check, then the check number should be noted in this field."
 msgid "Num (column in register)"
@@ -593,17 +593,17 @@ msgstr ""
 #. "to make accessible"
 #, fuzzy
 msgid "open, to"
-msgstr "¶íïéãìá áñ÷åßïõ êáôáãñáöþí"
+msgstr "Άνοιγμα αρχείου καταγραφών"
 
 #. "If an account starts with a non-zero balance, then this amount is called the opening balance."
 #, fuzzy
 msgid "opening balance"
-msgstr "ÓöÜëìá áíïßãìáôïò áñ÷åßïõ"
+msgstr "Σφάλμα ανοίγματος αρχείου"
 
 #. "A menu choice in the graphical user interface that allows the user to specify how the application will act each time it is used. "
 #, fuzzy
 msgid "options"
-msgstr "åðéëïãÝò:\n"
+msgstr "επιλογές:\n"
 
 #. "Watch out: Although this word exists in gnucash program code, all that program code in gnucash is currently not activated. In the future, it will be used in business accounting as follows: A particular request to make or supply goods, but belonging to a (larger) job. Such a request can come from a customer or be sent to a vendor. An order will probably generate one invoice or bill."
 msgid "order"
@@ -612,7 +612,7 @@ msgstr ""
 #. "Name of an automatically created account that holds splits that have no account."
 #, fuzzy
 msgid "orphan"
-msgstr "ÊïñåÜôéêá"
+msgstr "Κορεάτικα"
 
 #. "The customer to (or employee or vendor from) which this invoice is sent - or short your business partner."
 msgid "owner (of bill, invoice or expense voucher)"
@@ -629,17 +629,17 @@ msgstr ""
 #. "A person to whom sth is paid"
 #, fuzzy
 msgid "payee"
-msgstr "óåëßäá"
+msgstr "σελίδα"
 
 #. "A person who pays or who has to pay for sth"
 #, fuzzy
 msgid "payer"
-msgstr "Óôñþìá"
+msgstr "Στρώμα"
 
 #. "1. The action of paying sb/sth or of being paid. 2. A sum of money paid."
 #, fuzzy
 msgid "payment"
-msgstr "ðáôñéêÜ"
+msgstr "πατρικά"
 
 #. "An account where no transactions may be posted to; transactions can only be posted to subaccounts of this account, so this account serves as a placeholder in the hierarchy"
 msgid "placeholder"
@@ -648,23 +648,23 @@ msgstr ""
 #. "A set of investments owned by a person"
 #, fuzzy
 msgid "portfolio"
-msgstr "ÅîáãùãÞ êáôáãñáöþí"
+msgstr "Εξαγωγή καταγραφών"
 
 #. "Register invoice, voucher in account register"
 #, fuzzy
 msgid "post, to"
-msgstr "Êëåßóéìï êáôáãñáöþí"
+msgstr "Κλείσιμο καταγραφών"
 
 #
 #. "A menu choice in many graphical user interface applications that allows the user to specify how the application will act each time it is used. "
 #, fuzzy
 msgid "preferences"
-msgstr "ÐñïôéìÞóåéò"
+msgstr "Προτιμήσεις"
 
 #. "Loan repayment calculator: your payments are split in interests payment and principal payment"
 #, fuzzy
 msgid "principal payment"
-msgstr "Ï_íüìáôá ÓõíáñôÞóåùí"
+msgstr "Ο_νόματα Συναρτήσεων"
 
 #. "An amount of money for which sth may be bought or sold"
 msgid "price (in a split)"
@@ -673,22 +673,22 @@ msgstr ""
 #. "An ask is an offer to sell, and the price you want to sell at."
 #, fuzzy
 msgid "price type: ask"
-msgstr "Ôýðïò áñ÷åßïõ:"
+msgstr "Τύπος αρχείου:"
 
 #. "A bid is an offer to buy, and the price you want to buy at."
 #, fuzzy
 msgid "price type: bid"
-msgstr "Ôýðïò áñ÷åßïõ:"
+msgstr "Τύπος αρχείου:"
 
 #. "online quotes (rather: quotation!?) A statement of the current price of stocks or commodities"
 #, fuzzy
 msgid "price: quotes"
-msgstr "Áðüêñõøç Óçìåéþìáôùí"
+msgstr "Απόκρυψη Σημειώματων"
 
 #. "Money gained in business, esp. the difference between the amount earned (sales) and the amount spent (expenses/cost): Profit is sales minus expenses/cost."
 #, fuzzy
 msgid "profit"
-msgstr "óôéãìÞ"
+msgstr "στιγμή"
 
 #. "OBSOLETE. This report was renamed to 'income statement' on 2004-07-13. Old definition: A list that shows the amount of money spent compared with the amount earned by a business in a particular period"
 msgid "Profit & Loss"
@@ -702,7 +702,7 @@ msgstr ""
 #. "-"
 #, fuzzy
 msgid "rebalance, to (a transaction)"
-msgstr "Åêêßíçóç íÝáò äéåíÝñãåéáò"
+msgstr "Εκκίνηση νέας διενέργειας"
 
 #. "reconcile an account, a reconciled split. To find a way to make the bank's account statement agree with the user's recorded transactions in an account."
 msgid "reconcile, to"
@@ -711,18 +711,18 @@ msgstr ""
 #. "-"
 #, fuzzy
 msgid "record keeping"
-msgstr "Óå ç÷ïãñÜöçóç"
+msgstr "Σε ηχογράφηση"
 
 #. "A list of items; a book containing such a list"
 #, fuzzy
 msgid "register"
-msgstr "ÅããñáöÞ"
+msgstr "Εγγραφή"
 
 #
 #. "A transaction that is divided into two or more parts"
 #, fuzzy
 msgid "register entry: split transaction"
-msgstr "Åêêßíçóç íÝáò äéåíÝñãåéáò"
+msgstr "Εκκίνηση νέας διενέργειας"
 
 #. "-"
 msgid "register entry: stock split"
@@ -744,13 +744,13 @@ msgstr ""
 #. "another form of register"
 #, fuzzy
 msgid "register: transaction journal"
-msgstr "Åêêßíçóç íÝáò äéåíÝñãåéáò"
+msgstr "Εκκίνηση νέας διενέργειας"
 
 #
 #. "reload the current document"
 #, fuzzy
 msgid "reload, to"
-msgstr "ÁíáíÝùóç"
+msgstr "Ανανέωση"
 
 #. "aka 'two-sided form' is in Europe often used for the balance sheet. Complement: report form: Vertical Form"
 msgid "report form: T Account Form"
@@ -763,12 +763,12 @@ msgstr ""
 #. "name of an equity account (?); to be distinguished from the opening balance."
 #, fuzzy
 msgid "Retained Earnings"
-msgstr "ÁðïìÝíïõí"
+msgstr "Απομένουν"
 
 #. "Create a new transaction that is the inverse of the old one.  When you add the two together they completely cancel out.  Accounts use this instead of voiding transactions, usually because the prior month has been closed and can no longer be changed, or the entire accounting system is 'write only'."
 #, fuzzy
 msgid "reverse transaction, to (Action in the register)"
-msgstr "Ç ðåñéãñáöÞ ðåñéÝ÷åé"
+msgstr "Η περιγραφή περιέχει"
 
 #. "(In the customer summary report) The total amount of money received because something was sold."
 msgid "sales"
@@ -778,12 +778,12 @@ msgstr ""
 #. "To write data (typically a file) to a storage medium, such as a disk or tape."
 #, fuzzy
 msgid "save, to (to a file)"
-msgstr "ÁðïèÞêåõóç ôçò áíáöïñÜò óå áñ÷åßï"
+msgstr "Αποθήκευση της αναφοράς σε αρχείο"
 
 #. "A transaction or reminder of a transaction that can be automatically executed at a specific time. It can be executed either once, or several times at regular intervals."
 #, fuzzy
 msgid "Scheduled Transaction"
-msgstr "ÄéåíÝñãåéåò"
+msgstr "Διενέργειες"
 
 #. "DEPRECATED. To repair unbalanced transactions and orphan splits in an account tree. Any transactions that have debits != credits will get a balancing split added (pointing to a special new account called 'Imbalance'). Any splits that do not have accounts are put into another special account called 'Orphan'. Deprecated - use the term 'to check and repair' now."
 msgid "scrub, to"
@@ -792,7 +792,7 @@ msgstr ""
 #. "A document or certificate showing who owns shares"
 #, fuzzy
 msgid "security"
-msgstr "ÁóöÜëåéá"
+msgstr "Ασφάλεια"
 
 #. "-"
 msgid "Share Balance (register)"
@@ -801,96 +801,96 @@ msgstr ""
 #. "Any of the equal parts into which the money of a business company is divided, giving the holder a right to a portion of the profits"
 #, fuzzy
 msgid "shares"
-msgstr "Äéáìïéñáæüìåíá"
+msgstr "Διαμοιραζόμενα"
 
 #. "(of a price) A place wfrom which sth comes or is obtained"
 #, fuzzy
 msgid "source"
-msgstr "Ðüñïò"
+msgstr "Πόρος"
 
 #. "One of the two or several parts a transaction is divided into"
 #, fuzzy
 msgid "split"
-msgstr "Äéáßñåóç"
+msgstr "Διαίρεση"
 
 #. "This sets the particular design or shape of a report."
 msgid "style sheet"
-msgstr "åðßóôñùìá ýöïõò"
+msgstr "επίστρωμα ύφους"
 
 #. "The total of a set of figures that are part of a larger group of figures"
 #, fuzzy
 msgid "subtotal"
-msgstr "%d óõíïëéêÜ"
+msgstr "%d συνολικά"
 
 #. "On the government's tax forms, the tax code identifies the given line or place on the form where certain amounts must be specified according to the current country's legislation"
 #, fuzzy
 msgid "tax code"
-msgstr "ðëçñïöïñßåò çëåê. äéåýè."
+msgstr "πληροφορίες ηλεκ. διεύθ."
 
 #. "field of an account"
 #, fuzzy
 msgid "tax info"
-msgstr "ðëçñïöïñßåò çëåê. äéåýè."
+msgstr "πληροφορίες ηλεκ. διεύθ."
 
 #. "if you create a new e.g. style sheet, you can start from a template"
 #, fuzzy
 msgid "template"
-msgstr "Ðñüôõðï"
+msgstr "Πρότυπο"
 
 #. "see: date range"
 #, fuzzy
 msgid "time period"
-msgstr "þñá"
+msgstr "ώρα"
 
 #
 #. "as abbreviation for Total"
 #, fuzzy
 msgid "Tot"
-msgstr "Ðñoò"
+msgstr "Πρoς"
 
 #. "The full number or amount: total of some balances, of any account's running balance etc."
 msgid "total"
-msgstr "óýíïëï"
+msgstr "σύνολο"
 
 #. "A piece of business done; the transfer of money from one account to one or more other accounts. (see also: Scheduled Transaction)"
 #, fuzzy
 msgid "transaction"
-msgstr "ÄéåíÝñãåéåò"
+msgstr "Διενέργειες"
 
 #
 #. "A transaction whose amount has actually been moved. The word comes from checks: a check is issued, but several steps have to be done until the amount is actually retrieved from the bank account, which is the point in time where that transaction (check) gets cleared."
 #, fuzzy
 msgid "transaction state: cleared"
-msgstr "¸íáñîç äéåíÝñãåéáò"
+msgstr "Έναρξη διενέργειας"
 
 #
 #. "-"
 #, fuzzy
 msgid "transaction state: frozen"
-msgstr "¸íáñîç äéåíÝñãåéáò"
+msgstr "Έναρξη διενέργειας"
 
 #
 #. "A transaction that was reconciled with the bank's statement."
 #, fuzzy
 msgid "transaction state: reconciled"
-msgstr "¸íáñîç äéåíÝñãåéáò"
+msgstr "Έναρξη διενέργειας"
 
 #
 #. "A transaction that is void i.e. not valid (anymore)."
 #, fuzzy
 msgid "transaction state: voided"
-msgstr "¸íáñîç äéåíÝñãåéáò"
+msgstr "Έναρξη διενέργειας"
 
 #
 #. "1. The action of transferring sth. 2. see: credit transfer"
 #, fuzzy
 msgid "transfer (noun)"
-msgstr "ÌåôáöïñÜ"
+msgstr "Μεταφορά"
 
 #. "The account where an amount is transferred to"
 #, fuzzy
 msgid "transfer account"
-msgstr "ðñïóùñéíÜ"
+msgstr "προσωρινά"
 
 #. "To move money from one account to another. Will create a transaction."
 msgid "transfer, to (register toolbar)"
@@ -903,12 +903,12 @@ msgstr ""
 #
 #. "A class or things that have characteristics in common; type of an account, of a commodity etc."
 msgid "type"
-msgstr "åßäïò"
+msgstr "είδος"
 
 #. "A fixed amount or number used as a standard of measurement; e.g. millimeters, inch; for absolute positioning in the custom check format."
 #, fuzzy
 msgid "units"
-msgstr "&ÌïíÜäåò:"
+msgstr "&Μονάδες:"
 
 #. "-"
 msgid "URL"
@@ -925,7 +925,7 @@ msgstr ""
 #. "The terms 'Voucher' and 'Expense Voucher' are used interchangeably in gnucash. The 'Expense Voucher' is also a bit of a misnomer -- it's more like an 'Expense Report' in gnucash.  The phrase is meant to be a list of expenses incurred by an employee for which the company will reminburse them."
 #, fuzzy
 msgid "voucher"
-msgstr "Ðüñïò"
+msgstr "Πόρος"
 
 #. "see debit"
 msgid "withdraw (in the reconcile dialog)"
@@ -933,7 +933,7 @@ msgstr ""
 
 #, fuzzy
 #~ msgid "invoice owner"
-#~ msgstr "áñ÷Üñéïò"
+#~ msgstr "αρχάριος"
 
 #~ msgid "Term"
-#~ msgstr "Ïñéóìüò"
+#~ msgstr "Ορισμός"
diff --git a/po/glossary/es.po b/po/glossary/es.po
index a006701..34a0f20 100644
--- a/po/glossary/es.po
+++ b/po/glossary/es.po
@@ -1,8 +1,8 @@
-# Glosario de términos de GnuCash traducido al español
+# Glosario de términos de GnuCash traducido al español
 # Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
-# Raúl Miró <cotin at geocities.com>, 2001.
+# Raúl Miró <cotin at geocities.com>, 2001.
 # Eneko Lacunza <enlar at enlar.net>, 2003.
-# Raúl Miró <cotin at geocities.com>, 2003.
+# Raúl Miró <cotin at geocities.com>, 2003.
 # Eneko Lacunza <enlar at enlar.net>, 2004.
 #
 msgid ""
@@ -15,8 +15,8 @@ msgstr ""
 "Language-Team: Spanish <es at li.org>\n"
 "Language: es\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=iso-8859-15\n"
-"Content-Transfer-Encoding: 8-bit\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
 
 #. "English Definition (Dear translator: This file will never be visible to the user! It should only serve as a tool for you, the translator. Nothing more.)"
 msgid "Term (Dear translator: This file will never be visible to the user!)"
@@ -28,7 +28,7 @@ msgstr "cuenta"
 
 #. "-"
 msgid "account code"
-msgstr "código de cuenta"
+msgstr "código de cuenta"
 
 #. "the tree view of all accounts"
 msgid "account hierarchy"
@@ -82,7 +82,7 @@ msgstr "tipo de cuenta: mercado monetario"
 
 #. "-"
 msgid "account type: Mutual fund"
-msgstr "tipo de cuenta: Fondo de Inversión"
+msgstr "tipo de cuenta: Fondo de Inversión"
 
 #. "The right side of the balance sheet in T account form shows the source of funds and contains equity & liability. While not common in english, most languages would translate 'equity & liability' with 'passive'. Complement: Active. See also: Report Form Implementation: https://bugzilla.gnome.org/show_bug.cgi?id=421766"
 #, fuzzy
@@ -121,71 +121,71 @@ msgstr "cuenta: cuenta de nivel superior"
 
 #. "The process of doing something that caused a transaction to happen"
 msgid "Action (register)"
-msgstr "Acción (libro)"
+msgstr "Acción (libro)"
 
 #. "Automated teller machine"
 msgid "action: ATM"
-msgstr "acción: cajero automático"
+msgstr "acción: cajero automático"
 
 #. "Transaction was an auto deposit"
 msgid "action: autoDep"
-msgstr "acción: autoDep"
+msgstr "acción: autoDep"
 
 #. "-"
 msgid "action: buy"
-msgstr "acción: compra"
+msgstr "acción: compra"
 
 #. "-"
 msgid "action: deposit"
-msgstr "acción: ingreso"
+msgstr "acción: ingreso"
 
 #. "When people can automatically deduct money straight from your account. The reverse of Direct Deposit."
 msgid "action: direct debit"
-msgstr "acción: abono directo"
+msgstr "acción: abono directo"
 
 #. "transaction is a distribution (???)"
 msgid "action: dist"
-msgstr "acción: dist"
+msgstr "acción: dist"
 
 #. "transaction is a dividend"
 msgid "action: div"
-msgstr "acción: div"
+msgstr "acción: div"
 
 #. "-"
 msgid "action: fee"
-msgstr "acción: fee"
+msgstr "acción: fee"
 
 #. "transaction comes from interest"
 msgid "action: int"
-msgstr "acción: int"
+msgstr "acción: int"
 
 #. "-"
 msgid "action: loan"
-msgstr "acción: préstamo"
+msgstr "acción: préstamo"
 
 #. "see: payment 1."
 msgid "action: payment"
-msgstr "acción: pago"
+msgstr "acción: pago"
 
 #. "Point of sale"
 msgid "action: POS"
-msgstr "acción: POS"
+msgstr "acción: POS"
 
 #. "-"
 msgid "action: rebate"
-msgstr "acción: descuento"
+msgstr "acción: descuento"
 
 #. "-"
 msgid "action: sell"
-msgstr "acción: venta"
+msgstr "acción: venta"
 
 #. "-"
 msgid "action: Teller"
-msgstr "acción: cajero (persona)"
+msgstr "acción: cajero (persona)"
 
 #. "see: transfer 2. (=credit transfer)"
 msgid "action: transfer"
-msgstr "acción: transferencia"
+msgstr "acción: transferencia"
 
 #. "-"
 msgid "action: wire"
@@ -193,7 +193,7 @@ msgstr ""
 
 #. "-"
 msgid "action: withdraw"
-msgstr "acción: reintegro"
+msgstr "acción: reintegro"
 
 #. "A sum of money"
 msgid "amount"
@@ -258,11 +258,11 @@ msgstr "ganancias de capital"
 
 #. "Distinguishing the uppercase and lowercase letters"
 msgid "case sensitive"
-msgstr "distinguir mayúsculas"
+msgstr "distinguir mayúsculas"
 
 #. "Money in coins or notes"
 msgid "cash"
-msgstr "metálico"
+msgstr "metálico"
 
 #. "(esp. US) (= cheque) A special printed form on which one writes an order to a bank to pay a sum of money from one's account to another person"
 msgid "check"
@@ -282,20 +282,20 @@ msgstr "valor"
 
 #. "e.g. NASDAQ"
 msgid "commodity listing"
-msgstr "índice de valores"
+msgstr "índice de valores"
 
 #. "the smallest amount of a commodity that's traded (e.g. 1/100 for USD, 1 for most stocks)"
 msgid "commodity option: fraction"
-msgstr "opción de valor: fracción"
+msgstr "opción de valor: fracción"
 
 #. "e.g. USD, DEM"
 msgid "commodity option: Symbol"
-msgstr "opción de valor: Símbolo"
+msgstr "opción de valor: Símbolo"
 
 #. "interest which is earned on both the initial deposit and on any interest that has already been earned but left on deposit."
 #, fuzzy
 msgid "compound interests"
-msgstr "interés"
+msgstr "interés"
 
 #. "(a) A sum of money paid into an account. (b) A record of such a payment. (c) The state of having money in one's bank account."
 msgid "Credit (column in register)"
@@ -303,7 +303,7 @@ msgstr "Haber (columna en el libro), Abono"
 
 #. "-"
 msgid "Credit Card"
-msgstr "Tarjeta de crédito"
+msgstr "Tarjeta de crédito"
 
 #. "A transfer of money direct from one bank account to another, without using a cheque"
 msgid "credit transfer"
@@ -328,7 +328,7 @@ msgstr "base de datos"
 
 #. "A specific numbered day of the month"
 msgid "Date"
-msgstr "Día (Fecha)"
+msgstr "Día (Fecha)"
 
 #. "DD/MM/YY or MM/DD/YY or something else"
 msgid "date format"
@@ -352,11 +352,11 @@ msgstr "ingreso"
 
 #. "The process of something becoming less valuable"
 msgid "depreciation"
-msgstr "depreciación"
+msgstr "depreciación"
 
 #. "1. One textfield per transaction. The text in it should describe what the transaction was about. A short descriptive phrase (up to 40 chars) 2. One textfield per account. It is intended to be a longer, 1-5 sentence description of what this account is all about."
 msgid "Description (column in register)"
-msgstr "Descripción"
+msgstr "Descripción"
 
 #. "Reductions to a basic price of goods or services. Your language might distinguish between discounts dealing with payments (billing terms) and others (invoice)."
 #, fuzzy
@@ -401,7 +401,7 @@ msgstr "tipo de archivo"
 
 #. "-"
 msgid "financial calculator: interest rate"
-msgstr "calculadora financiera: tasa de interés"
+msgstr "calculadora financiera: tasa de interés"
 
 #. "see: payment"
 msgid "financial calculator: payments"
@@ -425,7 +425,7 @@ msgstr ""
 
 #. "Money charged for borrowing money, or paid to somebody who invests money"
 msgid "interest"
-msgstr "interés"
+msgstr "interés"
 
 #. "A list of goods sold or services provided together with the prices charged; see also: a bill. In Gnucash, an 'invoice' is a statement that we sent out (to a customer), whereas a 'bill' is one that we received (from a vendor)."
 msgid "invoice"
@@ -445,11 +445,11 @@ msgstr "pasivo/patrimonio"
 
 #. "A sum of money that is lent (by a bank)"
 msgid "loan"
-msgstr "préstamo"
+msgstr "préstamo"
 
 #. "The money lost in business activity"
 msgid "loss"
-msgstr "pérdida"
+msgstr "pérdida"
 
 #. "name of an automatically created account"
 msgid "Lost Accounts"
@@ -512,7 +512,7 @@ msgstr "notas"
 
 #. "Abbreviation for: number; Field in a transaction. If this transaction was done by check, then the check number should be noted in this field."
 msgid "Num (column in register)"
-msgstr "Núm."
+msgstr "Núm."
 
 #. "to make accessible"
 msgid "open, to"
@@ -532,7 +532,7 @@ msgstr "pedido"
 
 #. "Name of an automatically created account that holds splits that have no account."
 msgid "orphan"
-msgstr "huérfano"
+msgstr "huérfano"
 
 #. "The customer to (or employee or vendor from) which this invoice is sent - or short your business partner."
 msgid "owner (of bill, invoice or expense voucher)"
@@ -578,11 +578,11 @@ msgstr "preferencias"
 #. "Loan repayment calculator: your payments are split in interests payment and principal payment"
 #, fuzzy
 msgid "principal payment"
-msgstr "acción: pago"
+msgstr "acción: pago"
 
 #. "An amount of money for which sth may be bought or sold"
 msgid "price (in a split)"
-msgstr "cotización (valor), precio (asiento)"
+msgstr "cotización (valor), precio (asiento)"
 
 #. "An ask is an offer to sell, and the price you want to sell at."
 msgid "price type: ask"
@@ -602,7 +602,7 @@ msgstr "beneficio"
 
 #. "OBSOLETE. This report was renamed to 'income statement' on 2004-07-13. Old definition: A list that shows the amount of money spent compared with the amount earned by a business in a particular period"
 msgid "Profit & Loss"
-msgstr "Cuenta de Pérdidas y Ganancias"
+msgstr "Cuenta de Pérdidas y Ganancias"
 
 #. "-"
 msgid "quick-fill"
@@ -618,7 +618,7 @@ msgstr "conciliar"
 
 #. "-"
 msgid "record keeping"
-msgstr "teneduría de libros?"
+msgstr "teneduría de libros?"
 
 #. "A list of items; a book containing such a list"
 msgid "register"
@@ -626,11 +626,11 @@ msgstr "libro de cuentas/anotaciones"
 
 #. "A transaction that is divided into two or more parts"
 msgid "register entry: split transaction"
-msgstr "anotación de libro de cuentas: asiento múltiple"
+msgstr "anotación de libro de cuentas: asiento múltiple"
 
 #. "-"
 msgid "register entry: stock split"
-msgstr "anotación en libro de cuentas: división de valor"
+msgstr "anotación en libro de cuentas: división de valor"
 
 #. "one form of register"
 msgid "register: auto-split ledger"
@@ -638,7 +638,7 @@ msgstr "libro de cuentas: libro con asientos desglosados"
 
 #. "another form of register"
 msgid "register: basic ledger"
-msgstr "libro de cuentas: libro básico"
+msgstr "libro de cuentas: libro básico"
 
 #. "another form of register"
 msgid "register: general ledger"
@@ -667,7 +667,7 @@ msgstr ""
 #. "Create a new transaction that is the inverse of the old one.  When you add the two together they completely cancel out.  Accounts use this instead of voiding transactions, usually because the prior month has been closed and can no longer be changed, or the entire accounting system is 'write only'."
 #, fuzzy
 msgid "reverse transaction, to (Action in the register)"
-msgstr "Descripción"
+msgstr "Descripción"
 
 #. "(In the customer summary report) The total amount of money received because something was sold."
 msgid "sales"
@@ -716,11 +716,11 @@ msgstr "subtotal"
 #. "On the government's tax forms, the tax code identifies the given line or place on the form where certain amounts must be specified according to the current country's legislation"
 #, fuzzy
 msgid "tax code"
-msgstr "información sobre impuestos"
+msgstr "información sobre impuestos"
 
 #. "field of an account"
 msgid "tax info"
-msgstr "información sobre impuestos"
+msgstr "información sobre impuestos"
 
 #. "if you create a new e.g. style sheet, you can start from a template"
 msgid "template"
@@ -728,7 +728,7 @@ msgstr "plantilla"
 
 #. "see: date range"
 msgid "time period"
-msgstr "período de tiempo"
+msgstr "período de tiempo"
 
 #. "as abbreviation for Total"
 msgid "Tot"
@@ -756,7 +756,7 @@ msgstr "estado del asiento: conciliado"
 
 #. "A transaction that is void i.e. not valid (anymore)."
 msgid "transaction state: voided"
-msgstr "estado de asiento: inválido"
+msgstr "estado de asiento: inválido"
 
 #. "1. The action of transferring sth. 2. see: credit transfer"
 msgid "transfer (noun)"
@@ -809,4 +809,4 @@ msgstr "cargo"
 #~ msgstr "factura"
 
 #~ msgid "Term"
-#~ msgstr "Condiciones (Términos) (de pago)"
+#~ msgstr "Condiciones (Términos) (de pago)"
diff --git a/po/glossary/es_NI-policy.txt b/po/glossary/es_NI-policy.txt
index fe478db..6871160 100644
--- a/po/glossary/es_NI-policy.txt
+++ b/po/glossary/es_NI-policy.txt
@@ -1,23 +1,23 @@
 LEG22102001 - es_NI-policy.txt
 
 En este documento se describen las normas aplicadas al traducir los
-textos de GnuCash al idioma español
+textos de GnuCash al idioma español
 
-Nota: El autor no es native speaker del español, ni especialista
-      contable.  Cualquier recomendación o corrección es muy
+Nota: El autor no es native speaker del español, ni especialista
+      contable.  Cualquier recomendación o corrección es muy
       bienvenida.
 
 
 Onda:
 =====
 
-La onda es, crear una notación apta para pequeños negocios, de tal
+La onda es, crear una notación apta para pequeños negocios, de tal
 manera, que se puede usar en la vida comercial y fiscal.  Por lo tanto
-se prefiere términos oficiales/contables ante términos del habla
-común.
+se prefiere términos oficiales/contables ante términos del habla
+común.
 
-La explicación de estos términos a una persona privada que quiere usar
-GnuCash es tarea de la documentación.
+La explicación de estos términos a una persona privada que quiere usar
+GnuCash es tarea de la documentación.
 
 
 Mayuscula/Menuscula:
@@ -37,10 +37,10 @@ Ejemplos:
 + "Abrir"
 
 
-Puntuación
+Puntuación
 ==========
 
-Normalmente se deja dos espacios después de la puntuación de frases.
+Normalmente se deja dos espacios después de la puntuación de frases.
 Ya que supongo que usamos fuentes proporcionales no se utiliza esta
 regla y solamente se inserta un (1) espacio.
 
@@ -49,12 +49,12 @@ Diccionario
 ===========
 
 Commodity	valores (plural)
-Stock		acción
+Stock		acción
 Income		ingreso
 Expense		egreso
 Asset		activo
 Liability	pasivo
-Price quote	cotización
+Price quote	cotización
 Reconcile	reconciliar
 Portfolio	cartera
 Parent account	cuenta superior
@@ -67,15 +67,15 @@ Forward		avanzar
 
 Top-Level	primer plano
 
-Account Tree	jerarquía de cuentas
+Account Tree	jerarquía de cuentas
 GnuCash Network	Red GnuCash
 
--- estoy buscando el término correcto para
+-- estoy buscando el término correcto para
 
-Equity		¿patrimonio? o equidad, lo último esta actualmente en
+Equity		¿patrimonio? o equidad, lo último esta actualmente en
 		uso.
 
-Security	código de seguridad
+Security	código de seguridad
 
 Share		partida
 
@@ -93,12 +93,12 @@ Nota: prefiereo "encontrar" bara "find" y "buscar" para "search", pero
 no ha sido esforzado.
 
 
-Género
+Género
 ======
 
-Donde aplicable se utiliza los dos géneros al referirse a personas,
-usando la notación: el/la contador/a. Por razones de consistencia
-siempre el género femenino viene en segunda posición.
+Donde aplicable se utiliza los dos géneros al referirse a personas,
+usando la notación: el/la contador/a. Por razones de consistencia
+siempre el género femenino viene en segunda posición.
 
 
 
diff --git a/po/glossary/it.po b/po/glossary/it.po
index 9a524d5..4d06055 100644
--- a/po/glossary/it.po
+++ b/po/glossary/it.po
@@ -6,7 +6,7 @@
 # Cristian Marchi <cri79 at libero.it>, 2008.
 #
 # - I messaggi ancora dubbi sono marcati come fuzzy.
-# - Quando qui sono indicate più traduzioni, la prima è quella usata
+# - Quando qui sono indicate più traduzioni, la prima è quella usata
 #   nel .po vero del programma.
 #
 msgid ""
@@ -18,7 +18,7 @@ msgstr ""
 "Language-Team: Italian <tp at lists.linux.it>\n"
 "Language: it\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
 #. "English Definition (Dear translator: This file will never be visible to the user! It should only serve as a tool for you, the translator. Nothing more.)"
@@ -44,16 +44,16 @@ msgstr "nome conto"
 #. "The left side of the balance sheet in T account form shows the application of funds in form of assets. Because it contains only assets use assets directly. Complement: Passive. See also: Report Form"
 #, fuzzy
 msgid "account type: Active"
-msgstr "tipo conto: attivo, attività"
+msgstr "tipo conto: attivo, attività"
 
 #. "A thing, esp. owned by a person or company, that has value and can be used or sold to pay debts. Dependent on the context you might use 'account type: Active' instead."
 msgid "account type: Asset"
-msgstr "tipo conto: attivo, attività"
+msgstr "tipo conto: attivo, attività"
 
 #. "in fact: 'Active & Passive', group aka 'Balance Sheet accounts'; complement of 'Profit & Loss'"
 #, fuzzy
 msgid "account type: Assets & Liabilities"
-msgstr "tipo conto: passivo, passività, obbligazione, debito"
+msgstr "tipo conto: passivo, passività, obbligazione, debito"
 
 #. "(esp. US) (Brit = current account) a bank account from which money can be withdrawn without previous notice"
 msgid "account type: checking"
@@ -77,7 +77,7 @@ msgstr "tipo conto: entrate"
 
 #. "A debt, a financial obligation, but see also 'account type: Passive'"
 msgid "account type: Liability"
-msgstr "tipo conto: passivo, passività, obbligazione, debito"
+msgstr "tipo conto: passivo, passività, obbligazione, debito"
 
 #. "-"
 msgid "account type: money-market"
@@ -90,12 +90,12 @@ msgstr "tipo conto: fondi comuni"
 #. "The right side of the balance sheet in T account form shows the source of funds and contains equity & liability. While not common in english, most languages would translate 'equity & liability' with 'passive'. Complement: Active. See also: Report Form Implementation: https://bugzilla.gnome.org/show_bug.cgi?id=421766"
 #, fuzzy
 msgid "account type: Passive"
-msgstr "tipo conto: attivo, attività"
+msgstr "tipo conto: attivo, attività"
 
 #. "Group of accounts tracking your success, complement of 'Assets & Liabilities'"
 #, fuzzy
 msgid "account type: Profit & Loss"
-msgstr "tipo conto: attivo, attività"
+msgstr "tipo conto: attivo, attività"
 
 #. "1. (US) any type of account that earns interest 2. (Brit) any type of bank account that earns a higher level of interest than a current account or deposit account"
 msgid "account type: saving"
@@ -447,7 +447,7 @@ msgstr "libro mastro, mastro"
 
 #. "The heading for the right side of the balance sheet. See also: Equity."
 msgid "liabilities/equity"
-msgstr "passività/nette"
+msgstr "passività/nette"
 
 #. "A sum of money that is lent (by a bank)"
 msgid "loan"
@@ -482,7 +482,7 @@ msgstr "marcatore"
 
 #. "The way how more than one window is displayed in GnuCash at the same time. MDI = Multiple Document Interface."
 msgid "MDI modus"
-msgstr "modalità MDI"
+msgstr "modalità MDI"
 
 #. "One textfield per split that should help you remember what this split was about."
 msgid "Memo"
@@ -628,7 +628,7 @@ msgstr "tenere traccia"
 
 #. "A list of items; a book containing such a list"
 msgid "register"
-msgstr "registro (termine generico e più comprensibile)"
+msgstr "registro (termine generico e più comprensibile)"
 
 #. "A transaction that is divided into two or more parts"
 msgid "register entry: split transaction"
@@ -788,7 +788,7 @@ msgstr "tipo"
 
 #. "A fixed amount or number used as a standard of measurement; e.g. millimeters, inch; for absolute positioning in the custom check format."
 msgid "units"
-msgstr "unità"
+msgstr "unità"
 
 #. "-"
 msgid "URL"
diff --git a/po/glossary/lt.po b/po/glossary/lt.po
index 28b9c9f..1f8605c 100644
--- a/po/glossary/lt.po
+++ b/po/glossary/lt.po
@@ -12,7 +12,7 @@ msgstr ""
 "Language: lt\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n"
 "%100<10 || n%100>=20) ? 1 : 2);\n"
 "X-Generator: Virtaal 0.7.0\n"
diff --git a/po/glossary/nb.po b/po/glossary/nb.po
index b1261c5..c3aca89 100644
--- a/po/glossary/nb.po
+++ b/po/glossary/nb.po
@@ -15,7 +15,7 @@ msgstr ""
 "Language-Team: Norwegian/Bokmaal <i18n-nb at lister.ping.uio.no>\n"
 "Language:  Norwegian/Bokmaal\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
 #. "English Definition (Dear translator: This file will never be visible to the user! It should only serve as a tool for you, the translator. Nothing more.)"
@@ -117,7 +117,7 @@ msgstr "account: underkonto"
 
 #. "-"
 msgid "account: top level account"
-msgstr "account: toppnivå konto"
+msgstr "account: toppnivå konto"
 
 #. "The process of doing something that caused a transaction to happen"
 msgid "Action (register)"
@@ -133,7 +133,7 @@ msgstr ""
 
 #. "-"
 msgid "action: buy"
-msgstr "action: kjøpe"
+msgstr "action: kjøpe"
 
 #. "-"
 msgid "action: deposit"
@@ -141,7 +141,7 @@ msgstr "action: bankinskudd"
 
 #. "When people can automatically deduct money straight from your account. The reverse of Direct Deposit."
 msgid "action: direct debit"
-msgstr "action: automatisk overførsel"
+msgstr "action: automatisk overførsel"
 
 #. "transaction is a distribution (???)"
 msgid "action: dist"
@@ -185,7 +185,7 @@ msgstr ""
 
 #. "see: transfer 2. (=credit transfer)"
 msgid "action: transfer"
-msgstr "action: overfør"
+msgstr "action: overfør"
 
 #. "-"
 msgid "action: wire"
@@ -197,7 +197,7 @@ msgstr "action: bankuttak"
 
 #. "A sum of money"
 msgid "amount"
-msgstr "beløp"
+msgstr "beløp"
 
 #. "The result of adding several amounts together and then dividing this total by the number of amounts"
 msgid "average"
@@ -246,11 +246,11 @@ msgstr "Budsjett"
 
 #. "-"
 msgid "business (adjective)"
-msgstr "næring (adjektiv)"
+msgstr "næring (adjektiv)"
 
 #. "as Menu Item: Headline for features that are related to small business accounting"
 msgid "business (noun)"
-msgstr "Næring"
+msgstr "Næring"
 
 #. "Profits made from the sale of investments or property"
 msgid "capital gains"
@@ -258,7 +258,7 @@ msgstr ""
 
 #. "Distinguishing the uppercase and lowercase letters"
 msgid "case sensitive"
-msgstr "skill mellom store/små bokstaver"
+msgstr "skill mellom store/små bokstaver"
 
 #. "Money in coins or notes"
 msgid "cash"
@@ -307,12 +307,12 @@ msgstr "Kredittkort"
 
 #. "A transfer of money direct from one bank account to another, without using a cheque"
 msgid "credit transfer"
-msgstr "bankoverføring"
+msgstr "bankoverføring"
 
 #. "A document that you give to a client that says you owe money to the client, i.e. the opposite of an invoice"
 #, fuzzy
 msgid "credit note"
-msgstr "bankoverføring"
+msgstr "bankoverføring"
 
 #. "The system of money used in a country"
 msgid "currency"
@@ -336,7 +336,7 @@ msgstr "dato format"
 
 #. "A range in time that is delimited by two distinct dates."
 msgid "date range"
-msgstr "dato område"
+msgstr "dato område"
 
 #. "(a) A written note in an account of a sum owed or paid out. (b) A sum withdrawn from an account."
 msgid "Debit (column in register)"
@@ -365,7 +365,7 @@ msgstr "konto"
 
 #. "Important Buzzword :)"
 msgid "double entry"
-msgstr "dobbel bokføring"
+msgstr "dobbel bokføring"
 
 #. "a person who works for somebody or a company in return for wages"
 msgid "employee"
@@ -445,7 +445,7 @@ msgstr "gjeld/egenkapital"
 
 #. "A sum of money that is lent (by a bank)"
 msgid "loan"
-msgstr "lån"
+msgstr "lån"
 
 #. "The money lost in business activity"
 msgid "loss"
@@ -461,16 +461,16 @@ msgstr ""
 
 #. "Combine two books into one (see book)."
 msgid "merge, to"
-msgstr "slå sammen, til"
+msgstr "slå sammen, til"
 
 #. "The thing that the scatter plot uses to mark each data point"
 msgid "marker"
-msgstr "markør"
+msgstr "markør"
 
 #. "1. Some text annotation, but this meaning isn't used inside gnucash. 2. In the Customer summary report: The ratio of profit vs. sales, i.e. the profit amount divided by the sales amount, shown in percent."
 #, fuzzy
 msgid "markup"
-msgstr "markør"
+msgstr "markør"
 
 #. "The way how more than one window is displayed in GnuCash at the same time. MDI = Multiple Document Interface."
 msgid "MDI modus"
@@ -514,11 +514,11 @@ msgstr "No, (kolonne i registeret)="
 
 #. "to make accessible"
 msgid "open, to"
-msgstr "åpne, til"
+msgstr "Ã¥pne, til"
 
 #. "If an account starts with a non-zero balance, then this amount is called the opening balance."
 msgid "opening balance"
-msgstr "inngående balanse"
+msgstr "inngående balanse"
 
 #. "A menu choice in the graphical user interface that allows the user to specify how the application will act each time it is used. "
 msgid "options"
@@ -562,12 +562,12 @@ msgstr "plassholder"
 
 #. "A set of investments owned by a person"
 msgid "portfolio"
-msgstr "portefølje"
+msgstr "portefølje"
 
 #. "Register invoice, voucher in account register"
 #, fuzzy
 msgid "post, to"
-msgstr "åpne, til"
+msgstr "Ã¥pne, til"
 
 #. "A menu choice in many graphical user interface applications that allows the user to specify how the application will act each time it is used. "
 msgid "preferences"
@@ -580,7 +580,7 @@ msgstr "action: betaling"
 
 #. "An amount of money for which sth may be bought or sold"
 msgid "price (in a split)"
-msgstr "beløp (i en splitt)"
+msgstr "beløp (i en splitt)"
 
 #. "An ask is an offer to sell, and the price you want to sell at."
 msgid "price type: ask"
@@ -616,7 +616,7 @@ msgstr "avstemme, til"
 
 #. "-"
 msgid "record keeping"
-msgstr "bokføring"
+msgstr "bokføring"
 
 #. "A list of items; a book containing such a list"
 msgid "register"
@@ -648,7 +648,7 @@ msgstr "register: transaksjons journal"
 
 #. "reload the current document"
 msgid "reload, to"
-msgstr "laste på nytt, til"
+msgstr "laste på nytt, til"
 
 #. "aka 'two-sided form' is in Europe often used for the balance sheet. Complement: report form: Vertical Form"
 msgid "report form: T Account Form"
@@ -757,15 +757,15 @@ msgstr "transaction state: annulert"
 
 #. "1. The action of transferring sth. 2. see: credit transfer"
 msgid "transfer (noun)"
-msgstr "overfør (noun)"
+msgstr "overfør (noun)"
 
 #. "The account where an amount is transferred to"
 msgid "transfer account"
-msgstr "overføringskonto"
+msgstr "overføringskonto"
 
 #. "To move money from one account to another. Will create a transaction."
 msgid "transfer, to (register toolbar)"
-msgstr "overfor, til (registrerings verktøylinje)"
+msgstr "overfor, til (registrerings verktøylinje)"
 
 #. "The trial balance is a worksheet on which you list all your general ledger accounts and their debit or credit balance. It is a tool that is used to alert you to errors in your books. The total debits must equal the total credits. If they don't equal, you know you have an error that must be tracked down."
 #, fuzzy
@@ -786,11 +786,11 @@ msgstr "URL"
 
 #. "The worth of sth in terms of money or other commodities for which it can be exchanged"
 msgid "value (in a split)"
-msgstr "beløp"
+msgstr "beløp"
 
 #. "In small business accounting: A person or company that sells items and is supplying goods"
 msgid "vendor"
-msgstr "leverandør"
+msgstr "leverandør"
 
 #. "The terms 'Voucher' and 'Expense Voucher' are used interchangeably in gnucash. The 'Expense Voucher' is also a bit of a misnomer -- it's more like an 'Expense Report' in gnucash.  The phrase is meant to be a list of expenses incurred by an employee for which the company will reminburse them."
 #, fuzzy



Summary of changes:
 .gitignore                                         |   1 +
 CMakeLists.txt                                     |   4 +-
 ChangeLog                                          | 446 ++++++++++++++++++++-
 NEWS                                               |  97 +++++
 bindings/python/sqlite3test.c                      |   6 +-
 cmake/CMakeLists.txt                               |  16 +-
 configure.ac                                       |   2 +-
 libgnucash/backend/dbi/gnc-dbisqlresult.cpp        |   2 +-
 .../backend/sql/gnc-sql-column-table-entry.cpp     |   2 +-
 libgnucash/engine/gnc-date.cpp                     |  18 +-
 libgnucash/engine/gnc-date.h                       |   2 +-
 libgnucash/engine/test/test-gnc-date.c             |  23 +-
 po/glossary/ca.po                                  |   2 +-
 po/glossary/el.po                                  | 268 ++++++-------
 po/glossary/es.po                                  | 108 ++---
 po/glossary/es_NI-policy.txt                       |  40 +-
 po/glossary/it.po                                  |  24 +-
 po/glossary/lt.po                                  |   2 +-
 po/glossary/nb.po                                  |  58 +--
 19 files changed, 814 insertions(+), 307 deletions(-)



More information about the gnucash-changes mailing list