gnucash master: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Tue Nov 28 18:15:22 EST 2017


Updated	 via  https://github.com/Gnucash/gnucash/commit/5204100d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/e92a1b37 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/831640b5 (commit)
	 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/50874d89 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d8c2f524 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/037c93fa (commit)
	 via  https://github.com/Gnucash/gnucash/commit/1e81d3ac (commit)
	 via  https://github.com/Gnucash/gnucash/commit/9c4635e3 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/0d8112bf (commit)
	 via  https://github.com/Gnucash/gnucash/commit/22e7e1b4 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/761d4091 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/baf7575f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/a5d15de4 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/99f2283d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/c5f483d1 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/78ec2e33 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/67e4b352 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/8a6ce10a (commit)
	 via  https://github.com/Gnucash/gnucash/commit/1b52053d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/ed4bad34 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/2a476cb6 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/bbafb818 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/9cd2c6d1 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/937f8c50 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/1674eb0b (commit)
	 via  https://github.com/Gnucash/gnucash/commit/2cbfc5bb (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/cdb764fe (commit)



commit 5204100d53b67fda3960f58568331d4822eab6bf
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Nov 28 14:25:35 2017 -0800

    Use GNUInstallDirs in CMake Builds
    
    Provides correct file layout when building distribution tarballs.
    Fixes Bugs 790840 and 790841.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index f35ac5c..1f8054d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -46,6 +46,7 @@ INCLUDE (GncConfigure)
 INCLUDE (GncAddGSchemaTargets)
 INCLUDE (GncAddTest)
 INCLUDE (MakeDistFiles)
+INCLUDE (GNUInstallDirs)
 
 # ############################################################
 # These options are settable from the CMake command line. For example, to disable
@@ -73,17 +74,17 @@ OPTION (AUTOTOOLS_IN_DIST "Add autotools support to distribution tarballs." ON)
 # These are also settable from the command line in a similar way.
 
 SET(GNUCASH_BUILD_ID "" CACHE STRING "Overrides the GnuCash build identification (Build ID) which defaults to a description of the vcs commit from which gnucash is built. Distributions may want to insert a package management based version number instead")
-SET(BINDIR ${CMAKE_INSTALL_PREFIX}/bin CACHE STRING "user executables")
-SET(SYSCONFDIR ${CMAKE_INSTALL_PREFIX}/etc CACHE STRING "read-only single-machine data")
-SET(DATAROOTDIR ${CMAKE_INSTALL_PREFIX}/share CACHE STRING "read-only arch.-independent data root")
-SET(DATADIR ${DATAROOTDIR} CACHE STRING "read-only architecture-independent data")
-SET(LIBDIR ${CMAKE_INSTALL_PREFIX}/lib CACHE STRING "object code libraries")
+SET(BINDIR ${CMAKE_INSTALL_BINDIR} CACHE STRING "user executables")
+SET(SYSCONFDIR ${CMAKE_INSTALL_SYSCONFDIR} CACHE STRING "read-only single-machine data")
+SET(DATAROOTDIR ${CMAKE_INSTALL_DATAROOTDIR} CACHE STRING "read-only arch.-independent data root")
+SET(DATADIR ${CMAKE_INSTALL_DATADIR} CACHE STRING "read-only architecture-independent data")
+SET(LIBDIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING "object code libraries")
 SET(LOCALEDIR ${DATAROOTDIR}/locale CACHE STRING "locale-dependent data")
 SET(GNC_HELPDIR ${DATADIR} CACHE STRING "where to store help files")
 SET(DATADIRNAME share)
 SET(GNC_SYSTEM_XDG_DATA_DIRS /usr/local/share /usr/share)
 SET(GNC_DBD_DIR ${CMAKE_PREFIX_PATH}/lib/dbd CACHE PATH "specify location of libdbi drivers")
-SET(PKGLIBDIR ${CMAKE_INSTALL_PREFIX}/lib/gnucash)
+SET(PKGLIBDIR ${CMAKE_INSTALL_LIBDIR}/gnucash)
 SET(TEST_MYSQL_URL "" CACHE STRING "MySQL database URL for testing")
 SET(TEST_PGSQL_URL "" CACHE STRING "PgSQL database URL for testing")
 
@@ -492,11 +493,11 @@ SET( CMAKE_CXX_FLAGS_DEBUG "-O0 -g ${CMAKE_CXX_FLAGS} -Wno-deprecated-declaratio
 
 IF (APPLE AND WITH_GNUCASH)
   SET(CMAKE_MACOSX_RPATH ON)
-  SET(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib")
+  SET(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_FULL_LIBDIR}")
 ENDIF (APPLE AND WITH_GNUCASH)
 
 IF (UNIX)
-  SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib:${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}:${PKGLIBDIR}")
 ENDIF()
 
 SET(BUILD_SHARED_LIBS ON)
@@ -564,7 +565,7 @@ SET(gnucash_DOCS
 )
 
 
-INSTALL(FILES ${gnucash_DOCS} DESTINATION share/doc/gnucash)
+INSTALL(FILES ${gnucash_DOCS} DESTINATION ${CMAKE_INSTALL_DOCDIR})
 
 # ############################################################
 
@@ -689,8 +690,8 @@ ADD_DEFINITIONS (-DHAVE_CONFIG_H)
 SET (CONFIG_H ${CMAKE_CURRENT_BINARY_DIR}/common/config.h)
 CONFIGURE_FILE (${CMAKE_CURRENT_SOURCE_DIR}/common/config.h.cmake.in ${CONFIG_H})
 
-SET(SCHEME_INSTALLED_SOURCE_DIR ${CMAKE_INSTALL_PREFIX}/share/gnucash/scm)
-SET(SCHEME_INSTALLED_CACHE_DIR ${CMAKE_INSTALL_PREFIX}/lib/gnucash/scm/ccache/${GUILE_EFFECTIVE_VERSION})
+SET(SCHEME_INSTALLED_SOURCE_DIR ${CMAKE_INSTALL_DATADIR}/gnucash/scm)
+SET(SCHEME_INSTALLED_CACHE_DIR ${PKGLIBDIR}/scm/ccache/${GUILE_EFFECTIVE_VERSION})
 
 # The subdirectories
 ADD_SUBDIRECTORY (borrowed)
@@ -834,9 +835,9 @@ IF (BUILDING_FROM_VCS)
     COMMAND ${GIT_EXECUTABLE} log --format=\"%ad %aN %n%n%x09* %s%d%n\" --date=short --since=2016-01-01 > ${CMAKE_BINARY_DIR}/ChangeLog
     WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
   )
-  INSTALL(FILES ${CMAKE_BINARY_DIR}/ChangeLog DESTINATION share/doc/gnucash)
+  INSTALL(FILES ${CMAKE_BINARY_DIR}/ChangeLog DESTINATION ${CMAKE_INSTALL_DOCDIR})
 ELSE()
-  INSTALL(FILES ${CMAKE_SOURCE_DIR}/ChangeLog DESTINATION share/doc/gnucash)
+  INSTALL(FILES ${CMAKE_SOURCE_DIR}/ChangeLog DESTINATION ${CMAKE_INSTALL_DOCDIR})
 ENDIF()
 
 #Link LICENSE to COPYING so that people expecting to find it,
@@ -850,7 +851,7 @@ ENDIF()
 INSTALL(CODE
 " EXECUTE_PROCESS(
       COMMAND ${CMAKE_COMMAND} -E ${_CMD} LICENSE COPYING
-      WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/share/doc/gnucash
+      WORKING_DIRECTORY ${CMAKE_INSTALL_DOCDIR}
   )"
 )
 
@@ -860,7 +861,7 @@ IF (WIN32)
   FIND_LIBRARY(LIBSTDC++ libstdc++-6.dll)
   FIND_LIBRARY(LIBDW2 libgcc_s_dw2-1.dll)
   SET(MINGW_DLLS ${LIBSTDC++} ${LIBDW2})
-  INSTALL(PROGRAMS ${MINGW_DLLS} DESTINATION bin)
+  INSTALL(PROGRAMS ${MINGW_DLLS} DESTINATION ${CMAKE_INSTALL_BINDIR})
   FILE(COPY ${MINGW_DLLS} DESTINATION ${BINDIR_BUILD}
     # Do permissions matter for windows?
     FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
diff --git a/borrowed/goffice/CMakeLists.txt b/borrowed/goffice/CMakeLists.txt
index adb1fca..b056787 100644
--- a/borrowed/goffice/CMakeLists.txt
+++ b/borrowed/goffice/CMakeLists.txt
@@ -7,9 +7,9 @@ set(goffice_SOURCES go-optionmenu.c go-charmap-sel.c go-glib-extras.c)
 #TARGET_INCLUDE_DIRECTORIES(gnc-goffice PUBLIC ${GTK_CFLAGS} ${LIBXML2_CFLAGS})
 
 #INSTALL(TARGETS gnc-goffice
-#  LIBRARY DESTINATION lib
-#  ARCHIVE DESTINATION lib
-#  RUNTIME DESTINATION bin)
+#  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+#  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+#  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
 SET_DIST_LIST(goffice_DIST CMakeLists.txt Makefile.am
   README ${goffice_noinst_HEADERS} ${goffice_SOURCES})
diff --git a/borrowed/gwengui-gtk3/CMakeLists.txt b/borrowed/gwengui-gtk3/CMakeLists.txt
index 446c63c..a9b68f9 100644
--- a/borrowed/gwengui-gtk3/CMakeLists.txt
+++ b/borrowed/gwengui-gtk3/CMakeLists.txt
@@ -53,7 +53,7 @@ TARGET_INCLUDE_DIRECTORIES(gwengui-gtk3 PUBLIC
 TARGET_LINK_LIBRARIES(gwengui-gtk3 ${GWENHYWFAR_LDFLAGS} ${GTK3_LDFLAGS})
 
 INSTALL(TARGETS gwengui-gtk3
-  LIBRARY DESTINATION lib
-  ARCHIVE DESTINATION lib
-  RUNTIME DESTINATION bin
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
   )
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
index bce5e3e..d79d108 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -2,9 +2,9 @@
 
 IF (APPLE)
   INSTALL(CODE "EXECUTE_PROCESS(
-                COMMAND /usr/bin/install_name_tool -add_rpath ${CMAKE_INSTALL_PREFIX}/lib
-                                                   -add_rpath ${CMAKE_INSTALL_PREFIX}/lib/gnucash
-                                                   ${CMAKE_INSTALL_PREFIX}/bin/gnucash)")
+                COMMAND /usr/bin/install_name_tool -add_rpath ${CMAKE_INSTALL_LIBDIR}
+                                                   -add_rpath ${PKGLIBDIR}
+                                                   ${CMAKE_INSTALL_BINDIR}/gnucash)")
 ENDIF(APPLE)
 
 
diff --git a/common/test-core/CMakeLists.txt b/common/test-core/CMakeLists.txt
index aa6e331..3309232 100644
--- a/common/test-core/CMakeLists.txt
+++ b/common/test-core/CMakeLists.txt
@@ -73,4 +73,4 @@ ADD_LIBRARY(gmock STATIC  ${lib_gmock_SOURCES})
 TARGET_INCLUDE_DIRECTORIES(gmock PUBLIC
   ${GTEST_INCLUDE_DIR} ${GTEST_SRC_DIR}
   ${GMOCK_INCLUDE_DIR} ${GMOCK_SRC_DIR})
-INSTALL(FILES unittest-support.h DESTINATION libexec/gnucash/libgnucash/engine/test)
+INSTALL(FILES unittest-support.h DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/gnucash/libgnucash/engine/test)
diff --git a/data/accounts/CMakeLists.txt b/data/accounts/CMakeLists.txt
index d02aa52..1c62ab1 100644
--- a/data/accounts/CMakeLists.txt
+++ b/data/accounts/CMakeLists.txt
@@ -36,7 +36,7 @@ SET(accounts_SUBDIRS
   zh_TW
 )
 
-SET(ACCOUNTS_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/share/gnucash/accounts)
+SET(ACCOUNTS_INSTALL_DIR ${CMAKE_INSTALL_DATADIR}/gnucash/accounts)
 SET(ACCOUNTS_BUILD_DIR ${DATADIR_BUILD}/gnucash/accounts)
 
 
diff --git a/data/checks/CMakeLists.txt b/data/checks/CMakeLists.txt
index 095119b..e9f8b3a 100644
--- a/data/checks/CMakeLists.txt
+++ b/data/checks/CMakeLists.txt
@@ -8,7 +8,7 @@ SET(checks_DATA
   quicken_3part.chk
 )
 
-INSTALL(FILES ${checks_DATA} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/gnucash/checks)
+INSTALL(FILES ${checks_DATA} DESTINATION ${CMAKE_INSTALL_DATADIR}/gnucash/checks)
 
 FILE(COPY ${checks_DATA} DESTINATION ${DATADIR_BUILD}/gnucash/checks)
 
diff --git a/gnucash/CMakeLists.txt b/gnucash/CMakeLists.txt
index 69fc47e..1ba974a 100644
--- a/gnucash/CMakeLists.txt
+++ b/gnucash/CMakeLists.txt
@@ -85,7 +85,7 @@ IF (MAC_INTEGRATION)
   TARGET_LINK_LIBRARIES(gnucash ${OSX_EXTRA_LIBRARIES})
 ENDIF(MAC_INTEGRATION)
 
-INSTALL(TARGETS gnucash DESTINATION bin)
+INSTALL(TARGETS gnucash DESTINATION ${CMAKE_INSTALL_BINDIR})
 # No headers to install.
 
 # Generate the gnucash-env script
@@ -95,7 +95,7 @@ SET(SCRIPT_OUTPUT_DIR ${BINDIR_BUILD})
 FOREACH (script gnucash-env gnucash-make-guids)
   SET (GNUCASH_ENV_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${script})
   LIST(APPEND SCRIPT_LIST ${SCRIPT_OUTPUT_DIR}/${script})
-  SET (GNC_OVERRIDES_DIR ${CMAKE_INSTALL_PREFIX}/libexec/gnucash/overrides)
+  SET (GNC_OVERRIDES_DIR ${CMAKE_INSTALL_LIBEXECDIR}/gnucash/overrides)
   FILE(WRITE ${GNUCASH_ENV_SCRIPT} "#!/bin/sh\n")
   FILE(APPEND ${GNUCASH_ENV_SCRIPT} "PATH=\"${GNC_OVERRIDES_DIR}:\${PATH}\"\n")
   FILE(APPEND ${GNUCASH_ENV_SCRIPT} "export PATH\n")
@@ -154,9 +154,9 @@ IF (NOT(${GNC_DBD_DIR} STREQUAL "${CMAKE_PREFIX_PATH}/lib/dbd"))
   FILE(APPEND ${ENV_FILE_OUT} "GNC_DBD_DIR=${GNC_DBD_DIR}")
 ENDIF()
 
-IF (NOT(${DATADIR} STREQUAL "/usr/share") AND NOT(${DATADIR} STREQUAL "/usr/local/share"))
+IF (NOT(${CMAKE_INSTALL_FULL_DATADIR} STREQUAL "/usr/share") AND NOT(${CMAKE_INSTALL_FULL_DATADIR} STREQUAL "/usr/local/share"))
   FILE(APPEND ${ENV_FILE_OUT} ${XDG_TEXT})
-  FILE(APPEND ${ENV_FILE_OUT} "XDG_DATA_DIRS=${DATADIR};{XDG_DATA_DIRS};" "${GNC_SYSTEM_XDG_DATA_DIRS}\n")
+  FILE(APPEND ${ENV_FILE_OUT} "XDG_DATA_DIRS=${CMAKE_INSTALL_DATADIR};{XDG_DATA_DIRS};" "${GNC_SYSTEM_XDG_DATA_DIRS}\n")
 ENDIF()
 
 FILE(APPEND ${BUILD_ENV_FILE_OUT} "GNC_DBD_DIR=${LIBDBI_DRIVERS_DIR}/dbd")
@@ -192,8 +192,9 @@ FILE(COPY ${ENV_FILE_OUT}
   FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
 )
 
-INSTALL(FILES ${SCRIPT_LIST} ${VALGRIND_OUTDIR}/gnucash-valgrind DESTINATION bin)
-INSTALL(FILES ${ENVIRONMENT_FILE_DIR}/environment DESTINATION etc/gnucash)
+INSTALL(FILES ${SCRIPT_LIST} ${VALGRIND_OUTDIR}/gnucash-valgrind DESTINATION ${CMAKE_INSTALL_BINDIR})
+INSTALL(FILES ${ENVIRONMENT_FILE_DIR}/environment DESTINATION
+  ${CMAKE_INSTALL_FULL_SYSCONFDIR}/gnucash)
 
 IF (WIN32)
   # Write out a command script for windows
@@ -234,7 +235,7 @@ IF (WIN32)
   ENDFOREACH(line)
   FILE(APPEND ${BUILD_CMD_FILE} "\nstart gnucash %*\n")
 
-  INSTALL(PROGRAMS ${CMD_FILE} DESTINATION bin)
+  INSTALL(PROGRAMS ${CMD_FILE} DESTINATION })
 ENDIF(WIN32)
 
 # The GResource Files are absolute paths but SET_LOCAL_DIST requires
diff --git a/gnucash/gnome-search/CMakeLists.txt b/gnucash/gnome-search/CMakeLists.txt
index 3695186..f754c17 100644
--- a/gnucash/gnome-search/CMakeLists.txt
+++ b/gnucash/gnome-search/CMakeLists.txt
@@ -53,15 +53,15 @@ TARGET_COMPILE_DEFINITIONS(gncmod-gnome-search PRIVATE -DG_LOG_DOMAIN=\"gnc.gui.
 TARGET_INCLUDE_DIRECTORIES(gncmod-gnome-search PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-gnome-search PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-gnome-search PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-gnome-search
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
-INSTALL(FILES ${gnome_search_HEADERS} DESTINATION include/gnucash)
+INSTALL(FILES ${gnome_search_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gnucash)
 
 SET(gnome_search_GLADE dialog-search.glade)
 
diff --git a/gnucash/gnome-utils/CMakeLists.txt b/gnucash/gnome-utils/CMakeLists.txt
index 084ecb2..4a8881e 100644
--- a/gnucash/gnome-utils/CMakeLists.txt
+++ b/gnucash/gnome-utils/CMakeLists.txt
@@ -233,15 +233,15 @@ TARGET_INCLUDE_DIRECTORIES(gncmod-gnome-utils
 
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-gnome-utils PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-gnome-utils PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-gnome-utils
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
-INSTALL(FILES ${gnome_utils_HEADERS} DESTINATION include/gnucash)
+INSTALL(FILES ${gnome_utils_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gnucash)
 
 
 # Scheme
diff --git a/gnucash/gnome/CMakeLists.txt b/gnucash/gnome/CMakeLists.txt
index b1c1670..5c939f0 100644
--- a/gnucash/gnome/CMakeLists.txt
+++ b/gnucash/gnome/CMakeLists.txt
@@ -156,9 +156,9 @@ ENDIF(MAC_INTEGRATION)
 
 
 INSTALL(TARGETS gnc-gnome
-  LIBRARY DESTINATION lib
-  ARCHIVE DESTINATION lib
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
 # No headers to install
 
diff --git a/gnucash/html/CMakeLists.txt b/gnucash/html/CMakeLists.txt
index 25a77d3..88f7afd 100644
--- a/gnucash/html/CMakeLists.txt
+++ b/gnucash/html/CMakeLists.txt
@@ -54,12 +54,12 @@ PUBLIC
 )
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-html PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-html PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-html
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
-INSTALL(FILES ${html_HEADERS} DESTINATION include/gnucash)
+INSTALL(FILES ${html_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gnucash)
diff --git a/gnucash/import-export/CMakeLists.txt b/gnucash/import-export/CMakeLists.txt
index 6e620ae..57808e1 100644
--- a/gnucash/import-export/CMakeLists.txt
+++ b/gnucash/import-export/CMakeLists.txt
@@ -65,16 +65,16 @@ TARGET_INCLUDE_DIRECTORIES(gncmod-generic-import PUBLIC ${CMAKE_CURRENT_SOURCE_D
 
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-generic-import PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-generic-import PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-generic-import
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
 )
 
-INSTALL(FILES ${generic_import_HEADERS} DESTINATION include/gnucash)
+INSTALL(FILES ${generic_import_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gnucash)
 
 SET(generic_import_GLADE dialog-import.glade)
 
diff --git a/gnucash/import-export/aqb/CMakeLists.txt b/gnucash/import-export/aqb/CMakeLists.txt
index 52c2ff5..06e7c26 100644
--- a/gnucash/import-export/aqb/CMakeLists.txt
+++ b/gnucash/import-export/aqb/CMakeLists.txt
@@ -70,13 +70,13 @@ IF(WITH_AQBANKING)
     ${KTOBLZCHECK_INCLUDE_DIRS})
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-aqbanking PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-aqbanking PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
   INSTALL(TARGETS gncmod-aqbanking
-    LIBRARY DESTINATION lib/gnucash
-    ARCHIVE DESTINATION lib/gnucash
-    RUNTIME DESTINATION bin)
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
 # No headers to install
 
diff --git a/gnucash/import-export/bi-import/CMakeLists.txt b/gnucash/import-export/bi-import/CMakeLists.txt
index ad6cf6c..e7a70a8 100644
--- a/gnucash/import-export/bi-import/CMakeLists.txt
+++ b/gnucash/import-export/bi-import/CMakeLists.txt
@@ -40,13 +40,13 @@ TARGET_INCLUDE_DIRECTORIES(gncmod-bi-import
 TARGET_COMPILE_DEFINITIONS(gncmod-bi-import PRIVATE -DG_LOG_DOMAIN=\"gnc.plugin.bi-import\")
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-bi-import PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-bi-import PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-bi-import
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 # No headers to install.
 
 SET_LOCAL_DIST(bi_import_DIST_local CMakeLists.txt Makefile.am README ${bi_import_SOURCES} ${bi_import_noinst_HEADERS})
diff --git a/gnucash/import-export/csv-exp/CMakeLists.txt b/gnucash/import-export/csv-exp/CMakeLists.txt
index 424efcf..dccaefa 100644
--- a/gnucash/import-export/csv-exp/CMakeLists.txt
+++ b/gnucash/import-export/csv-exp/CMakeLists.txt
@@ -26,13 +26,13 @@ TARGET_LINK_LIBRARIES(gncmod-csv-export gncmod-register-gnome gncmod-register-co
 TARGET_COMPILE_DEFINITIONS(gncmod-csv-export PRIVATE -DG_LOG_DOMAIN=\"gnc.export.csv\")
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-csv-export PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-csv-export PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-csv-export
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 # No headers to install.
 
 SET(csv_export_GLADE assistant-csv-export.glade)
diff --git a/gnucash/import-export/csv-imp/CMakeLists.txt b/gnucash/import-export/csv-imp/CMakeLists.txt
index e2fbb5e..0360e5d 100644
--- a/gnucash/import-export/csv-imp/CMakeLists.txt
+++ b/gnucash/import-export/csv-imp/CMakeLists.txt
@@ -73,13 +73,13 @@ TARGET_INCLUDE_DIRECTORIES(gncmod-csv-import PRIVATE
 )
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-csv-import PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-csv-import PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-csv-import
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
 # No headers to install
 
diff --git a/gnucash/import-export/customer-import/CMakeLists.txt b/gnucash/import-export/customer-import/CMakeLists.txt
index f7e8255..d209d0e 100644
--- a/gnucash/import-export/customer-import/CMakeLists.txt
+++ b/gnucash/import-export/customer-import/CMakeLists.txt
@@ -31,13 +31,13 @@ TARGET_INCLUDE_DIRECTORIES(gncmod-customer-import
 TARGET_COMPILE_DEFINITIONS(gncmod-customer-import PRIVATE -DG_LOG_DOMAIN=\"gnc.plugin.customer-import\")
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-customer-import PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-customer-import PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-customer-import
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 # No headers to install.
 
 SET_LOCAL_DIST(customer_import_DIST_local CMakeLists.txt Makefile.am ${customer_import_SOURCES} ${customer_import_noinst_HEADERS})
diff --git a/gnucash/import-export/log-replay/CMakeLists.txt b/gnucash/import-export/log-replay/CMakeLists.txt
index a0878b4..cea9116 100644
--- a/gnucash/import-export/log-replay/CMakeLists.txt
+++ b/gnucash/import-export/log-replay/CMakeLists.txt
@@ -21,13 +21,13 @@ TARGET_LINK_LIBRARIES(gncmod-log-replay gncmod-gnome-utils gncmod-app-utils gncm
 TARGET_COMPILE_DEFINITIONS(gncmod-log-replay PRIVATE -DG_LOG_DOMAIN=\"gnc.import.log-replay\")
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-log-replay PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-log-replay PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-log-replay
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 # No headers to install.
 
 SET(log_replay_UI gnc-plugin-log-replay-ui.xml)
diff --git a/gnucash/import-export/ofx/CMakeLists.txt b/gnucash/import-export/ofx/CMakeLists.txt
index 5484412..905b0fa 100644
--- a/gnucash/import-export/ofx/CMakeLists.txt
+++ b/gnucash/import-export/ofx/CMakeLists.txt
@@ -30,13 +30,13 @@ IF (WITH_OFX)
   TARGET_INCLUDE_DIRECTORIES(gncmod-ofx PRIVATE ${LIBOFX_INCLUDE_DIRS})
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-ofx PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-ofx PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
   INSTALL(TARGETS gncmod-ofx
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
   INSTALL(FILES ${ofx_UI} DESTINATION share/gnucash/ui)
 
diff --git a/gnucash/import-export/qif-imp/CMakeLists.txt b/gnucash/import-export/qif-imp/CMakeLists.txt
index 9c7e0e3..98cb79c 100644
--- a/gnucash/import-export/qif-imp/CMakeLists.txt
+++ b/gnucash/import-export/qif-imp/CMakeLists.txt
@@ -26,13 +26,13 @@ TARGET_LINK_LIBRARIES(gncmod-qif-import gncmod-app-utils gncmod-gnome-utils gnc-
 TARGET_COMPILE_DEFINITIONS(gncmod-qif-import PRIVATE -DG_LOG_DOMAIN=\"gnc.import.qif.import\")
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-qif-import PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-qif-import PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-qif-import
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 # No headers to install.
 
 
diff --git a/gnucash/import-export/qif/CMakeLists.txt b/gnucash/import-export/qif/CMakeLists.txt
index ae0fa02..65e54d7 100644
--- a/gnucash/import-export/qif/CMakeLists.txt
+++ b/gnucash/import-export/qif/CMakeLists.txt
@@ -30,13 +30,13 @@ TARGET_LINK_LIBRARIES(gncmod-qif gncmod-generic-import gncmod-engine ${GLIB2_LDF
 TARGET_COMPILE_DEFINITIONS(gncmod-qif PRIVATE -DG_LOG_DOMAIN=\"gnc.import.qif\")
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-qif PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-qif PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-qif
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 # No headers to install.
 
 SET_LOCAL_DIST(qif_DIST_local CMakeLists.txt Makefile.am ${qif_SOURCES} ${qif_noinst_HEADERS})
diff --git a/gnucash/overrides/CMakeLists.txt b/gnucash/overrides/CMakeLists.txt
index 3110352..620f6ea 100644
--- a/gnucash/overrides/CMakeLists.txt
+++ b/gnucash/overrides/CMakeLists.txt
@@ -28,5 +28,5 @@ INSTALL(
     PROGRAMS
       ${SCRIPT_OUTPUT_DIR}/gnucash-env
       ${SCRIPT_OUTPUT_DIR}/gnucash-make-guids
-    DESTINATION libexec/gnucash/overrides
+    DESTINATION }exec/gnucash/overrides
 )
diff --git a/gnucash/python/CMakeLists.txt b/gnucash/python/CMakeLists.txt
index 79d27ba..8028c65 100644
--- a/gnucash/python/CMakeLists.txt
+++ b/gnucash/python/CMakeLists.txt
@@ -11,9 +11,9 @@ IF (WITH_PYTHON)
     PRIVATE ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/core_utils ${CMAKE_SOURCE_DIR}/gnc-module ${PYTHON_INCLUDE_DIR})
   TARGET_COMPILE_OPTIONS(gncmod-python PRIVATE -DG_LOG_DOMAIN=\"gnc.python\")
   INSTALL(TARGETS gncmod-python
-    LIBRARY DESTINATION lib/gnucash
-    ARCHIVE DESTINATION lib/gnucash
-    RUNTIME DESTINATION bin
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
   )
 
   INSTALL(DIRECTORY pycons DESTINATION share/gnucash/python)
diff --git a/gnucash/register/ledger-core/CMakeLists.txt b/gnucash/register/ledger-core/CMakeLists.txt
index 6a663bb..5eed412 100644
--- a/gnucash/register/ledger-core/CMakeLists.txt
+++ b/gnucash/register/ledger-core/CMakeLists.txt
@@ -54,13 +54,13 @@ TARGET_INCLUDE_DIRECTORIES(gncmod-ledger-core
 )
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-ledger-core PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-ledger-core PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-ledger-core
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 # No headers to install
 
 
diff --git a/gnucash/register/register-core/CMakeLists.txt b/gnucash/register/register-core/CMakeLists.txt
index a001646..5d7a501 100644
--- a/gnucash/register/register-core/CMakeLists.txt
+++ b/gnucash/register/register-core/CMakeLists.txt
@@ -52,15 +52,15 @@ TARGET_COMPILE_DEFINITIONS (gncmod-register-core PRIVATE -DG_LOG_DOMAIN=\"gnc.re
 TARGET_INCLUDE_DIRECTORIES(gncmod-register-core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-register-core PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-register-core PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-register-core
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
-INSTALL(FILES ${register_core_HEADERS} DESTINATION include/gnucash)
+INSTALL(FILES ${register_core_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gnucash)
 
 SET_LOCAL_DIST(register_core_DIST_local CMakeLists.txt Makefile.am README ${register_core_SOURCES} ${register_core_HEADERS})
 
diff --git a/gnucash/register/register-gnome/CMakeLists.txt b/gnucash/register/register-gnome/CMakeLists.txt
index 2fa125a..3187abf 100644
--- a/gnucash/register/register-gnome/CMakeLists.txt
+++ b/gnucash/register/register-gnome/CMakeLists.txt
@@ -54,13 +54,13 @@ TARGET_INCLUDE_DIRECTORIES(gncmod-register-gnome
 )
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-register-gnome PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-register-gnome PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-register-gnome
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 # No headers to install
 
 SET_LOCAL_DIST(register_gnome_DIST_local CMakeLists.txt Makefile.am ${register_gnome_SOURCES} ${register_gnome_noinst_HEADERS})
diff --git a/gnucash/report/locale-specific/us/CMakeLists.txt b/gnucash/report/locale-specific/us/CMakeLists.txt
index 97f7211..afcf83c 100644
--- a/gnucash/report/locale-specific/us/CMakeLists.txt
+++ b/gnucash/report/locale-specific/us/CMakeLists.txt
@@ -13,13 +13,13 @@ TARGET_COMPILE_DEFINITIONS(gncmod-locale-reports-us PRIVATE -DG_LOG_DOMAIN=\"gnc
 
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-locale-reports-us PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-locale-reports-us PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-locale-reports-us
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 # No headers to install
 
 # Scheme
diff --git a/gnucash/report/report-gnome/CMakeLists.txt b/gnucash/report/report-gnome/CMakeLists.txt
index e2362e2..d95a57f 100644
--- a/gnucash/report/report-gnome/CMakeLists.txt
+++ b/gnucash/report/report-gnome/CMakeLists.txt
@@ -37,15 +37,15 @@ TARGET_COMPILE_DEFINITIONS (gncmod-report-gnome PRIVATE -DG_LOG_DOMAIN=\"gnc.rep
 TARGET_INCLUDE_DIRECTORIES(gncmod-report-gnome PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-report-gnome PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-report-gnome PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-report-gnome
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
-INSTALL(FILES ${report_gnome_HEADERS} DESTINATION include/gnucash)
+INSTALL(FILES ${report_gnome_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gnucash)
 
 # Scheme
 
diff --git a/gnucash/report/report-system/CMakeLists.txt b/gnucash/report/report-system/CMakeLists.txt
index a589284..19f4102 100644
--- a/gnucash/report/report-system/CMakeLists.txt
+++ b/gnucash/report/report-system/CMakeLists.txt
@@ -33,15 +33,15 @@ TARGET_INCLUDE_DIRECTORIES (gncmod-report-system
 
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-report-system PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-report-system PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-report-system
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
-INSTALL(FILES ${report_system_HEADERS} DESTINATION include/gnucash)
+INSTALL(FILES ${report_system_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gnucash)
 
 # Scheme
 
diff --git a/gnucash/report/stylesheets/CMakeLists.txt b/gnucash/report/stylesheets/CMakeLists.txt
index 8ca7325..33c69af 100644
--- a/gnucash/report/stylesheets/CMakeLists.txt
+++ b/gnucash/report/stylesheets/CMakeLists.txt
@@ -16,20 +16,20 @@ TARGET_LINK_LIBRARIES(gncmod-stylesheets gncmod-report-gnome gncmod-report-syste
 
 TARGET_COMPILE_DEFINITIONS(gncmod-stylesheets PRIVATE -DG_LOG_DOMAIN=\"gnc.report.core\")
 
-SET(LIB_DIR lib/gnucash)
+SET(LIB_DIR ${CMAKE_INSTALL_LIBDIR}/gnucash)
 IF (WIN32)
-  SET(LIB_DIR bin)
+  SET(LIB_DIR ${CMAKE_INSTALL_BINDIR})
 ENDIF(WIN32)
 
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-stylesheets PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-stylesheets PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-stylesheets
   LIBRARY DESTINATION ${LIB_DIR}
   ARCHIVE DESTINATION ${LIB_DIR}
-  RUNTIME DESTINATION bin)
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
 # No headers to install
 
diff --git a/libgnucash/app-utils/CMakeLists.txt b/libgnucash/app-utils/CMakeLists.txt
index db1507c..6107bf0 100644
--- a/libgnucash/app-utils/CMakeLists.txt
+++ b/libgnucash/app-utils/CMakeLists.txt
@@ -100,13 +100,13 @@ TARGET_INCLUDE_DIRECTORIES (gncmod-app-utils
 TARGET_COMPILE_DEFINITIONS (gncmod-app-utils PRIVATE -DG_LOG_DOMAIN=\"gnc.app-utils\")
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-app-utils PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-app-utils PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-app-utils
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
 )
 
 IF (WITH_PYTHON)
@@ -121,19 +121,19 @@ IF (WITH_PYTHON)
   TARGET_COMPILE_DEFINITIONS (gncmod-app-utils-python PRIVATE -DG_LOG_DOMAIN=\"gnc.app-utils\")
 
   IF (APPLE)
-    SET_TARGET_PROPERTIES (gncmod-app-utils-python PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+    SET_TARGET_PROPERTIES (gncmod-app-utils-python PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
   ENDIF()
 
   INSTALL(TARGETS gncmod-app-utils-python
-    LIBRARY DESTINATION lib/gnucash
-    ARCHIVE DESTINATION lib/gnucash
-    RUNTIME DESTINATION bin
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
   )
 ENDIF()
 
 
 
-INSTALL(FILES ${app_utils_HEADERS} DESTINATION include/gnucash)
+INSTALL(FILES ${app_utils_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gnucash)
 
 IF (WITH_OFX)
   FILE(READ ${CMAKE_SOURCE_DIR}/gnucash/import-export/ofx/migratable-prefs-ofx.xml MIGRATABLE_PREFS_OFX)
diff --git a/libgnucash/backend/dbi/CMakeLists.txt b/libgnucash/backend/dbi/CMakeLists.txt
index 6c8dbdf..4a43d31 100644
--- a/libgnucash/backend/dbi/CMakeLists.txt
+++ b/libgnucash/backend/dbi/CMakeLists.txt
@@ -41,11 +41,11 @@ TARGET_COMPILE_DEFINITIONS(gncmod-backend-dbi PRIVATE -DG_LOG_DOMAIN=\"gnc.backe
 TARGET_INCLUDE_DIRECTORIES(gncmod-backend-dbi PRIVATE ${LIBDBI_INCLUDE_PATH})
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-backend-dbi PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-backend-dbi PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_FULL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-backend-dbi
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 # No headers to install
diff --git a/libgnucash/backend/sql/CMakeLists.txt b/libgnucash/backend/sql/CMakeLists.txt
index 2bd6fa0..4659b0e 100644
--- a/libgnucash/backend/sql/CMakeLists.txt
+++ b/libgnucash/backend/sql/CMakeLists.txt
@@ -76,8 +76,8 @@ TARGET_COMPILE_DEFINITIONS (gnc-backend-sql PRIVATE -DG_LOG_DOMAIN=\"gnc.backend
 TARGET_INCLUDE_DIRECTORIES(gnc-backend-sql PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
 
 INSTALL(TARGETS gnc-backend-sql
-  LIBRARY DESTINATION lib
-  ARCHIVE DESTINATION lib
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
 # No headers to install
diff --git a/libgnucash/backend/xml/CMakeLists.txt b/libgnucash/backend/xml/CMakeLists.txt
index 4c3d8c9..e231f7a 100644
--- a/libgnucash/backend/xml/CMakeLists.txt
+++ b/libgnucash/backend/xml/CMakeLists.txt
@@ -92,9 +92,9 @@ TARGET_INCLUDE_DIRECTORIES (gnc-backend-xml-utils
 TARGET_COMPILE_DEFINITIONS (gnc-backend-xml-utils PRIVATE -DG_LOG_DOMAIN=\"gnc.backend.xml\" -DU_SHOW_CPLUSPLUS_API=0)
 
 INSTALL(TARGETS gnc-backend-xml-utils
-  LIBRARY DESTINATION lib
-  ARCHIVE DESTINATION lib
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 # No headers to install
 
 # ----
@@ -109,20 +109,20 @@ TARGET_LINK_LIBRARIES(gncmod-backend-xml gnc-backend-xml-utils gncmod-engine
 
 TARGET_COMPILE_DEFINITIONS (gncmod-backend-xml PRIVATE -DG_LOG_DOMAIN=\"gnc.backend.xml\" -DU_SHOW_CPLUSPLUS_API=0)
 
-SET(LIB_DIR lib/gnucash)
+SET(LIB_DIR ${CMAKE_INSTALL_LIBDIR}/gnucash)
 IF (WIN32)
-  SET(LIB_DIR bin)
+  SET(LIB_DIR ${CMAKE_INSTALL_BINDIR})
 ENDIF(WIN32)
 
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-backend-xml PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${LIB_DIR}")
+  SET_TARGET_PROPERTIES (gncmod-backend-xml PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_FULL_LIBDIR}")
 ENDIF()
 
 INSTALL(TARGETS gncmod-backend-xml
   LIBRARY DESTINATION ${LIB_DIR}
   ARCHIVE DESTINATION ${LIB_DIR}
-  RUNTIME DESTINATION bin)
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
 # ----
 
diff --git a/libgnucash/core-utils/CMakeLists.txt b/libgnucash/core-utils/CMakeLists.txt
index dd4ff00..52e1251 100644
--- a/libgnucash/core-utils/CMakeLists.txt
+++ b/libgnucash/core-utils/CMakeLists.txt
@@ -162,9 +162,9 @@ IF (MAC_INTEGRATION)
 ENDIF(MAC_INTEGRATION)
 
 INSTALL(TARGETS gnc-core-utils
-  LIBRARY DESTINATION lib
-  ARCHIVE DESTINATION lib
-  RUNTIME DESTINATION bin
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
 )
 
 IF (WITH_PYTHON)
@@ -184,9 +184,9 @@ IF (WITH_PYTHON)
   ENDIF(MAC_INTEGRATION)
 
   INSTALL(TARGETS gnc-core-utils-python
-    LIBRARY DESTINATION lib
-    ARCHIVE DESTINATION lib
-    RUNTIME DESTINATION bin
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
   )
 
 ENDIF()
diff --git a/libgnucash/engine/CMakeLists.txt b/libgnucash/engine/CMakeLists.txt
index b7f4fb0..b7dbd69 100644
--- a/libgnucash/engine/CMakeLists.txt
+++ b/libgnucash/engine/CMakeLists.txt
@@ -249,15 +249,15 @@ TARGET_INCLUDE_DIRECTORIES (gncmod-engine
 )
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-engine PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-engine PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_FULL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-engine
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
-INSTALL(FILES ${engine_HEADERS} DESTINATION include/gnucash)
+INSTALL(FILES ${engine_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gnucash)
 
 SET(qof_test_HEADERS
 kvp-frame.hpp
@@ -267,7 +267,7 @@ qofobject.h
 qofsession.h
 )
 
-INSTALL(FILES ${qof_test_HEADERS} DESTINATION libexec/gnucash/libgnucash/engine/test)
+INSTALL(FILES ${qof_test_HEADERS} DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/gnucash/libgnucash/engine/test)
 
 # Scheme
 
diff --git a/libgnucash/gnc-module/CMakeLists.txt b/libgnucash/gnc-module/CMakeLists.txt
index ae9bd03..c599e97 100644
--- a/libgnucash/gnc-module/CMakeLists.txt
+++ b/libgnucash/gnc-module/CMakeLists.txt
@@ -39,11 +39,11 @@ TARGET_INCLUDE_DIRECTORIES (gnc-module
 )
 
 INSTALL(TARGETS gnc-module
-  LIBRARY DESTINATION lib
-  ARCHIVE DESTINATION lib
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
-INSTALL(FILES ${gnc_module_HEADERS} DESTINATION include/gnucash)
+INSTALL(FILES ${gnc_module_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gnucash)
 
 # --- Compile Scheme file(s) ---
 
diff --git a/libgnucash/quotes/CMakeLists.txt b/libgnucash/quotes/CMakeLists.txt
index ed2ced8..21118ed 100644
--- a/libgnucash/quotes/CMakeLists.txt
+++ b/libgnucash/quotes/CMakeLists.txt
@@ -47,7 +47,7 @@ ENDFOREACH(file)
 ADD_CUSTOM_TARGET(quotes-man ALL DEPENDS ${_MAN_FILES})
 ADD_CUSTOM_TARGET(quotes-bin ALL DEPENDS gnc-fq-check gnc-fq-update)
 INSTALL(FILES ${_MAN_FILES} DESTINATION share/man/man1)
-INSTALL(PROGRAMS ${_BIN_FILES} DESTINATION bin)
+INSTALL(PROGRAMS ${_BIN_FILES} DESTINATION })
 
 SET_DIST_LIST(quotes_DIST CMakeLists.txt gnc-fq-check.in gnc-fq-dump gnc-fq-helper.in gnc-fq-update.in
         gnc-value-portfolio Makefile.am Quote_example.pl README)
diff --git a/libgnucash/scm/CMakeLists.txt b/libgnucash/scm/CMakeLists.txt
index 4d0aa5b..22165f8 100644
--- a/libgnucash/scm/CMakeLists.txt
+++ b/libgnucash/scm/CMakeLists.txt
@@ -52,7 +52,7 @@ GNC_ADD_SCHEME_TARGETS(scm-scm-3
 
 ADD_CUSTOM_TARGET(scm-scm ALL DEPENDS scm-scm-3 scm-scm-2 scm-scm-1 scm-scm-0 scm-gnumeric)
 
-INSTALL(FILES config DESTINATION etc/gnucash)
+INSTALL(FILES config DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/gnucash)
 
 SET_LOCAL_DIST(scm_DIST_local config CMakeLists.txt Makefile.am fin.scm string.scm build-config.scm.in substring-search.scm
                               xml-generator.scm main.scm price-quotes.scm printf.scm ${scm_SCHEME_4})
diff --git a/libgnucash/tax/us/CMakeLists.txt b/libgnucash/tax/us/CMakeLists.txt
index 83479bd..c25199b 100644
--- a/libgnucash/tax/us/CMakeLists.txt
+++ b/libgnucash/tax/us/CMakeLists.txt
@@ -12,13 +12,13 @@ TARGET_INCLUDE_DIRECTORIES(gncmod-tax-us
     PRIVATE ${CMAKE_BINARY_DIR}/common ${GUILE_INCLUDE_DIRS})
 
 IF (APPLE)
-  SET_TARGET_PROPERTIES (gncmod-tax-us PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/gnucash")
+  SET_TARGET_PROPERTIES (gncmod-tax-us PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}/gnucash")
 ENDIF()
 
 INSTALL(TARGETS gncmod-tax-us
-  LIBRARY DESTINATION lib/gnucash
-  ARCHIVE DESTINATION lib/gnucash
-  RUNTIME DESTINATION bin)
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/gnucash
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 # No headers to install
 
 # Scheme

commit e92a1b3723e7ddfa72d1fa40c6b3a79b7e1e19f7
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Nov 28 14:25:24 2017 -0800

    Fix python tests in tarball builds.

diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am
index 264c2cf..06e8e81 100644
--- a/bindings/python/Makefile.am
+++ b/bindings/python/Makefile.am
@@ -106,18 +106,25 @@ sqlite3test_SOURCES = sqlite3test.c
 sqlite3test_LDADD = ${_gnucash_core_c_la_LIBADD}
 sqlite3test_CPPFLAGS = ${_gnucash_core_c_la_CPPFLAGS}
 
-PYTHON_LINK_FILES = \
+PYTHON_GNUCASH_LINK_FILES = \
   $(pkgpyexec_DATA)
 
-.py-links:$(PYTHON_LINK_FILES)
+
+if BUILDING_FROM_VCS
+  PYTHON_LINK_FILES = $(filter-out gnucash_core_c.py,${PYTHON_GNUCASH_LINK_FILES})
+else
+  PYTHON_LINK_FILES = ${PYTHON_GNUCASH_LINK_FILES}
+endif
+
+.py-links:$(PYTHON_GNUCASH_LINK_FILES)
 	$(RM) -rf gnucash
 	mkdir -p gnucash
 if GNUCASH_SEPARATE_BUILDDIR
-	for X in $(filter-out gnucash_core_c.py,${PYTHON_LINK_FILES}) ; do \
-	  $(LN_S) -f ${srcdir}/$$X . ; \
+	for X in ${PYTHON_LINK_FILES} ; do \
+	    $(LN_S) -f ${srcdir}/$$X . ; \
 	done
 endif
-	( cd gnucash; for file in $(PYTHON_LINK_FILES) ; do \
+	( cd gnucash; for file in $(PYTHON_GNUCASH_LINK_FILES) ; do \
 	  $(LN_S) -f ../$$file .; \
 	  done )
 
diff --git a/bindings/python/tests/CMakeLists.txt b/bindings/python/tests/CMakeLists.txt
index d0a857a..ef38aa1 100644
--- a/bindings/python/tests/CMakeLists.txt
+++ b/bindings/python/tests/CMakeLists.txt
@@ -12,6 +12,7 @@ SET(test_python_bindings_DATA
         test_account.py
         test_book.py
         test_business.py
+        test_commodity.py
         test_split.py
         test_transaction.py)
 
diff --git a/common/test-core/CMakeLists.txt b/common/test-core/CMakeLists.txt
index 9d2e335..aa6e331 100644
--- a/common/test-core/CMakeLists.txt
+++ b/common/test-core/CMakeLists.txt
@@ -36,6 +36,7 @@ IF (BUILDING_FROM_VCS)
 ELSE()
   SET (SWIG_UNITTEST_SUPPORT_GUILE_C  swig-unittest-support-guile.c)
   SET (SWIG_UNITTEST_SUPPORT_PYTHON_C swig-unittest-support-python.c)
+  FILE(COPY unittest_support.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
 ENDIF()
 
 

commit 831640b546805ce2896ee6a5df3df7af428bc3c9
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Nov 28 09:53:06 2017 -0800

    Remove common/test-core/unittest_support.py from git.
    
    It's a SWIG-generated file accidentally added during directory
    rearrangement.

diff --git a/common/test-core/unittest_support.py b/common/test-core/unittest_support.py
deleted file mode 100644
index cdf7ecf..0000000
--- a/common/test-core/unittest_support.py
+++ /dev/null
@@ -1,166 +0,0 @@
-# This file was automatically generated by SWIG (http://www.swig.org).
-# Version 3.0.10
-#
-# Do not make changes to this file unless you know what you are doing--modify
-# the SWIG interface file instead.
-
-
-
-
-
-from sys import version_info as _swig_python_version_info
-if _swig_python_version_info >= (2, 7, 0):
-    def swig_import_helper():
-        import importlib
-        pkg = __name__.rpartition('.')[0]
-        mname = '.'.join((pkg, '_unittest_support')).lstrip('.')
-        try:
-            return importlib.import_module(mname)
-        except ImportError:
-            return importlib.import_module('_unittest_support')
-    _unittest_support = swig_import_helper()
-    del swig_import_helper
-elif _swig_python_version_info >= (2, 6, 0):
-    def swig_import_helper():
-        from os.path import dirname
-        import imp
-        fp = None
-        try:
-            fp, pathname, description = imp.find_module('_unittest_support', [dirname(__file__)])
-        except ImportError:
-            import _unittest_support
-            return _unittest_support
-        if fp is not None:
-            try:
-                _mod = imp.load_module('_unittest_support', fp, pathname, description)
-            finally:
-                fp.close()
-            return _mod
-    _unittest_support = swig_import_helper()
-    del swig_import_helper
-else:
-    import _unittest_support
-del _swig_python_version_info
-try:
-    _swig_property = property
-except NameError:
-    pass  # Python < 2.2 doesn't have 'property'.
-
-try:
-    import builtins as __builtin__
-except ImportError:
-    import __builtin__
-
-def _swig_setattr_nondynamic(self, class_type, name, value, static=1):
-    if (name == "thisown"):
-        return self.this.own(value)
-    if (name == "this"):
-        if type(value).__name__ == 'SwigPyObject':
-            self.__dict__[name] = value
-            return
-    method = class_type.__swig_setmethods__.get(name, None)
-    if method:
-        return method(self, value)
-    if (not static):
-        if _newclass:
-            object.__setattr__(self, name, value)
-        else:
-            self.__dict__[name] = value
-    else:
-        raise AttributeError("You cannot add attributes to %s" % self)
-
-
-def _swig_setattr(self, class_type, name, value):
-    return _swig_setattr_nondynamic(self, class_type, name, value, 0)
-
-
-def _swig_getattr(self, class_type, name):
-    if (name == "thisown"):
-        return self.this.own()
-    method = class_type.__swig_getmethods__.get(name, None)
-    if method:
-        return method(self)
-    raise AttributeError("'%s' object has no attribute '%s'" % (class_type.__name__, name))
-
-
-def _swig_repr(self):
-    try:
-        strthis = "proxy of " + self.this.__repr__()
-    except __builtin__.Exception:
-        strthis = ""
-    return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)
-
-try:
-    _object = object
-    _newclass = 1
-except __builtin__.Exception:
-    class _object:
-        pass
-    _newclass = 0
-
-class TestErrorStruct(_object):
-    __swig_setmethods__ = {}
-    __setattr__ = lambda self, name, value: _swig_setattr(self, TestErrorStruct, name, value)
-    __swig_getmethods__ = {}
-    __getattr__ = lambda self, name: _swig_getattr(self, TestErrorStruct, name)
-    __repr__ = _swig_repr
-    __swig_setmethods__["log_level"] = _unittest_support.TestErrorStruct_log_level_set
-    __swig_getmethods__["log_level"] = _unittest_support.TestErrorStruct_log_level_get
-    if _newclass:
-        log_level = _swig_property(_unittest_support.TestErrorStruct_log_level_get, _unittest_support.TestErrorStruct_log_level_set)
-    __swig_setmethods__["log_domain"] = _unittest_support.TestErrorStruct_log_domain_set
-    __swig_getmethods__["log_domain"] = _unittest_support.TestErrorStruct_log_domain_get
-    if _newclass:
-        log_domain = _swig_property(_unittest_support.TestErrorStruct_log_domain_get, _unittest_support.TestErrorStruct_log_domain_set)
-    __swig_setmethods__["msg"] = _unittest_support.TestErrorStruct_msg_set
-    __swig_getmethods__["msg"] = _unittest_support.TestErrorStruct_msg_get
-    if _newclass:
-        msg = _swig_property(_unittest_support.TestErrorStruct_msg_get, _unittest_support.TestErrorStruct_msg_set)
-
-    def __init__(self):
-        this = _unittest_support.new_TestErrorStruct()
-        try:
-            self.this.append(this)
-        except __builtin__.Exception:
-            self.this = this
-    __swig_destroy__ = _unittest_support.delete_TestErrorStruct
-    __del__ = lambda self: None
-TestErrorStruct_swigregister = _unittest_support.TestErrorStruct_swigregister
-TestErrorStruct_swigregister(TestErrorStruct)
-
-G_LOG_FLAG_RECURSION = _unittest_support.G_LOG_FLAG_RECURSION
-G_LOG_FLAG_FATAL = _unittest_support.G_LOG_FLAG_FATAL
-G_LOG_LEVEL_ERROR = _unittest_support.G_LOG_LEVEL_ERROR
-G_LOG_LEVEL_CRITICAL = _unittest_support.G_LOG_LEVEL_CRITICAL
-G_LOG_LEVEL_WARNING = _unittest_support.G_LOG_LEVEL_WARNING
-G_LOG_LEVEL_MESSAGE = _unittest_support.G_LOG_LEVEL_MESSAGE
-G_LOG_LEVEL_INFO = _unittest_support.G_LOG_LEVEL_INFO
-G_LOG_LEVEL_DEBUG = _unittest_support.G_LOG_LEVEL_DEBUG
-G_LOG_LEVEL_MASK = _unittest_support.G_LOG_LEVEL_MASK
-
-def test_add_error(error):
-    return _unittest_support.test_add_error(error)
-test_add_error = _unittest_support.test_add_error
-
-def test_clear_error_list():
-    return _unittest_support.test_clear_error_list()
-test_clear_error_list = _unittest_support.test_clear_error_list
-
-def test_set_checked_handler(domain, level, data):
-    return _unittest_support.test_set_checked_handler(domain, level, data)
-test_set_checked_handler = _unittest_support.test_set_checked_handler
-
-def test_set_list_handler(domain, level, data):
-    return _unittest_support.test_set_list_handler(domain, level, data)
-test_set_list_handler = _unittest_support.test_set_list_handler
-
-def test_set_null_handler(domain, level, data):
-    return _unittest_support.test_set_null_handler(domain, level, data)
-test_set_null_handler = _unittest_support.test_set_null_handler
-
-def g_log_remove_handler(log_domain, handler):
-    return _unittest_support.g_log_remove_handler(log_domain, handler)
-g_log_remove_handler = _unittest_support.g_log_remove_handler
-# This file is compatible with both classic and new-style classes.
-
-

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 50874d89daf42bea3f676bc5fa92e927375f10c0
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Nov 25 14:54:51 2017 -0800

    Correct GUILE_LOAD_COMPILE_PATH to include Guile's own modules as well as ours.

diff --git a/gnucash/environment.in b/gnucash/environment.in
index 86e817b..f8e3a1b 100644
--- a/gnucash/environment.in
+++ b/gnucash/environment.in
@@ -63,9 +63,8 @@ GUILE_WARN_DEPRECATED=no
 # GUILE_LIBS=
 # GUILE_COMPILED_LIBS=
 GUILE_LOAD_PATH={GNC_DATA}/scm;{GUILE_LIBS};{GUILE_LOAD_PATH}
-# Note the use of {SYS_LIB}/lib here instead of {GNC_LIB}. The latter points to
-# the wrong directory on Windows for this particular purpose.
-GUILE_LOAD_COMPILED_PATH={SYS_LIB}/gnucash/scm/ccache/@-GUILE_EFFECTIVE_VERSION-@;{GUILE_COMPILED_LIBS};{GUILE_LOAD_COMPILED_PATH}
+
+GUILE_LOAD_COMPILED_PATH={SYS_LIB}/guile/2.0/ccache;{GNC_LIB}ccache/@-GUILE_EFFECTIVE_VERSION-@;{GUILE_COMPILED_LIBS};{GUILE_LOAD_COMPILED_PATH}
 
 # Tell Guile where to find GnuCash specific shared libraries
 GNC_LIBRARY_PATH={SYS_LIB};{GNC_LIB}

commit d8c2f5244755b8162268077335c78df1449e9a48
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Nov 24 16:53:58 2017 -0800

    Correct quoting for SQL backends.
    
    Only string values should be quoted in queries; in particular NULL
    isn't a string value and must not be quoted.
    Note that this is a less than perfect solution because it doesn't use
    the Database's quoting function and so doesn't escape quotes, linefeeds,
    or carriage returns inside the string. That's because the SQL generating
    logic is independent of the connection class and can't easily get to it.

diff --git a/libgnucash/backend/dbi/gnc-dbisqlconnection.cpp b/libgnucash/backend/dbi/gnc-dbisqlconnection.cpp
index 0498439..a4172f4 100644
--- a/libgnucash/backend/dbi/gnc-dbisqlconnection.cpp
+++ b/libgnucash/backend/dbi/gnc-dbisqlconnection.cpp
@@ -73,8 +73,10 @@ GncDbiSqlStatement::add_where_cond(QofIdTypeConst type_name,
     {
         if (colpair != *col_values.begin())
             m_sql += " AND ";
-        m_sql += colpair.first + " = " +
-            m_conn->quote_string (colpair.second.c_str());
+        if (colpair.second == "NULL")
+            m_sql += colpair.first + " IS " + colpair.second;
+        else
+            m_sql += colpair.first + " = " + colpair.second;
     }
 }
 
diff --git a/libgnucash/backend/sql/gnc-address-sql.cpp b/libgnucash/backend/sql/gnc-address-sql.cpp
index 4ef7fc3..4445bef 100644
--- a/libgnucash/backend/sql/gnc-address-sql.cpp
+++ b/libgnucash/backend/sql/gnc-address-sql.cpp
@@ -138,7 +138,7 @@ GncSqlColumnTableEntryImpl<CT_ADDRESS>::add_to_query(QofIdTypeConst obj_name,
         if (s == nullptr)
             continue;
         auto buf = std::string{m_col_name} + "_" + subtable_row->m_col_name;
-        vec.emplace_back(make_pair(buf, std::string(s)));
+        vec.emplace_back(make_pair(buf, quote_string(s)));
     }
 }
 /* ========================== END OF FILE ===================== */
diff --git a/libgnucash/backend/sql/gnc-owner-sql.cpp b/libgnucash/backend/sql/gnc-owner-sql.cpp
index 2587689..2e862b2 100644
--- a/libgnucash/backend/sql/gnc-owner-sql.cpp
+++ b/libgnucash/backend/sql/gnc-owner-sql.cpp
@@ -224,12 +224,12 @@ GncSqlColumnTableEntryImpl<CT_OWNERREF>::add_to_query(QofIdTypeConst obj_name,
     std::ostringstream buf;
 
     buf << type;
-    vec.emplace_back(std::make_pair(type_hdr, buf.str()));
+    vec.emplace_back(std::make_pair(type_hdr, quote_string(buf.str())));
     buf.str("");
     auto guid = qof_instance_get_guid(inst);
     if (guid != nullptr)
         buf << guid_to_string(guid);
     else
         buf << "NULL";
-    vec.emplace_back(std::make_pair(guid_hdr, buf.str()));
+    vec.emplace_back(std::make_pair(guid_hdr, quote_string(buf.str())));
 }
diff --git a/libgnucash/backend/sql/gnc-sql-backend.cpp b/libgnucash/backend/sql/gnc-sql-backend.cpp
index 3af2d3e..0c7e6af 100644
--- a/libgnucash/backend/sql/gnc-sql-backend.cpp
+++ b/libgnucash/backend/sql/gnc-sql-backend.cpp
@@ -883,7 +883,7 @@ GncSqlBackend::build_insert_statement (const char* table_name,
     {
         if (col_value != *values.begin())
             sql << ",";
-        sql << quote_string(col_value.second);
+        sql << col_value.second;
     }
     sql << ")";
 
@@ -914,7 +914,7 @@ GncSqlBackend::build_update_statement(const gchar* table_name,
         if (col_value != *values.begin())
             sql << ",";
         sql << col_value.first << "=" <<
-            quote_string(col_value.second);
+            col_value.second;
     }
 
     stmt = create_statement_from_sql(sql.str());
diff --git a/libgnucash/backend/sql/gnc-sql-column-table-entry.cpp b/libgnucash/backend/sql/gnc-sql-column-table-entry.cpp
index 3f3bf52..7a0548c 100644
--- a/libgnucash/backend/sql/gnc-sql-column-table-entry.cpp
+++ b/libgnucash/backend/sql/gnc-sql-column-table-entry.cpp
@@ -50,6 +50,7 @@ set_autoinc_id (void* object, void* item)
     // Nowhere to put the ID
 }
 
+
 QofAccessFunc
 GncSqlColumnTableEntry::get_getter (QofIdTypeConst obj_name) const noexcept
 {
@@ -103,7 +104,7 @@ GncSqlColumnTableEntry::add_objectref_guid_to_query (QofIdTypeConst obj_name,
     auto guid = qof_instance_get_guid (inst);
     if (guid != nullptr)
         vec.emplace_back (std::make_pair (std::string{m_col_name},
-                                          std::string{guid_to_string(guid)}));
+                                          quote_string(guid_to_string(guid))));
 }
 
 void
@@ -153,7 +154,8 @@ GncSqlColumnTableEntryImpl<CT_STRING>::add_to_query(QofIdTypeConst obj_name,
     {
         std::ostringstream stream;
         stream << s;
-        vec.emplace_back (std::make_pair (std::string{m_col_name}, stream.str()));
+        vec.emplace_back (std::make_pair (std::string{m_col_name},
+                                          quote_string(stream.str())));
         return;
     }
 }
@@ -360,7 +362,7 @@ GncSqlColumnTableEntryImpl<CT_GUID>::add_to_query(QofIdTypeConst obj_name,
     {
 
         vec.emplace_back (std::make_pair (std::string{m_col_name},
-                                          std::string{guid_to_string(s)}));
+                                          quote_string(guid_to_string(s))));
         return;
     }
 }
@@ -467,7 +469,7 @@ GncSqlColumnTableEntryImpl<CT_TIMESPEC>::add_to_query(QofIdTypeConst obj_name,
 
     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")));
+                                      time.format_zulu ("'%Y-%m-%d %H:%M:%S'")));
 }
 
 /* ----------------------------------------------------------------- */
@@ -539,7 +541,8 @@ GncSqlColumnTableEntryImpl<CT_GDATE>::add_to_query(QofIdTypeConst obj_name,
         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}, buf.str()));
+        vec.emplace_back (std::make_pair (std::string{m_col_name},
+                                          quote_string(buf.str())));
         return;
     }
 }
diff --git a/libgnucash/backend/sql/gnc-sql-column-table-entry.hpp b/libgnucash/backend/sql/gnc-sql-column-table-entry.hpp
index d86fbfc..28fbb64 100644
--- a/libgnucash/backend/sql/gnc-sql-column-table-entry.hpp
+++ b/libgnucash/backend/sql/gnc-sql-column-table-entry.hpp
@@ -30,6 +30,7 @@ extern "C"
 }
 #include <memory>
 #include <vector>
+#include <iostream>
 #include "gnc-sql-result.hpp"
 
 struct GncSqlColumnInfo;
@@ -86,6 +87,27 @@ enum GncSqlObjectType
     CT_TAXTABLEREF
 };
 
+static inline std::string
+quote_string(const std::string& str)
+{
+    if (str == "NULL" || str == "null") return "NULL";
+    /* FIXME: This is here because transactions.num has a NULL
+     * constraint, which is dumb; it's often empty.
+     */
+    if (str.empty()) return "''";
+    std::string retval;
+    retval.reserve(str.length() + 2);
+    retval.insert(0, 1, '\'');
+    for (auto c = str.begin(); c != str.end(); ++c)
+    {
+        if (*c == '\'')
+            retval += *c;
+        retval += *c;
+    }
+    retval += '\'';
+    return retval;
+}
+
 /**
  * Contains all of the information required to copy information between an
  * object and the database for a specific object property.

commit 037c93faea77f51a36d7391d0f3ef403b5036843
Merge: 1e81d3a 22e7e1b
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Fri Nov 24 17:24:52 2017 +0100

    Merge branch 'gtk3-update8' of https://github.com/Bob-IT/gnucash into unstable


commit 1e81d3ace27fd32f7a4b61ae2aaa45c7dfffa92e
Author: Jose Marino <jmarino at users.noreply.github.com>
Date:   Tue Nov 21 16:53:10 2017 -0700

    report: fix default colors incorrectly set to transparent
    
    The default color of a color option is set during a call to "gnc:make-color-option"
    as a list of rgba values. In all color option instances in the scheme code this
    default color is incorrectly set to transparent.
    For example, white color was being set with:
      (list #xff #xff #xff 0)
    The last value in the list is the value of the alpha channel, with 0 meaning
    transparent. When the color button is displayed in the gui it shows a checkerboard
    pattern instead of the intended color.
    
    This commit changes all default colors of color options to have alpha=#xff, i.e.,
    fully opaque.

diff --git a/gnucash/report/report-system/doc/report-html.txt b/gnucash/report/report-system/doc/report-html.txt
index 99899fa..35f4341 100644
--- a/gnucash/report/report-system/doc/report-html.txt
+++ b/gnucash/report/report-system/doc/report-html.txt
@@ -363,7 +363,7 @@ We have three different kinds of style control information available:
             (gnc:make-color-option
               (_ "Style Sheet Options")
 	      (_ "Background Color") "a" (_ "Background color for reports.")
-	      (list #xff #xff #xff 0)
+	      (list #xff #xff #xff #xff)
 	      255 #f))
           options))
 
diff --git a/gnucash/report/standard-reports/price-scatter.scm b/gnucash/report/standard-reports/price-scatter.scm
index 551a6fb..5df439d 100644
--- a/gnucash/report/standard-reports/price-scatter.scm
+++ b/gnucash/report/standard-reports/price-scatter.scm
@@ -118,7 +118,7 @@
       gnc:pagename-display optname-markercolor
       "b"
       (N_ "Color of the marker.")
-      (list #xb2 #x22 #x22 0)
+      (list #xb2 #x22 #x22 #xff)
       255 #f))
 
     (gnc:options-set-default-section options gnc:pagename-general)
diff --git a/gnucash/report/stylesheets/stylesheet-easy.scm b/gnucash/report/stylesheets/stylesheet-easy.scm
index 25be3d9..38e7fb6 100644
--- a/gnucash/report/stylesheets/stylesheet-easy.scm
+++ b/gnucash/report/stylesheets/stylesheet-easy.scm
@@ -101,28 +101,28 @@
      (gnc:make-color-option
       (N_ "Colors")
       (N_ "Background Color") "a" (N_ "General background color for report.")
-      (list #xff #xff #xff 0)
+      (list #xff #xff #xff #xff)
       255 #f))      
 
     (opt-register
      (gnc:make-color-option
       (N_ "Colors")
       (N_ "Text Color") "b" (N_ "Normal body text color.")
-      (list #x00 #x00 #x00 0)
+      (list #x00 #x00 #x00 #xff)
       255 #f))      
 
     (opt-register
      (gnc:make-color-option
       (N_ "Colors")
       (N_ "Link Color") "c" (N_ "Link text color.")
-      (list #xb2 #x22 #x22 0)
+      (list #xb2 #x22 #x22 #xff)
       255 #f))
 
     (opt-register
      (gnc:make-color-option
       (N_ "Colors")
       (N_ "Table Cell Color") "c" (N_ "Default background for table cells.")
-      (list #xff #xff #xff 0)
+      (list #xff #xff #xff #xff)
       255 #f))      
 
     (opt-register
@@ -130,7 +130,7 @@
       (N_ "Colors")
       (N_ "Alternate Table Cell Color") "d"
       (N_ "Default alternate background for table cells.")
-      (list #xff #xff #xff 0)
+      (list #xff #xff #xff #xff)
       255 #f))
 
     (opt-register
@@ -138,7 +138,7 @@
       (N_ "Colors")
       (N_ "Subheading/Subtotal Cell Color") "e"
       (N_ "Default color for subtotal rows.")
-      (list #xee #xe8 #xaa 0)
+      (list #xee #xe8 #xaa #xff)
       255 #f))
 
     (opt-register
@@ -146,7 +146,7 @@
       (N_ "Colors")
       (N_ "Sub-subheading/total Cell Color") "f"
       (N_ "Color for subsubtotals.")
-      (list #xfa #xfa #xd2 0)
+      (list #xfa #xfa #xd2 #xff)
       255 #f))
 
     (opt-register
@@ -154,7 +154,7 @@
       (N_ "Colors")
       (N_ "Grand Total Cell Color") "g"
       (N_ "Color for grand totals.")
-      (list #xff #xff #x00 0)
+      (list #xff #xff #x00 #xff)
       255 #f))
 
     (opt-register 
diff --git a/gnucash/report/stylesheets/stylesheet-fancy.scm b/gnucash/report/stylesheets/stylesheet-fancy.scm
index a4b4bc8..eebdc3a 100644
--- a/gnucash/report/stylesheets/stylesheet-fancy.scm
+++ b/gnucash/report/stylesheets/stylesheet-fancy.scm
@@ -95,28 +95,28 @@
      (gnc:make-color-option
       (N_ "Colors")
       (N_ "Background Color") "a" (N_ "General background color for report.")
-      (list #xff #xff #xff 0)
+      (list #xff #xff #xff #xff)
       255 #f))      
 
     (opt-register
      (gnc:make-color-option
       (N_ "Colors")
       (N_ "Text Color") "b" (N_ "Normal body text color.")
-      (list #x00 #x00 #x00 0)
+      (list #x00 #x00 #x00 #xff)
       255 #f))      
 
     (opt-register
      (gnc:make-color-option
       (N_ "Colors")
       (N_ "Link Color") "c" (N_ "Link text color.")
-      (list #xb2 #x22 #x22 0)
+      (list #xb2 #x22 #x22 #xff)
       255 #f))
 
     (opt-register
      (gnc:make-color-option
       (N_ "Colors")
       (N_ "Table Cell Color") "c" (N_ "Default background for table cells.")
-      (list #xff #xff #xff 0)
+      (list #xff #xff #xff #xff)
       255 #f))      
 
     (opt-register
@@ -124,7 +124,7 @@
       (N_ "Colors")
       (N_ "Alternate Table Cell Color") "d"
       (N_ "Default alternate background for table cells.")
-      (list #xff #xff #xff 0)
+      (list #xff #xff #xff #xff)
       255 #f))
 
     (opt-register
@@ -132,7 +132,7 @@
       (N_ "Colors")
       (N_ "Subheading/Subtotal Cell Color") "e"
       (N_ "Default color for subtotal rows.")
-      (list #xee #xe8 #xaa 0)
+      (list #xee #xe8 #xaa #xff)
       255 #f))
 
     (opt-register
@@ -140,7 +140,7 @@
       (N_ "Colors")
       (N_ "Sub-subheading/total Cell Color") "f"
       (N_ "Color for subsubtotals.")
-      (list #xfa #xfa #xd2 0)
+      (list #xfa #xfa #xd2 #xff)
       255 #f))
 
     (opt-register
@@ -148,7 +148,7 @@
       (N_ "Colors")
       (N_ "Grand Total Cell Color") "g"
       (N_ "Color for grand totals.")
-      (list #xff #xff #x00 0)
+      (list #xff #xff #x00 #xff)
       255 #f))
 
     (opt-register 
diff --git a/gnucash/report/stylesheets/stylesheet-footer.scm b/gnucash/report/stylesheets/stylesheet-footer.scm
index 5192bab..59c3fb6 100644
--- a/gnucash/report/stylesheets/stylesheet-footer.scm
+++ b/gnucash/report/stylesheets/stylesheet-footer.scm
@@ -114,28 +114,28 @@
      (gnc:make-color-option
       (N_ "Colors")
       (N_ "Background Color") "a" (N_ "General background color for report.")
-      (list #xff #xff #xff 0)
+      (list #xff #xff #xff #xff)
       255 #f))      
 
     (opt-register
      (gnc:make-color-option
       (N_ "Colors")
       (N_ "Text Color") "b" (N_ "Normal body text color.")
-      (list #x00 #x00 #x00 0)
+      (list #x00 #x00 #x00 #xff)
       255 #f))      
 
     (opt-register
      (gnc:make-color-option
       (N_ "Colors")
       (N_ "Link Color") "c" (N_ "Link text color.")
-      (list #xb2 #x22 #x22 0)
+      (list #xb2 #x22 #x22 #xff)
       255 #f))
 
     (opt-register
      (gnc:make-color-option
       (N_ "Colors")
       (N_ "Table Cell Color") "c" (N_ "Default background for table cells.")
-      (list #xff #xff #xff 0)
+      (list #xff #xff #xff #xff)
       255 #f))      
 
     (opt-register
@@ -143,7 +143,7 @@
       (N_ "Colors")
       (N_ "Alternate Table Cell Color") "d"
       (N_ "Default alternate background for table cells.")
-      (list #xff #xff #xff 0)
+      (list #xff #xff #xff #xff)
       255 #f))
 
     (opt-register
@@ -151,7 +151,7 @@
       (N_ "Colors")
       (N_ "Subheading/Subtotal Cell Color") "e"
       (N_ "Default color for subtotal rows.")
-      (list #xee #xe8 #xaa 0)
+      (list #xee #xe8 #xaa #xff)
       255 #f))
 
     (opt-register
@@ -159,7 +159,7 @@
       (N_ "Colors")
       (N_ "Sub-subheading/total Cell Color") "f"
       (N_ "Color for subsubtotals.")
-      (list #xfa #xfa #xd2 0)
+      (list #xfa #xfa #xd2 #xff)
       255 #f))
 
     (opt-register
@@ -167,7 +167,7 @@
       (N_ "Colors")
       (N_ "Grand Total Cell Color") "g"
       (N_ "Color for grand totals.")
-      (list #xff #xff #x00 0)
+      (list #xff #xff #x00 #xff)
       255 #f))
 
     (opt-register 
diff --git a/gnucash/report/stylesheets/stylesheet-head-or-tail.scm b/gnucash/report/stylesheets/stylesheet-head-or-tail.scm
index b264982..e31cb46 100644
--- a/gnucash/report/stylesheets/stylesheet-head-or-tail.scm
+++ b/gnucash/report/stylesheets/stylesheet-head-or-tail.scm
@@ -170,28 +170,28 @@
      (gnc:make-color-option
       (N_ "Colors")
       (N_ "Background Color") "a" (N_ "General background color for report.")
-      (list #xff #xff #xff 0)
+      (list #xff #xff #xff #xff)
       255 #f))
 
     (opt-register
      (gnc:make-color-option
       (N_ "Colors")
       (N_ "Text Color") "b" (N_ "Normal body text color.")
-      (list #x00 #x00 #x00 0)
+      (list #x00 #x00 #x00 #xff)
       255 #f))
 
     (opt-register
      (gnc:make-color-option
       (N_ "Colors")
       (N_ "Link Color") "c" (N_ "Link text color.")
-      (list #xb2 #x22 #x22 0)
+      (list #xb2 #x22 #x22 #xff)
       255 #f))
 
     (opt-register
      (gnc:make-color-option
       (N_ "Colors")
       (N_ "Table Cell Color") "c" (N_ "Default background for table cells.")
-      (list #xff #xff #xff 0)
+      (list #xff #xff #xff #xff)
       255 #f))
 
     (opt-register
@@ -199,7 +199,7 @@
       (N_ "Colors")
       (N_ "Alternate Table Cell Color") "d"
       (N_ "Default alternate background for table cells.")
-      (list #xff #xff #xff 0)
+      (list #xff #xff #xff #xff)
       255 #f))
 
     (opt-register
@@ -207,7 +207,7 @@
       (N_ "Colors")
       (N_ "Subheading/Subtotal Cell Color") "e"
       (N_ "Default color for subtotal rows.")
-      (list #xee #xe8 #xaa 0)
+      (list #xee #xe8 #xaa #xff)
       255 #f))
 
     (opt-register
@@ -215,7 +215,7 @@
       (N_ "Colors")
       (N_ "Sub-subheading/total Cell Color") "f"
       (N_ "Color for subsubtotals.")
-      (list #xfa #xfa #xd2 0)
+      (list #xfa #xfa #xd2 #xff)
       255 #f))
 
     (opt-register
@@ -223,7 +223,7 @@
       (N_ "Colors")
       (N_ "Grand Total Cell Color") "g"
       (N_ "Color for grand totals.")
-      (list #xff #xff #x00 0)
+      (list #xff #xff #x00 #xff)
       255 #f))
 
     (opt-register
diff --git a/gnucash/report/stylesheets/stylesheet-plain.scm b/gnucash/report/stylesheets/stylesheet-plain.scm
index d5d6f6e..12cc747 100644
--- a/gnucash/report/stylesheets/stylesheet-plain.scm
+++ b/gnucash/report/stylesheets/stylesheet-plain.scm
@@ -46,7 +46,7 @@
           (gnc:make-color-option
            (N_ "General")
            (N_ "Background Color") "a" (N_ "Background color for reports.")
-           (list #xff #xff #xff 0)
+           (list #xff #xff #xff #xff)
            255 #f))
          (opt-register
           (gnc:make-pixmap-option
@@ -62,7 +62,7 @@
           (gnc:make-color-option
            (N_ "Colors")
            (N_ "Alternate Table Cell Color") "a" (N_ "Background color for alternate lines.")
-           (list #xff #xff #xff 0)
+           (list #xff #xff #xff #xff)
            255 #f))
          (opt-register
           (gnc:make-number-range-option
diff --git a/gnucash/report/utility-reports/hello-world.scm b/gnucash/report/utility-reports/hello-world.scm
index ad8c5a1..bbabfdd 100644
--- a/gnucash/report/utility-reports/hello-world.scm
+++ b/gnucash/report/utility-reports/hello-world.scm
@@ -159,14 +159,14 @@
      (gnc:make-color-option
       (N_ "Hello, World!") (N_ "Background Color")
       "f" (N_ "This is a color option.")
-      (list #xf6 #xff #xdb 0)
+      (list #xf6 #xff #xdb #xff)
       255
       #f))
     (add-option
      (gnc:make-color-option
       (N_ "Hello, World!") (N_ "Text Color")
       "f" (N_ "This is a color option.")
-      (list #x00 #x00 #x00 0)
+      (list #x00 #x00 #x00 #xff)
       255
       #f))
     

commit 9c4635e3930f6026080cf18ea7ca92133733c944
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Nov 23 11:41:09 2017 -0800

    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.

diff --git a/libgnucash/backend/dbi/gnc-dbiproviderimpl.hpp b/libgnucash/backend/dbi/gnc-dbiproviderimpl.hpp
index 47795f9..32f3ec6 100644
--- a/libgnucash/backend/dbi/gnc-dbiproviderimpl.hpp
+++ b/libgnucash/backend/dbi/gnc-dbiproviderimpl.hpp
@@ -130,7 +130,7 @@ GncDbiProviderImpl<DbType::DBI_MYSQL>::append_col_def (std::string& ddl,
     }
     else if (info.m_type == BCT_DATETIME)
     {
-        type_name = "TIMESTAMP NULL DEFAULT 0";
+        type_name = "DATETIME NULL DEFAULT '1970-01-01 00:00:00'";
     }
     else
     {
diff --git a/libgnucash/backend/sql/gnc-entry-sql.cpp b/libgnucash/backend/sql/gnc-entry-sql.cpp
index c8be0d9..9beb95b 100644
--- a/libgnucash/backend/sql/gnc-entry-sql.cpp
+++ b/libgnucash/backend/sql/gnc-entry-sql.cpp
@@ -57,7 +57,7 @@ extern "C"
 static QofLogModule log_module = G_LOG_DOMAIN;
 
 #define TABLE_NAME "entries"
-#define TABLE_VERSION 3
+#define TABLE_VERSION 4
 #define MAX_DESCRIPTION_LEN 2048
 #define MAX_ACTION_LEN 2048
 #define MAX_NOTES_LEN 2048
@@ -226,6 +226,7 @@ GncSqlEntryBackend::create_tables (GncSqlBackend* sql_be)
         /* Upgrade:
             1->2: 64 bit int handling
             2->3: "entered" -> "date_entered", and it can be NULL
+            3->4: Use DATETIME instead of TIMESTAMP in MySQL
         */
         sql_be->upgrade_table(TABLE_NAME, col_table);
         sql_be->set_table_version (TABLE_NAME, TABLE_VERSION);
diff --git a/libgnucash/backend/sql/gnc-invoice-sql.cpp b/libgnucash/backend/sql/gnc-invoice-sql.cpp
index 5cfffad..769aa2d 100644
--- a/libgnucash/backend/sql/gnc-invoice-sql.cpp
+++ b/libgnucash/backend/sql/gnc-invoice-sql.cpp
@@ -56,7 +56,7 @@ extern "C"
 static QofLogModule log_module = G_LOG_DOMAIN;
 
 #define TABLE_NAME "invoices"
-#define TABLE_VERSION 3
+#define TABLE_VERSION 4
 
 #define MAX_ID_LEN 2048
 #define MAX_NOTES_LEN 2048
@@ -164,6 +164,7 @@ GncSqlInvoiceBackend::create_tables (GncSqlBackend* sql_be)
         /* Upgrade:
              1->2: 64 bit int handling
              2->3: invoice open date can be NULL
+             3->4: Use DATETIME instead of TIMESTAMP in MySQL
         */
         sql_be->upgrade_table(TABLE_NAME, col_table);
         sql_be->set_table_version (TABLE_NAME, TABLE_VERSION);
diff --git a/libgnucash/backend/sql/gnc-price-sql.cpp b/libgnucash/backend/sql/gnc-price-sql.cpp
index eaf99eb..f2cc188 100644
--- a/libgnucash/backend/sql/gnc-price-sql.cpp
+++ b/libgnucash/backend/sql/gnc-price-sql.cpp
@@ -51,7 +51,7 @@ extern "C"
 static QofLogModule log_module = G_LOG_DOMAIN;
 
 #define TABLE_NAME "prices"
-#define TABLE_VERSION 2
+#define TABLE_VERSION 3
 
 #define PRICE_MAX_SOURCE_LEN 2048
 #define PRICE_MAX_TYPE_LEN 2048
@@ -148,7 +148,10 @@ GncSqlPriceBackend::create_tables (GncSqlBackend* sql_be)
     }
     else if (version < m_version)
     {
-        /* Upgrade 64 bit int handling */
+        /*
+          1->2: Upgrade 64 bit int handling
+          2->3: Use DATETIME instead of TIMESTAMP in MySQL
+        */
         sql_be->upgrade_table(TABLE_NAME, col_table);
         sql_be->set_table_version (TABLE_NAME, TABLE_VERSION);
 
diff --git a/libgnucash/backend/sql/gnc-slots-sql.cpp b/libgnucash/backend/sql/gnc-slots-sql.cpp
index 7cd80fd..8b35b27 100644
--- a/libgnucash/backend/sql/gnc-slots-sql.cpp
+++ b/libgnucash/backend/sql/gnc-slots-sql.cpp
@@ -54,7 +54,7 @@ extern "C"
 static QofLogModule log_module = G_LOG_DOMAIN;
 
 #define TABLE_NAME "slots"
-#define TABLE_VERSION 3
+#define TABLE_VERSION 4
 
 typedef enum
 {
@@ -958,11 +958,12 @@ GncSqlSlotsBackend::create_tables (GncSqlBackend* sql_be)
             PERR ("Unable to create index\n");
         }
     }
-    else if (version < TABLE_VERSION)
+    else if (version < m_version)
     {
         /* Upgrade:
             1->2: 64-bit int values to proper definition, add index
             2->3: Add gdate field
+            3->4: Use DATETIME instead of TIMESTAMP in MySQL
         */
         if (version == 1)
         {
@@ -982,7 +983,7 @@ GncSqlSlotsBackend::create_tables (GncSqlBackend* sql_be)
                 PERR ("Unable to add gdate column\n");
             }
         }
-        else if (version < m_version)
+        else
         {
             sql_be->upgrade_table(TABLE_NAME, col_table);
         }
diff --git a/libgnucash/backend/sql/gnc-transaction-sql.cpp b/libgnucash/backend/sql/gnc-transaction-sql.cpp
index e3ff00f..266d356 100644
--- a/libgnucash/backend/sql/gnc-transaction-sql.cpp
+++ b/libgnucash/backend/sql/gnc-transaction-sql.cpp
@@ -69,7 +69,7 @@ extern "C"
 static QofLogModule log_module = G_LOG_DOMAIN;
 
 #define TRANSACTION_TABLE "transactions"
-#define TX_TABLE_VERSION 3
+#define TX_TABLE_VERSION 4
 #define SPLIT_TABLE "splits"
 #define SPLIT_TABLE_VERSION 4
 
@@ -481,6 +481,7 @@ GncSqlTransBackend::create_tables (GncSqlBackend* sql_be)
         /* Upgrade:
             1->2: 64 bit int handling
             2->3: allow dates to be NULL
+            3->4: Use DATETIME instead of TIMESTAMP in MySQL
         */
         sql_be->upgrade_table(m_table_name.c_str(), tx_col_table);
         sql_be->set_table_version (m_table_name.c_str(), m_version);

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 22e7e1b440bd9d6925ab545a6ad1128c25b13ffa
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Thu Nov 23 13:57:10 2017 +0000

    Fix some corrupted glade files

diff --git a/gnucash/gnome-utils/gtkbuilder/dialog-preferences.glade b/gnucash/gnome-utils/gtkbuilder/dialog-preferences.glade
index ce06a8f..3b44403 100644
--- a/gnucash/gnome-utils/gtkbuilder/dialog-preferences.glade
+++ b/gnucash/gnome-utils/gtkbuilder/dialog-preferences.glade
@@ -1,5 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
-<?xml version="1.0" encoding="utf-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
 <!-- Generated with glade 3.20.0 -->
 <interface>
@@ -1128,8 +1126,7 @@ many months before the current month:</property>
                   <object class="GtkLabel" id="label50">
                     <property name="visible">True</property>
                     <property name="halign">start</property>
-                    <property name="label" translatable="yes"><b>General</b></property>
-                    <property name="label" translatable="yes"><b>General</b></property>
+                    <property name="label" translatable="yes" comments="Preferences Dialog, General Tab"><b>General</b></property>
                     <property name="use_markup">True</property>
                   </object>
                   <packing>
@@ -1618,8 +1615,7 @@ many months before the current month:</property>
                     <property name="visible">True</property>
                     <property name="halign">start</property>
                     <property name="margin_left">12</property>
-                    <property name="label" translatable="yes">Time to wait for answer:</property>
-                    <property name="label" translatable="yes">Time to wait for answer:</property>
+                    <property name="label" translatable="yes">Time to _wait for answer:</property>
                     <property name="use_underline">True</property>
                     <property name="mnemonic_widget">pref/general/autosave-interval-minutes</property>
                   </object>
@@ -2526,8 +2522,7 @@ many months before the current month:</property>
                     <property name="visible">True</property>
                     <property name="halign">start</property>
                     <property name="margin_left">12</property>
-                    <property name="label" translatable="yes">Number of _characters for auto complete:</property>
-                    <property name="label" translatable="yes">Number of _characters for auto complete:</property>
+                    <property name="label" translatable="yes" comments="Register2 feature">Number of _characters for auto complete:</property>
                     <property name="use_underline">True</property>
                     <property name="mnemonic_widget">pref/general.register/key-length</property>
                   </object>
@@ -2566,7 +2561,6 @@ many months before the current month:</property>
                     <property name="tooltip_text" translatable="yes">Show the date when the transaction was entered below the posted date and reconciled date on split row.</property>
                     <property name="halign">start</property>
                     <property name="margin_left">12</property>
-                    <property name="margin_left">12</property>
                     <property name="use_underline">True</property>
                     <property name="draw_indicator">True</property>
                   </object>
@@ -2584,7 +2578,6 @@ many months before the current month:</property>
                     <property name="tooltip_text" translatable="yes">Show the calendar buttons Cancel, Today and Select.</property>
                     <property name="halign">start</property>
                     <property name="margin_left">12</property>
-                    <property name="margin_left">12</property>
                     <property name="use_underline">True</property>
                     <property name="draw_indicator">True</property>
                   </object>
@@ -2602,7 +2595,6 @@ many months before the current month:</property>
                     <property name="tooltip_text" translatable="yes">This will move the selection to the blank split when the transaction is expanded.</property>
                     <property name="halign">start</property>
                     <property name="margin_left">12</property>
-                    <property name="margin_left">12</property>
                     <property name="use_underline">True</property>
                     <property name="draw_indicator">True</property>
                   </object>
@@ -2620,7 +2612,6 @@ many months before the current month:</property>
                     <property name="tooltip_text" translatable="yes">Show the entered date and reconciled date on transaction selection.</property>
                     <property name="halign">start</property>
                     <property name="margin_left">12</property>
-                    <property name="margin_left">12</property>
                     <property name="use_underline">True</property>
                     <property name="draw_indicator">True</property>
                   </object>
diff --git a/gnucash/gnome/gtkbuilder/gnc-plugin-page-register.glade b/gnucash/gnome/gtkbuilder/gnc-plugin-page-register.glade
index ce244d0..d690887 100644
--- a/gnucash/gnome/gtkbuilder/gnc-plugin-page-register.glade
+++ b/gnucash/gnome/gtkbuilder/gnc-plugin-page-register.glade
@@ -1,10 +1,8 @@
-<?xml version="1.0" encoding="utf-8"?>
-<?xml version="1.0" encoding="utf-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
 <!-- Generated with glade 3.20.0 -->
+<interface>
   <requires lib="gtk+" version="3.10"/>
   <object class="GtkDialog" id="filter_by_dialog">
-  <object class="GtkDialog" id="filter_by_dialog">
     <property name="visible">True</property>
     <property name="can_focus">False</property>
     <property name="border_width">6</property>
@@ -126,8 +124,7 @@
                     <child>
                       <object class="GtkLabel" id="label847682">
                         <property name="visible">True</property>
-                        <property name="label" translatable="yes">Start:</property>
-                        <property name="label" translatable="yes">Start:</property>
+                        <property name="label" translatable="yes" comments="Filter By Dialog, Date Tab, Start section">Start:</property>
                       </object>
                       <packing>
                         <property name="left_attach">0</property>
@@ -213,8 +210,7 @@
                     <child>
                       <object class="GtkLabel" id="label847684">
                         <property name="visible">True</property>
-                        <property name="label" translatable="yes">End:</property>
-                        <property name="label" translatable="yes">End:</property>
+                        <property name="label" translatable="yes" comments="Filter By Dialog, Date Tab, End section">End:</property>
                       </object>
                       <packing>
                         <property name="left_attach">0</property>
@@ -838,8 +834,9 @@
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
                     <property name="receives_default">False</property>
+                    <property name="tooltip_text" translatable="yes">Sort in descending order.</property>
                     <property name="halign">start</property>
-                    <property name="halign">start</property>
+                    <property name="use_underline">True</property>
                     <property name="draw_indicator">True</property>
                     <signal name="toggled" handler="gnc_plugin_page_register_sort_order_reverse_cb" swapped="no"/>
                   </object>
@@ -879,7 +876,7 @@
     <property name="visible">True</property>
     <property name="can_focus">False</property>
     <property name="border_width">6</property>
-    <property name="title" translatable="yes">Duplicate Transaction</property>
+    <property name="title" translatable="yes" comments="Duplicate Transaction Dialog">Duplicate Transaction</property>
     <property name="resizable">False</property>
     <property name="modal">True</property>
     <property name="type_hint">dialog</property>
diff --git a/gnucash/import-export/dialog-import.glade b/gnucash/import-export/dialog-import.glade
index 96c39c0..8f329fb 100644
--- a/gnucash/import-export/dialog-import.glade
+++ b/gnucash/import-export/dialog-import.glade
@@ -1,5 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
-<?xml version="1.0" encoding="utf-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
 <!-- Generated with glade 3.20.0 -->
 <interface>
@@ -441,8 +439,7 @@
             <property name="visible">True</property>
             <property name="halign">start</property>
             <property name="margin_left">12</property>
-            <property name="label" translatable="yes">Commercial ATM _fees threshold</property>
-            <property name="label" translatable="yes">Commercial ATM _fees threshold</property>
+            <property name="label" translatable="yes" comments="Preferences->Online Banking:Generic">Commercial ATM _fees threshold</property>
             <property name="use_underline">True</property>
             <property name="mnemonic_widget">pref/dialogs.import.generic/atm-fee-threshold</property>
           </object>
@@ -456,8 +453,7 @@
             <property name="visible">True</property>
             <property name="halign">start</property>
             <property name="margin_left">12</property>
-            <property name="label" translatable="yes">Auto-c_lear threshold</property>
-            <property name="label" translatable="yes">Auto-c_lear threshold</property>
+            <property name="label" translatable="yes" comments="Preferences->Online Banking:Generic">Auto-c_lear threshold</property>
             <property name="use_underline">True</property>
             <property name="mnemonic_widget">pref/dialogs.import.generic/auto-clear-threshold</property>
           </object>
@@ -471,8 +467,7 @@
             <property name="visible">True</property>
             <property name="halign">start</property>
             <property name="margin_left">12</property>
-            <property name="label" translatable="yes">Auto-_add threshold</property>
-            <property name="label" translatable="yes">Auto-_add threshold</property>
+            <property name="label" translatable="yes" comments="Preferences->Online Banking:Generic">Auto-_add threshold</property>
             <property name="use_underline">True</property>
             <property name="mnemonic_widget">pref/dialogs.import.generic/auto-add-threshold</property>
           </object>
@@ -486,8 +481,7 @@
             <property name="visible">True</property>
             <property name="halign">start</property>
             <property name="margin_left">12</property>
-            <property name="label" translatable="yes">Match _display threshold</property>
-            <property name="label" translatable="yes">Match _display threshold</property>
+            <property name="label" translatable="yes" comments="Preferences->Online Banking:Generic">Match _display threshold</property>
             <property name="use_underline">True</property>
             <property name="mnemonic_widget">pref/dialogs.import.generic/match-threshold</property>
           </object>
@@ -622,8 +616,7 @@
             <child>
               <object class="GtkLabel" id="label847772">
                 <property name="visible">True</property>
-                <property name="label" translatable="yes">Imported transaction's first split:</property>
-                <property name="label" translatable="yes">Imported transaction's first split:</property>
+                <property name="label" translatable="yes" comments="Dialog Select matching transactions">Imported transaction's first split:</property>
                 <property name="justify">center</property>
               </object>
               <packing>
@@ -657,8 +650,7 @@
             <child>
               <object class="GtkLabel" id="label847766">
                 <property name="visible">True</property>
-                <property name="label" translatable="yes">Potential splits matching the selected transaction: </property>
-                <property name="label" translatable="yes">Potential splits matching the selected transaction: </property>
+                <property name="label" translatable="yes" comments="Dialog Select matching transactions">Potential splits matching the selected transaction: </property>
                 <property name="justify">center</property>
               </object>
               <packing>

commit 761d40918df88556598f98c8f8c72984a533ddc5
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Thu Nov 23 13:56:36 2017 +0000

    Change assistant-ab-initial.glade to gtk3.10 version

diff --git a/gnucash/import-export/aqb/assistant-ab-initial.glade b/gnucash/import-export/aqb/assistant-ab-initial.glade
index 2658fe9..45cfca0 100644
--- a/gnucash/import-export/aqb/assistant-ab-initial.glade
+++ b/gnucash/import-export/aqb/assistant-ab-initial.glade
@@ -1,14 +1,15 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
 <interface>
-  <requires lib="gtk+" version="2.16"/>
-  <!-- interface-naming-policy project-wide -->
+  <requires lib="gtk+" version="3.10"/>
   <object class="GtkAssistant" id="aqbanking_init_assistant">
     <property name="can_focus">False</property>
     <property name="border_width">12</property>
     <property name="title" translatable="yes">AqBanking Initial Assistant</property>
+    <property name="default_width">400</property>
+    <signal name="cancel" handler="aai_on_cancel" swapped="no"/>
     <signal name="close" handler="aai_on_finish" swapped="no"/>
     <signal name="prepare" handler="aai_on_prepare" swapped="no"/>
-    <signal name="cancel" handler="aai_on_cancel" swapped="no"/>
     <child>
       <placeholder/>
     </child>
@@ -41,10 +42,11 @@ Press "Cancel" if you do not wish to setup any Online Banking connection now.
       </packing>
     </child>
     <child>
-      <object class="GtkVBox" id="wizard_page">
+      <object class="GtkBox" id="wizard_page">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="border_width">12</property>
+        <property name="orientation">vertical</property>
         <property name="spacing">12</property>
         <child>
           <object class="GtkLabel" id="label8877441">
@@ -88,27 +90,30 @@ Press "Cancel" if you do not wish to setup any Online Banking connection now.
       </packing>
     </child>
     <child>
-      <object class="GtkVBox" id="account_match_page">
+      <object class="GtkBox" id="account_match_page">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="border_width">12</property>
+        <property name="orientation">vertical</property>
         <child>
-          <object class="GtkVBox" id="vbox157">
+          <object class="GtkBox" id="vbox157">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
+            <property name="orientation">vertical</property>
             <property name="spacing">12</property>
             <child>
               <object class="GtkScrolledWindow" id="scrolledwindow25">
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
-                <property name="hscrollbar_policy">automatic</property>
-                <property name="vscrollbar_policy">automatic</property>
                 <property name="shadow_type">in</property>
                 <child>
                   <object class="GtkTreeView" id="account_page_view">
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
                     <property name="rules_hint">True</property>
+                    <child internal-child="selection">
+                      <object class="GtkTreeSelection"/>
+                    </child>
                   </object>
                 </child>
               </object>
@@ -122,7 +127,7 @@ Press "Cancel" if you do not wish to setup any Online Banking connection now.
               <object class="GtkLabel" id="label828">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="label" translatable="yes">Double Click on the line of an Online Banking account name if you want to match it to a GnuCash account. Click "Forward" when all desired accounts are matching.</property>
+                <property name="label" translatable="yes">Double Click on the line of an Online Banking account name if you want to match it to a GnuCash account. Click "Next" when all desired accounts are matching.</property>
                 <property name="wrap">True</property>
               </object>
               <packing>
@@ -160,5 +165,10 @@ Press "Apply" now.</property>
         <property name="complete">True</property>
       </packing>
     </child>
+    <child internal-child="action_area">
+      <object class="GtkBox">
+        <property name="can_focus">False</property>
+      </object>
+    </child>
   </object>
 </interface>

commit baf7575f1d77198219bc6fc2bc0bcf1e18625f07
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Thu Nov 23 13:55:58 2017 +0000

    Replace deprecated GTK_STOCK_ macro identifiers

diff --git a/gnucash/import-export/aqb/dialog-ab-trans.c b/gnucash/import-export/aqb/dialog-ab-trans.c
index 5f59e85..dc4480a 100644
--- a/gnucash/import-export/aqb/dialog-ab-trans.c
+++ b/gnucash/import-export/aqb/dialog-ab-trans.c
@@ -478,10 +478,10 @@ gnc_ab_trans_dialog_new(GtkWidget *parent, AB_ACCOUNT *ab_acc,
 static void
 gnc_ab_trans_dialog_entry_set (GtkWidget* entry,
                                const gchar* message,
-                               const gchar* stock_icon)
+                               const gchar* icon_name)
 {
     g_object_set (entry,
-                  "secondary-icon-stock", stock_icon,
+                  "secondary-icon-name", icon_name,
                   "secondary-icon-tooltip-text", message,
                   NULL);
 }
@@ -499,7 +499,7 @@ gnc_ab_trans_dialog_check_ktoblzcheck(const GncABTransDialog *td,
                                                "the account number might contain an error."),
                                              AB_Transaction_GetRemoteIban(trans));
             gnc_ab_trans_dialog_entry_set (td->recp_account_entry, message,
-                                           GTK_STOCK_DIALOG_WARNING);
+                                           "dialog-warning");
         }
         else
         {
@@ -540,9 +540,9 @@ gnc_ab_trans_dialog_check_ktoblzcheck(const GncABTransDialog *td,
                                   AB_Transaction_GetRemoteAccountNumber(trans),
                                   AB_Transaction_GetRemoteBankCode(trans));
         gnc_ab_trans_dialog_entry_set (td->recp_bankcode_entry, message,
-                                       GTK_STOCK_DIALOG_WARNING);
+                                       "dialog-warning");
         gnc_ab_trans_dialog_entry_set (td->recp_account_entry, message,
-                                       GTK_STOCK_DIALOG_WARNING);
+                                       "dialog-warning");
 
         blztext = "Kontonummer wahrscheinlich falsch";
         break;
@@ -624,7 +624,7 @@ gnc_ab_trans_dialog_verify_values(GncABTransDialog *td)
         gnc_ab_trans_dialog_entry_set (td->recp_name_entry,
                                        _("You did not enter a recipient name. A recipient name is "
                                          "required for an online transfer.\n"),
-                                       GTK_STOCK_CANCEL);
+                                       "process-stop");
 
         g_free (othername);
         values_ok = FALSE;
@@ -644,7 +644,7 @@ gnc_ab_trans_dialog_verify_values(GncABTransDialog *td)
         gnc_ab_trans_dialog_entry_set (td->recp_account_entry,
                                        _("You did not enter a recipient account. A recipient account is "
                                          "required for an online transfer.\n"),
-                                       GTK_STOCK_CANCEL);
+                                       "process-stop");
         values_ok = FALSE;
     }
     else
@@ -660,7 +660,7 @@ gnc_ab_trans_dialog_verify_values(GncABTransDialog *td)
         gnc_ab_trans_dialog_entry_set (td->recp_bankcode_entry,
                                        _("You did not enter a recipient bank. A recipient bank is "
                                          "required for an online transfer.\n"),
-                                       GTK_STOCK_CANCEL);
+                                       "process-stop");
         values_ok = FALSE;
     }
     else
@@ -680,7 +680,7 @@ gnc_ab_trans_dialog_verify_values(GncABTransDialog *td)
                                          "interpreted correctly. You might have mixed up decimal "
                                          "point and comma, compared to your locale settings. "
                                          "This does not result in a valid online transfer job."),
-                                       GTK_STOCK_CANCEL);
+                                       "process-stop");
         values_ok = FALSE;
     }
     else
@@ -695,7 +695,7 @@ gnc_ab_trans_dialog_verify_values(GncABTransDialog *td)
         gnc_ab_trans_dialog_entry_set (td->purpose_entry,
                                        _("You did not enter any transaction purpose. A purpose is "
                                          "required for an online transfer.\n"),
-                                       GTK_STOCK_CANCEL);
+                                       "process-stop");
         g_free (purpose);
         values_ok = FALSE;
     }
@@ -721,7 +721,7 @@ gnc_ab_trans_dialog_verify_values(GncABTransDialog *td)
                                          "\n\n"
                                          "In particular, neither Umlauts nor an ampersand (&) is allowed, "
                                          "neither in the recipient or sender name nor in any purpose line."),
-                                       GTK_STOCK_CANCEL);
+                                       "process-stop");
         values_ok = FALSE;
     }
 #endif

commit a5d15de4263e486031a1fa66efb6b3a1483d2fb4
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Thu Nov 23 13:55:19 2017 +0000

    Change a couple of deprecated functions in gnc-html-webkit1.c

diff --git a/gnucash/html/gnc-html-webkit1.c b/gnucash/html/gnc-html-webkit1.c
index c37881f..0b0fadd 100644
--- a/gnucash/html/gnc-html-webkit1.c
+++ b/gnucash/html/gnc-html-webkit1.c
@@ -125,9 +125,10 @@ gnc_html_webkit_init( GncHtmlWebkit* self )
 {
     GncHtmlWebkitPrivate* priv;
     GncHtmlWebkitPrivate* new_priv;
-
+    GtkStyleContext *stylecontext;
     WebKitWebSettings* webkit_settings = NULL;
     const char* default_font_family = NULL;
+    PangoFontDescription *font_desc;
     gdouble zoom = 1.0;
 
     new_priv = g_realloc( GNC_HTML(self)->priv, sizeof(GncHtmlWebkitPrivate) );
@@ -137,9 +138,13 @@ gnc_html_webkit_init( GncHtmlWebkit* self )
     priv->html_string = NULL;
     priv->web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
 
+    /* Get the default font family from GtkStyleContext of a GtkWidget(priv->web_view). */
+    stylecontext = gtk_widget_get_style_context (GTK_WIDGET(priv->web_view));
+    gtk_style_context_get (stylecontext, gtk_widget_get_state_flags (GTK_WIDGET(priv->web_view)),
+                           "font", &font_desc, NULL);
 
-    /* Get the default font family from GtkStyle of a GtkWidget(priv-web_view). */
-    default_font_family = pango_font_description_get_family( gtk_rc_get_style(GTK_WIDGET(priv->web_view))->font_desc );
+    default_font_family = pango_font_description_get_family (font_desc);
+    pango_font_description_free (font_desc);
 
     /* Set default webkit settings */
     webkit_settings = webkit_web_view_get_settings (priv->web_view);
@@ -1188,8 +1193,8 @@ impl_webkit_print( GncHtml* self, const gchar* jobname, gboolean export_pdf )
         dialog = gtk_file_chooser_dialog_new (_("Export to PDF File"),
                                               NULL,
                                               GTK_FILE_CHOOSER_ACTION_SAVE,
-                                              GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                                              GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+                                              _("_Cancel"), GTK_RESPONSE_CANCEL,
+                                              _("_Save"), GTK_RESPONSE_ACCEPT,
                                               NULL);
         gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
 

commit 99f2283d83ffc7517b01f6c8d188fbbf2addc94c
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Thu Nov 23 13:54:40 2017 +0000

    Control the toggle button width
    
    There did not seem to be an easier way to control the toggle button
    width so created a custom one based on the GtkToggleButton. This
    allowed the use of the class function get_preferred_width which is set
    at two thirds the height.

diff --git a/gnucash/register/register-gnome/gnucash-item-edit.c b/gnucash/register/register-gnome/gnucash-item-edit.c
index 07c07d7..56bad13 100644
--- a/gnucash/register/register-gnome/gnucash-item-edit.c
+++ b/gnucash/register/register-gnome/gnucash-item-edit.c
@@ -58,6 +58,155 @@ enum
 
 static GtkBoxClass *gnc_item_edit_parent_class;
 
+static GtkToggleButtonClass *gnc_item_edit_tb_parent_class;
+
+static void
+gnc_item_edit_tb_init (GncItemEditTb *item_edit_tb)
+{
+    item_edit_tb->sheet = NULL;
+}
+
+static void
+gnc_item_edit_tb_get_property (GObject *object,
+                               guint param_id,
+                               GValue *value,
+                               GParamSpec *pspec)
+{
+    GncItemEditTb *item_edit_tb = GNC_ITEM_EDIT_TB (object);
+
+    switch (param_id)
+    {
+    case PROP_SHEET:
+        g_value_take_object (value, item_edit_tb->sheet);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+        break;
+    }
+}
+
+static void
+gnc_item_edit_tb_set_property (GObject *object,
+                               guint param_id,
+                               const GValue *value,
+                               GParamSpec *pspec)
+{
+    GncItemEditTb *item_edit_tb = GNC_ITEM_EDIT_TB (object);
+
+    switch (param_id)
+    {
+    case PROP_SHEET:
+        item_edit_tb->sheet = GNUCASH_SHEET (g_value_get_object (value));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+        break;
+    }
+}
+
+static void
+gnc_item_edit_tb_get_preferred_width (GtkWidget *widget,
+                                   gint *minimal_width,
+                                   gint *natural_width)
+{
+    GncItemEditTb *tb = GNC_ITEM_EDIT_TB (widget);
+    GncItemEdit *item_edit = GNC_ITEM_EDIT(tb->sheet->item_editor);
+    gint x, y, w, h, width = 0;
+    gnc_item_edit_get_pixel_coords (GNC_ITEM_EDIT (item_edit), &x, &y, &w, &h);
+    width = ((h - 2)*2)/3;
+    if (width < 20) // minimum size for a button
+        width = 20;
+    *minimal_width = *natural_width = width;
+}
+
+static void
+gnc_item_edit_tb_get_preferred_height (GtkWidget *widget,
+                                    gint *minimal_width,
+                                    gint *natural_width)
+{
+    GncItemEditTb *tb = GNC_ITEM_EDIT_TB (widget);
+    GncItemEdit *item_edit = GNC_ITEM_EDIT(tb->sheet->item_editor);
+    gint x, y, w, h;
+    gnc_item_edit_get_pixel_coords (GNC_ITEM_EDIT (item_edit), &x, &y, &w, &h);
+    *minimal_width = *natural_width = (h - 2);
+}
+
+static void
+gnc_item_edit_tb_class_init (GncItemEditTbClass *gnc_item_edit_tb_class)
+{
+    GObjectClass  *object_class;
+    GtkWidgetClass *widget_class;
+
+#if GTK_CHECK_VERSION(3,20,0)
+    gtk_widget_class_set_css_name (GTK_WIDGET_CLASS(gnc_item_edit_tb_class), "button");
+#endif
+
+    gnc_item_edit_tb_parent_class = g_type_class_peek_parent (gnc_item_edit_tb_class);
+
+    object_class = G_OBJECT_CLASS (gnc_item_edit_tb_class);
+    widget_class = GTK_WIDGET_CLASS (gnc_item_edit_tb_class);
+
+    object_class->get_property = gnc_item_edit_tb_get_property;
+    object_class->set_property = gnc_item_edit_tb_set_property;
+
+    g_object_class_install_property (object_class,
+                                     PROP_SHEET,
+                                     g_param_spec_object ("sheet",
+                                             "Sheet Value",
+                                             "Sheet Value",
+                                             GNUCASH_TYPE_SHEET,
+                                             G_PARAM_READWRITE));
+
+    /* GtkWidget method overrides */
+    widget_class->get_preferred_width = gnc_item_edit_tb_get_preferred_width;
+    widget_class->get_preferred_height = gnc_item_edit_tb_get_preferred_height;
+}
+
+GType
+gnc_item_edit_tb_get_type (void)
+{
+    static GType gnc_item_edit_tb_type = 0;
+
+    if (!gnc_item_edit_tb_type)
+    {
+        static const GTypeInfo gnc_item_edit_tb_info =
+        {
+            sizeof (GncItemEditTbClass),
+            NULL,
+            NULL,
+            (GClassInitFunc) gnc_item_edit_tb_class_init,
+            NULL,
+            NULL,
+            sizeof (GncItemEditTb),
+            0, /* n_preallocs */
+            (GInstanceInitFunc) gnc_item_edit_tb_init,
+            NULL,
+        };
+        gnc_item_edit_tb_type =
+            g_type_register_static(GTK_TYPE_TOGGLE_BUTTON,
+                                   "GncItemEditTb",
+                                   &gnc_item_edit_tb_info, 0);
+    }
+    return gnc_item_edit_tb_type;
+}
+
+GtkWidget *
+gnc_item_edit_tb_new (GnucashSheet *sheet)
+{
+    GtkStyleContext *context;
+    GncItemEditTb *item_edit_tb =
+            g_object_new (GNC_TYPE_ITEM_EDIT_TB,
+                          "sheet", sheet,
+                           NULL);
+
+    // This sets a style class for when Gtk+ version is less than 3.20
+    gnc_widget_set_css_name (GTK_WIDGET(item_edit_tb), "button");
+
+    context = gtk_widget_get_style_context (GTK_WIDGET(item_edit_tb));
+    gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
+
+    return GTK_WIDGET(item_edit_tb);
+}
 
 /*
  * Returns the coordinates for the editor bounding box
@@ -719,7 +868,7 @@ gnc_item_edit_new (GnucashSheet *sheet)
     /* Create the popup button
        It will only be displayed when the cell being edited provides
        a popup item (like a calendar or account list) */
-    item_edit->popup_toggle.tbutton = gtk_toggle_button_new();
+    item_edit->popup_toggle.tbutton = gnc_item_edit_tb_new (sheet);
     gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (item_edit->popup_toggle.tbutton), FALSE);
 
     /* Wrap the popup button in an event box to give it its own gdkwindow.
diff --git a/gnucash/register/register-gnome/gnucash-item-edit.h b/gnucash/register/register-gnome/gnucash-item-edit.h
index 45d1502..2be4d24 100644
--- a/gnucash/register/register-gnome/gnucash-item-edit.h
+++ b/gnucash/register/register-gnome/gnucash-item-edit.h
@@ -37,6 +37,10 @@
 #define GNC_ITEM_EDIT_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST ((k), GNC_TYPE_ITEM_EDIT, GncItemEditClass))
 #define GNC_IS_ITEM_EDIT(o)       (G_TYPE_CHECK_INSTANCE_TYPE((o), GNC_TYPE_ITEM_EDIT))
 
+#define GNC_TYPE_ITEM_EDIT_TB        (gnc_item_edit_tb_get_type ())
+#define GNC_ITEM_EDIT_TB(o)          (G_TYPE_CHECK_INSTANCE_CAST((o), GNC_TYPE_ITEM_EDIT_TB, GncItemEditTb))
+#define GNC_ITEM_EDIT_TB_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST ((k), GNC_TYPE_ITEM_EDIT_TB, GncItemEditTbClass))
+#define GNC_IS_ITEM_EDIT_TB(o)       (G_TYPE_CHECK_INSTANCE_TYPE((o), GNC_TYPE_ITEM_EDIT_TB))
 
 typedef int (*PopupGetHeight) (GtkWidget *item,
                                int space_available,
@@ -102,6 +106,19 @@ typedef struct
     GtkBoxClass parent_class;
 } GncItemEditClass;
 
+typedef struct
+{
+    GtkToggleButton tb;
+    GnucashSheet *sheet;
+} GncItemEditTb;
+
+typedef struct
+{
+    GtkToggleButtonClass parent_class;
+
+    void (* toggled) (GncItemEditTb *item_edit_tb);
+} GncItemEditTbClass;
+
 typedef enum
 {
     left,
@@ -145,5 +162,8 @@ void gnc_item_edit_focus_out (GncItemEdit *item_edit);
 gint gnc_item_edit_get_margin (GncItemEdit *item_edit, Sides side);
 gint gnc_item_edit_get_padding_border (GncItemEdit *item_edit, Sides side);
 
+GType gnc_item_edit_tb_get_type (void);
+GtkWidget *gnc_item_edit_tb_new (GnucashSheet *sheet);
+
 /** @} */
 #endif /* GNUCASH_ITEM_EDIT_H */

commit c5f483d115c5ad81ce722eb300f669309037750b
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Thu Nov 23 13:54:03 2017 +0000

    Move the double line to be inside the cursor cell

diff --git a/gnucash/register/register-gnome/gnucash-sheet-private.c b/gnucash/register/register-gnome/gnucash-sheet-private.c
index a951415..aa13c55 100644
--- a/gnucash/register/register-gnome/gnucash-sheet-private.c
+++ b/gnucash/register/register-gnome/gnucash-sheet-private.c
@@ -680,7 +680,7 @@ gnucash_sheet_draw_cursor (GnucashCursor *cursor, cairo_t *cr)
     cairo_stroke (cr);
 
     // make the bottom line thicker
-    cairo_move_to (cr, cursor->x - x + 0.5, cursor->y - y + cursor->h - 1.5);
+    cairo_move_to (cr, cursor->x - x + 0.5, cursor->y - y + cursor->h - 3.5);
     cairo_rel_line_to (cr, cursor->w, 0);
     cairo_set_line_width (cr, 1.0);
     cairo_stroke (cr);

commit 78ec2e339ebb6ec90de2ce7660b04ba4a9180df1
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Thu Nov 23 13:53:25 2017 +0000

    If a font size is specified for the sheet, popup size may be wrong
    
    When you specify a font size for the sheet, the popup will inherit this
    but when first popped it will use the minimum height value and so may
    be different resulting in not being in the right position. So check on
    allocation and if different remove and pop again.

diff --git a/gnucash/register/register-gnome/gnucash-item-edit.c b/gnucash/register/register-gnome/gnucash-item-edit.c
index 7af904d..07c07d7 100644
--- a/gnucash/register/register-gnome/gnucash-item-edit.c
+++ b/gnucash/register/register-gnome/gnucash-item-edit.c
@@ -739,6 +739,25 @@ gnc_item_edit_new (GnucashSheet *sheet)
     return GTK_WIDGET(item_edit);
 }
 
+static void
+check_popup_height_is_true (GtkWidget    *widget,
+                            GdkRectangle *allocation,
+                            gpointer user_data)
+{
+    GncItemEdit *item_edit = GNC_ITEM_EDIT(user_data);
+    GnucashSheet *sheet = item_edit->sheet;
+
+    // if a larger font is specified in css for the sheet, the popup returned height value
+    // on first pop does not reflect the true height but the minimum height so just to be
+    // sure check this value against the allocated one.
+    if (allocation->height != item_edit->popup_returned_height)
+    {
+        gtk_container_remove (GTK_CONTAINER(item_edit->sheet), item_edit->popup_item);
+
+        g_idle_add_full (G_PRIORITY_HIGH_IDLE,
+                        (GSourceFunc) gnc_item_edit_update, item_edit, NULL);
+    }
+}
 
 void
 gnc_item_edit_show_popup (GncItemEdit *item_edit)
@@ -807,6 +826,11 @@ gnc_item_edit_show_popup (GncItemEdit *item_edit)
     if (!gtk_widget_get_parent (item_edit->popup_item))
         gtk_layout_put (GTK_LAYOUT(sheet), item_edit->popup_item, popup_x, popup_y);
 
+    // Lets check popup height is the true height
+    item_edit->popup_returned_height = popup_h;
+    g_signal_connect_after (item_edit->popup_item, "size-allocate",
+                            G_CALLBACK(check_popup_height_is_true), item_edit);
+
     gtk_widget_set_size_request (item_edit->popup_item, popup_w - 1, popup_h);
 
     toggle = GTK_TOGGLE_BUTTON(item_edit->popup_toggle.tbutton);
diff --git a/gnucash/register/register-gnome/gnucash-item-edit.h b/gnucash/register/register-gnome/gnucash-item-edit.h
index 7d37378..45d1502 100644
--- a/gnucash/register/register-gnome/gnucash-item-edit.h
+++ b/gnucash/register/register-gnome/gnucash-item-edit.h
@@ -85,6 +85,7 @@ typedef struct
     PopupPostShow    popup_post_show;
     PopupGetWidth    popup_get_width;
     gpointer         popup_user_data;
+    gint             popup_returned_height;
 
     GtkBorder        padding;
     GtkBorder        margin;

commit 67e4b3529466b1dc1b90715853815889a1f19b42
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Thu Nov 23 13:52:43 2017 +0000

    Use previously created functions
    
    Use the previously created functions to reduce code and for conformity.
    As part of this some variables were renamed to be common.

diff --git a/gnucash/register/register-gnome/gnucash-header.c b/gnucash/register/register-gnome/gnucash-header.c
index 2f6d4d2..156ae68 100644
--- a/gnucash/register/register-gnome/gnucash-header.c
+++ b/gnucash/register/register-gnome/gnucash-header.c
@@ -69,6 +69,7 @@ static void
 gnc_header_draw_offscreen (GncHeader *header)
 {
     SheetBlockStyle *style = header->style;
+    GncItemEdit *item_edit = GNC_ITEM_EDIT(header->sheet->item_editor);
     Table *table = header->sheet->table;
     VirtualLocation virt_loc;
     VirtualCell *vcell;
@@ -125,7 +126,7 @@ gnc_header_draw_offscreen (GncHeader *header)
     for (i = 0; i < style->nrows; i++)
     {
         int col_offset = 0;
-        int h = 0, j;
+        int height = 0, j;
         virt_loc.phys_row_offset = i;
 
         /* TODO: This routine is duplicated in several places.
@@ -139,26 +140,29 @@ gnc_header_draw_offscreen (GncHeader *header)
             double text_x, text_y, text_w, text_h;
             BasicCell *cell;
             const char *text;
-            int w;
+            int width;
             PangoLayout *layout;
+            PangoRectangle logical_rect;
+            GdkRectangle rect;
+            int x_offset;
 
             virt_loc.phys_col_offset = j;
 
             cd = gnucash_style_get_cell_dimensions (style, i, j);
-            h = cd->pixel_height;
+            height = cd->pixel_height;
             if (header->in_resize && (j == header->resize_col))
-                w = header->resize_col_width;
+                width = header->resize_col_width;
             else
-                w = cd->pixel_width;
+                width = cd->pixel_width;
 
             cell = gnc_cellblock_get_cell (cb, i, j);
             if (!cell || !cell->cell_name)
             {
-                col_offset += w;
+                col_offset += width;
                 continue;
             }
 
-            cairo_rectangle (cr, col_offset - 0.5, row_offset + 0.5, w, h);
+            cairo_rectangle (cr, col_offset - 0.5, row_offset + 0.5, width, height);
             cairo_set_line_width (cr, 1.0);
             cairo_stroke (cr);
 
@@ -169,38 +173,28 @@ gnc_header_draw_offscreen (GncHeader *header)
                 text = "";
 
             layout = gtk_widget_create_pango_layout (GTK_WIDGET (header->sheet), text);
-            switch (gnc_table_get_align (table, virt_loc))
-            {
-            default:
-            case CELL_ALIGN_LEFT:
-                pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT);
-                break;
-
-            case CELL_ALIGN_RIGHT:
-                pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
-                break;
-
-            case CELL_ALIGN_CENTER:
-                pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
-                break;
-            }
 
-            text_x = col_offset + CELL_HPADDING;
-            text_y = row_offset + 1;
-            text_w = MAX (0, w - (2 * CELL_HPADDING));
-            text_h = h - 2;
+            pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
+
+            gnucash_sheet_set_text_bounds (header->sheet, &rect,
+                                           col_offset, row_offset, width, height);
+
             cairo_save (cr);
-            cairo_rectangle (cr, text_x, text_y, text_w, text_h);
+            cairo_rectangle (cr, rect.x, rect.y, rect.width, rect.height);
             cairo_clip (cr);
 
-            gtk_render_layout (stylectxt, cr, text_x, text_y, layout);
+            x_offset = gnucash_sheet_get_text_offset (header->sheet, virt_loc,
+                                                      rect.width, logical_rect.width);
+
+            gtk_render_layout (stylectxt, cr, rect.x + x_offset,
+                               rect.y + gnc_item_edit_get_padding_border (item_edit, top), layout);
 
             cairo_restore (cr);
             g_object_unref (layout);
 
-            col_offset += w;
+            col_offset += width;
         }
-        row_offset += h;
+        row_offset += height;
     }
     gtk_style_context_restore (stylectxt);
 
diff --git a/gnucash/register/register-gnome/gnucash-sheet-private.c b/gnucash/register/register-gnome/gnucash-sheet-private.c
index 8b0d067..a951415 100644
--- a/gnucash/register/register-gnome/gnucash-sheet-private.c
+++ b/gnucash/register/register-gnome/gnucash-sheet-private.c
@@ -381,6 +381,7 @@ draw_cell (GnucashSheet *sheet,
            cairo_t *cr,
            int x, int y, int width, int height)
 {
+    GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
     Table *table = sheet->table;
     PhysicalCellBorders borders;
     const char *text;
@@ -522,39 +523,19 @@ draw_cell (GnucashSheet *sheet,
         goto exit;
     }
 
-    pango_layout_get_pixel_extents(layout,
-                                   NULL,
-                                   &logical_rect);
+    pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
 
-    rect.x      = x + CELL_HPADDING;
-    rect.y      = y + CELL_VPADDING;
-    rect.width  = MAX (0, width - (2 * CELL_HPADDING));
-    rect.height = height - 2;
+    gnucash_sheet_set_text_bounds (sheet, &rect, x, y, width, height);
 
     cairo_save (cr);
     cairo_rectangle (cr, rect.x, rect.y, rect.width, rect.height);
     cairo_clip (cr);
 
-    switch (gnc_table_get_align (table, virt_loc))
-    {
-    default:
-    case CELL_ALIGN_LEFT:
-        x_offset = 0;
-        break;
-
-    case CELL_ALIGN_RIGHT:
-        x_offset = width - 2 * CELL_HPADDING - logical_rect.width - 3;
-        break;
-
-    case CELL_ALIGN_CENTER:
-        if (logical_rect.width > width - 2 * CELL_HPADDING)
-            x_offset = 0;
-        else
-            x_offset = (width - 2 * CELL_HPADDING -
-                        logical_rect.width) / 2;
-        break;
-    }
-    gtk_render_layout (stylectxt, cr, rect.x + x_offset + 1, rect.y, layout);
+    x_offset = gnucash_sheet_get_text_offset (sheet, virt_loc,
+                                              rect.width, logical_rect.width);
+
+    gtk_render_layout (stylectxt, cr, rect.x + x_offset,
+                       rect.y + gnc_item_edit_get_padding_border (item_edit, top), layout);
 
     cairo_restore (cr);
 
diff --git a/gnucash/register/register-gnome/gnucash-sheet.c b/gnucash/register/register-gnome/gnucash-sheet.c
index d8426cb..311ab1b 100644
--- a/gnucash/register/register-gnome/gnucash-sheet.c
+++ b/gnucash/register/register-gnome/gnucash-sheet.c
@@ -312,7 +312,7 @@ gnucash_sheet_get_text_cursor_position (GnucashSheet *sheet, const VirtualLocati
     PangoLayout *layout;
     PangoRectangle logical_rect;
     GdkRectangle rect;
-    gint x, y, w, h;
+    gint x, y, width, height;
     gint index, trailing;
     gboolean result;
     gint x_offset = 0;
@@ -321,7 +321,7 @@ gnucash_sheet_get_text_cursor_position (GnucashSheet *sheet, const VirtualLocati
         return 0;
 
     // Get the item_edit position
-    gnc_item_edit_get_pixel_coords (item_edit, &x, &y, &w, &h);
+    gnc_item_edit_get_pixel_coords (item_edit, &x, &y, &width, &height);
 
     layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), text);
 
@@ -330,35 +330,14 @@ gnucash_sheet_get_text_cursor_position (GnucashSheet *sheet, const VirtualLocati
 
     pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
 
-    rect.x      = x + CELL_HPADDING;
-    rect.y      = y + CELL_VPADDING;
-    rect.width  = MAX (0, w - (2 * CELL_HPADDING));
-    rect.height = h - 2;
+    gnucash_sheet_set_text_bounds (sheet, &rect, x, y, width, height);
 
-    // Get the alignment of the cell
-    switch (gnc_table_get_align (table, virt_loc))
-    {
-    default:
-    case CELL_ALIGN_LEFT:
-        x_offset = 0;
-        break;
-
-    case CELL_ALIGN_RIGHT:
-        x_offset = w - 2 * CELL_HPADDING - logical_rect.width - 3;
-        break;
-
-    case CELL_ALIGN_CENTER:
-        if (logical_rect.width > w - 2 * CELL_HPADDING)
-            x_offset = 0;
-        else
-            x_offset = (w - 2 * CELL_HPADDING -
-                        logical_rect.width) / 2;
-        break;
-    }
+    x_offset = gnucash_sheet_get_text_offset (sheet, virt_loc,
+                                              rect.width, logical_rect.width);
 
     result = pango_layout_xy_to_index (layout,
                  PANGO_SCALE * (sheet->button_x - rect.x - x_offset),
-                 PANGO_SCALE * (h/2), &index, &trailing);
+                 PANGO_SCALE * (height/2), &index, &trailing);
 
     g_object_unref (layout);
 
@@ -2231,6 +2210,7 @@ gnucash_sheet_col_max_width (GnucashSheet *sheet, gint virt_col, gint cell_col)
     SheetBlock *block;
     SheetBlockStyle *style;
     PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), "");
+    GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
 
     g_return_val_if_fail (virt_col >= 0, 0);
     g_return_val_if_fail (virt_col < sheet->num_virt_cols, 0);
diff --git a/gnucash/register/register-gnome/gnucash-sheet.h b/gnucash/register/register-gnome/gnucash-sheet.h
index 68b3c70..f729e8f 100644
--- a/gnucash/register/register-gnome/gnucash-sheet.h
+++ b/gnucash/register/register-gnome/gnucash-sheet.h
@@ -33,10 +33,6 @@
  * @brief Public declarations of GnucashSheet class.
  */
 
-#define CELL_VPADDING 2
-#define CELL_HPADDING 5
-
-
 #define GNUCASH_TYPE_SHEET     (gnucash_sheet_get_type ())
 #define GNUCASH_SHEET(obj)     (G_TYPE_CHECK_INSTANCE_CAST((obj), GNUCASH_TYPE_SHEET, GnucashSheet))
 #define GNUCASH_SHEET_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GNUCASH_TYPE_SHEET))

commit 8a6ce10aa872533739264a0a2a386067e5f2def5
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Thu Nov 23 13:52:02 2017 +0000

    Provide two functions for common code
    
    These two sections of code appear in three separate files in slightly
    different versions so define them hear for conformity

diff --git a/gnucash/register/register-gnome/gnucash-sheet.c b/gnucash/register/register-gnome/gnucash-sheet.c
index e2a759a..d8426cb 100644
--- a/gnucash/register/register-gnome/gnucash-sheet.c
+++ b/gnucash/register/register-gnome/gnucash-sheet.c
@@ -261,6 +261,47 @@ gnucash_sheet_deactivate_cursor_cell (GnucashSheet *sheet)
     gnucash_sheet_redraw_block (sheet, virt_loc.vcell_loc);
 }
 
+void
+gnucash_sheet_set_text_bounds (GnucashSheet *sheet, GdkRectangle *rect,
+                               gint x, gint y, gint width, gint height)
+{
+    GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
+
+    rect->x = x + gnc_item_edit_get_margin (item_edit, left);
+    rect->y = y + gnc_item_edit_get_margin (item_edit, top);
+    rect->width = MAX (0, width - gnc_item_edit_get_margin (item_edit, left_right));
+    rect->height = height - gnc_item_edit_get_margin (item_edit, top_bottom);
+}
+
+gint
+gnucash_sheet_get_text_offset (GnucashSheet *sheet, const VirtualLocation virt_loc,
+                                gint rect_width, gint logical_width)
+{
+    GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
+    Table *table = sheet->table;
+    gint x_offset = 0;
+
+    // Get the alignment of the cell
+    switch (gnc_table_get_align (table, virt_loc))
+    {
+    default:
+    case CELL_ALIGN_LEFT:
+        x_offset = gnc_item_edit_get_padding_border (item_edit, left);
+        break;
+
+    case CELL_ALIGN_RIGHT:
+        x_offset = rect_width - gnc_item_edit_get_padding_border (item_edit, right) - logical_width - 1;
+        break;
+
+    case CELL_ALIGN_CENTER:
+        if (logical_width > rect_width)
+            x_offset = 0;
+        else
+            x_offset = (rect_width - logical_width) / 2;
+        break;
+    }
+    return x_offset;
+}
 
 static gint
 gnucash_sheet_get_text_cursor_position (GnucashSheet *sheet, const VirtualLocation virt_loc)
@@ -2229,7 +2270,7 @@ gnucash_sheet_col_max_width (GnucashSheet *sheet, gint virt_col, gint cell_col)
                 pango_layout_set_text (layout, text, strlen (text));
                 pango_layout_get_pixel_size (layout, &width, NULL);
 
-                width += 2 * CELL_HPADDING;
+                width += gnc_item_edit_get_margin (item_edit, left_right);
 
                 max = MAX (max, width);
             }
diff --git a/gnucash/register/register-gnome/gnucash-sheet.h b/gnucash/register/register-gnome/gnucash-sheet.h
index b571d03..68b3c70 100644
--- a/gnucash/register/register-gnome/gnucash-sheet.h
+++ b/gnucash/register/register-gnome/gnucash-sheet.h
@@ -108,5 +108,11 @@ void gnucash_sheet_set_window (GnucashSheet *sheet, GtkWidget *window);
 void gnucash_get_style_classes (GnucashSheet *sheet, GtkStyleContext *stylectxt,
                                 RegisterColor field_type);
 
+void gnucash_sheet_set_text_bounds (GnucashSheet *sheet, GdkRectangle *rect,
+                                    gint x, gint y, gint width, gint height);
+
+gint gnucash_sheet_get_text_offset (GnucashSheet *sheet, const VirtualLocation virt_loc,
+                                    gint rect_width, gint logical_width);
+
 /** @} */
 #endif

commit 1b52053d2e253e0b2fb8e453a494e6e5d4aba5d1
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Thu Nov 23 13:51:25 2017 +0000

    This function doesn't do much and is only used for new account registers
    
    This function is used to get the width of the toggle button and add it
    to the sample text length to set the default column width. As the it is
    square, just use the row height instead and the user will no doubt set
    there own widths any way.

diff --git a/gnucash/register/register-gnome/gnucash-item-edit.c b/gnucash/register/register-gnome/gnucash-item-edit.c
index 047757e..7af904d 100644
--- a/gnucash/register/register-gnome/gnucash-item-edit.c
+++ b/gnucash/register/register-gnome/gnucash-item-edit.c
@@ -94,14 +94,6 @@ gnc_item_edit_get_pixel_coords (GncItemEdit *item_edit,
     *y += yd;
 }
 
-
-int
-gnc_item_edit_get_toggle_offset (int row_height)
-{
-    /* sync with gnc_item_edit_update */
-    return row_height - (2 * (CELL_VPADDING + 1)) + 3;
-}
-
 static gboolean
 gnc_item_edit_update (GncItemEdit *item_edit)
 {
diff --git a/gnucash/register/register-gnome/gnucash-item-edit.h b/gnucash/register/register-gnome/gnucash-item-edit.h
index a2eae31..7d37378 100644
--- a/gnucash/register/register-gnome/gnucash-item-edit.h
+++ b/gnucash/register/register-gnome/gnucash-item-edit.h
@@ -133,8 +133,6 @@ void gnc_item_edit_set_popup (GncItemEdit    *item_edit,
 void gnc_item_edit_show_popup (GncItemEdit *item_edit);
 void gnc_item_edit_hide_popup (GncItemEdit *item_edit);
 
-int gnc_item_edit_get_toggle_offset (int row_height);
-
 void gnc_item_edit_cut_clipboard (GncItemEdit *item_edit);
 void gnc_item_edit_copy_clipboard (GncItemEdit *item_edit);
 void gnc_item_edit_paste_clipboard (GncItemEdit *item_edit);
diff --git a/gnucash/register/register-gnome/gnucash-style.c b/gnucash/register/register-gnome/gnucash-style.c
index 2ef3c8f..e999620 100644
--- a/gnucash/register/register-gnome/gnucash-style.c
+++ b/gnucash/register/register-gnome/gnucash-style.c
@@ -215,9 +215,10 @@ set_dimensions_pass_one (GnucashSheet *sheet, CellBlock *cursor,
             if (cd->pixel_width > 0)
                 continue;
 
+            // This is used on new account popup cells to get the default
+            // width of text plus toggle button.
             if (cell && cell->is_popup)
-                width += gnc_item_edit_get_toggle_offset
-                         (cd->pixel_height);
+                width += cd->pixel_height; // toggle button is square, use cell height
 
             cd->pixel_width = MAX (cd->pixel_width, width);
         }

commit ed4bad34a7771ce7f287eb64f7001c307a3fe4ea
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Thu Nov 23 13:50:42 2017 +0000

    Adjust the sheet to get its spacings from the item_edit CSS

diff --git a/gnucash/register/register-gnome/gnucash-style.c b/gnucash/register/register-gnome/gnucash-style.c
index dcadb7c..2ef3c8f 100644
--- a/gnucash/register/register-gnome/gnucash-style.c
+++ b/gnucash/register/register-gnome/gnucash-style.c
@@ -169,6 +169,7 @@ set_dimensions_pass_one (GnucashSheet *sheet, CellBlock *cursor,
     int row, col;
     gint max_height = -1;
     PangoLayout *layout;
+    GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
 
     /* g_return_if_fail (font != NULL); */
 
@@ -196,13 +197,17 @@ set_dimensions_pass_one (GnucashSheet *sheet, CellBlock *cursor,
                 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), text);
                 pango_layout_get_pixel_size (layout, &width, &cd->pixel_height);
                 g_object_unref (layout);
-                width += 2 * CELL_HPADDING;
-                cd->pixel_height += 2 * CELL_VPADDING;
+                width += gnc_item_edit_get_margin (item_edit, left_right) +
+                         gnc_item_edit_get_padding_border (item_edit, left_right);
+
+                cd->pixel_height += gnc_item_edit_get_margin (item_edit, top_bottom) +
+                                    gnc_item_edit_get_padding_border (item_edit, top_bottom);
             }
             else
             {
                 width = 0;
-                cd->pixel_height = (2 * CELL_VPADDING);
+                cd->pixel_height = gnc_item_edit_get_margin (item_edit, top_bottom) +
+                                   gnc_item_edit_get_padding_border (item_edit, top_bottom);
             }
 
             max_height = MAX(max_height, cd->pixel_height);
@@ -239,6 +244,7 @@ static void
 set_dimensions_pass_two (GnucashSheet *sheet, int default_width)
 {
     SheetBlockStyle *style;
+    GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
     BlockDimensions *dimensions;
     CellDimensions *cd;
     GTable *cd_table;
@@ -315,7 +321,8 @@ set_dimensions_pass_two (GnucashSheet *sheet, int default_width)
                 pango_layout_get_pixel_size (layout, &sample_width, NULL);
                 g_object_unref (layout);
                 /*sample_width = gdk_string_width (font, text);*/
-                sample_width += 2 * CELL_HPADDING;
+                sample_width += gnc_item_edit_get_margin (item_edit, left_right) +
+                                gnc_item_edit_get_padding_border (item_edit, left_right);
             }
             else
                 sample_width = 0;

commit 2a476cb68a9b7a2edd4b2e399d38a61b6464b652
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Thu Nov 23 13:50:01 2017 +0000

    Get the item_edit cell padding from CSS instead of defines
    
    This commit sets up getting the vertical and horizontal item_edit cell
    margins, borders and padding from CSS. This increases the option to
    specify individual values for top, right, bottom and left instead of
    just specifying just two values.

diff --git a/gnucash/gnucash-310.css b/gnucash/gnucash-310.css
index e4a37a3..e6b218d 100644
--- a/gnucash/gnucash-310.css
+++ b/gnucash/gnucash-310.css
@@ -21,13 +21,14 @@
   color: mix (currentColor, grey, 0.2);
 }
 
-/* Register Cursor padding settings, make sure entry matches sheet.h */
-cursor entry {
-  padding: 2px 5px 2px 5px;
+/* Register Cursor settings, top, right, bottom, left */
+.cursor .entry {
+  margin: 2px 5px 2px 5px;  /* this only works by doing it in code, yellow area */
+  padding: 2px 2px 2px 2px; /* all work with different values, around the text blue area */
 }
 
-cursor button {
-  padding: 1px 1px 1px 1px;
+.cursor .button {
+  margin: 1px 1px 1px 1px; /* does not work, not used, here for completeness */
 }
 
 /* Register defaults */
@@ -37,7 +38,7 @@ cursor button {
 @define-color register_split_bg_color #EDE7D3;
 @define-color register_cursor_bg_color #FFEF98;
 
-.register-header {
+*.register-header {
   background-color: @register_header_bg_color;
 }
 
diff --git a/gnucash/gnucash-320.css b/gnucash/gnucash-320.css
index d7e0495..4f4ea09 100644
--- a/gnucash/gnucash-320.css
+++ b/gnucash/gnucash-320.css
@@ -12,13 +12,14 @@
   color: @negative-numbers;
 }
 
-/* Register Cursor padding settings, make sure entry matches sheet.h */
+/* Register Cursor settings, top, right, bottom, left */
 cursor entry {
-  padding: 2px 5px 2px 5px;
+  margin: 2px 5px 2px 5px;
+  padding: 0px 2px 0px 2px;
 }
 
 cursor button {
-  padding: 1px 1px 1px 1px;
+  margin: 1px 1px 1px 1px;
 }
 
 /* Register defaults */
@@ -28,7 +29,7 @@ cursor button {
 @define-color register_split_bg_color #EDE7D3;
 @define-color register_cursor_bg_color #FFEF98;
 
-.register-header {
+*.register-header {
   background-color: @register_header_bg_color;
 }
 
diff --git a/gnucash/register/register-gnome/gnucash-item-edit.c b/gnucash/register/register-gnome/gnucash-item-edit.c
index 3770dc5..047757e 100644
--- a/gnucash/register/register-gnome/gnucash-item-edit.c
+++ b/gnucash/register/register-gnome/gnucash-item-edit.c
@@ -358,6 +358,7 @@ draw_background_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data)
 static gboolean
 draw_text_cursor_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data)
 {
+    GncItemEdit *item_edit = GNC_ITEM_EDIT(user_data);
     GtkEditable *editable = GTK_EDITABLE(widget);
     GtkStyleContext *stylectxt = gtk_widget_get_style_context (GTK_WIDGET(widget));
     gint height = gtk_widget_get_allocated_height (widget);
@@ -398,8 +399,15 @@ draw_text_cursor_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data)
     // Now draw a vertical line
     cairo_set_source_rgb (cr, fg_color->red, fg_color->green, fg_color->blue);
     cairo_set_line_width (cr, 1.0);
-    cairo_move_to (cr, cursor_x + 0.5, 2);
-    cairo_rel_line_to (cr, 0, height - 4);
+#if GTK_CHECK_VERSION(3,20,0)
+    cairo_move_to (cr, cursor_x + 0.5, gnc_item_edit_get_margin (item_edit, top) +
+                                       gnc_item_edit_get_padding_border (item_edit, top));
+    cairo_rel_line_to (cr, 0, height - gnc_item_edit_get_margin (item_edit, top_bottom) -
+                                       gnc_item_edit_get_padding_border (item_edit, top_bottom));
+#else
+    cairo_move_to (cr, cursor_x + 0.5, gnc_item_edit_get_padding_border (item_edit, top));
+    cairo_rel_line_to (cr, 0, height - gnc_item_edit_get_padding_border (item_edit, top_bottom));
+#endif
     cairo_stroke (cr);
 
     return FALSE;
@@ -605,13 +613,60 @@ gnc_item_edit_get_type (void)
     return gnc_item_edit_type;
 }
 
+gint
+gnc_item_edit_get_margin (GncItemEdit *item_edit, Sides side)
+{
+    switch (side)
+    {
+    case left:
+        return item_edit->margin.left;
+    case right:
+        return item_edit->margin.right;
+    case top:
+        return item_edit->margin.top;
+    case bottom:
+        return item_edit->margin.bottom;
+    case left_right:
+        return item_edit->margin.left + item_edit->margin.right;
+    case top_bottom:
+        return item_edit->margin.top + item_edit->margin.bottom;
+    default:
+        return 2;
+    }
+}
+
+gint
+gnc_item_edit_get_padding_border (GncItemEdit *item_edit, Sides side)
+{
+    switch (side)
+    {
+    case left:
+        return item_edit->padding.left + item_edit->border.left;
+    case right:
+        return item_edit->padding.right + item_edit->border.right;
+    case top:
+        return item_edit->padding.top + item_edit->border.top;
+    case bottom:
+        return item_edit->padding.bottom + item_edit->border.bottom;
+    case left_right:
+        return item_edit->padding.left + item_edit->border.left +
+               item_edit->padding.right + item_edit->border.right;
+    case top_bottom:
+        return item_edit->padding.top + item_edit->border.top +
+               item_edit->padding.bottom + item_edit->border.bottom;
+    default:
+        return 2;
+    }
+}
 
 GtkWidget *
 gnc_item_edit_new (GnucashSheet *sheet)
 {
-    char *hpad_str, *vpad_str, *entry_css;
-    GtkStyleContext *stylecontext;
-    GtkCssProvider *provider;
+    GtkStyleContext *stylectxt;
+    GtkBorder padding;
+    GtkBorder margin;
+    GtkBorder border;
+    GtkWidget *vb = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
     GncItemEdit *item_edit =
             g_object_new (GNC_TYPE_ITEM_EDIT,
                           "sheet", sheet,
@@ -627,32 +682,54 @@ gnc_item_edit_new (GnucashSheet *sheet)
     item_edit->editor = gtk_entry_new();
     sheet->entry = item_edit->editor;
     gtk_entry_set_width_chars (GTK_ENTRY(item_edit->editor), 1);
-    gtk_box_pack_start (GTK_BOX(item_edit), item_edit->editor,  TRUE, TRUE, 0);
+    gtk_box_pack_start (GTK_BOX(item_edit), item_edit->editor, TRUE, TRUE, 0);
+
+    // Get the CSS space settings for the entry
+    stylectxt = gtk_widget_get_style_context (GTK_WIDGET(item_edit->editor));
+    gtk_style_context_get_padding (stylectxt, GTK_STATE_FLAG_NORMAL, &padding);
+    gtk_style_context_get_margin (stylectxt, GTK_STATE_FLAG_NORMAL, &margin);
+    gtk_style_context_get_border (stylectxt, GTK_STATE_FLAG_NORMAL, &border);
+
+    item_edit->padding = padding;
+    item_edit->margin = margin;
+    item_edit->border = border;
 
     // Make sure the Entry can not have focus and no frame
     gtk_widget_set_can_focus (GTK_WIDGET(item_edit->editor), FALSE);
     gtk_entry_set_has_frame (GTK_ENTRY(item_edit->editor), FALSE);
 
+#if !GTK_CHECK_VERSION(3,20,0)
+#if GTK_CHECK_VERSION(3,12,0)
+    gtk_widget_set_margin_start (GTK_WIDGET(item_edit->editor),
+                                 gnc_item_edit_get_margin (item_edit, left));
+    gtk_widget_set_margin_end (GTK_WIDGET(item_edit->editor),
+                               gnc_item_edit_get_margin (item_edit, right));
+#else
+    gtk_widget_set_margin_left (GTK_WIDGET(item_edit->editor),
+                                gnc_item_edit_get_margin (item_edit, left));
+    gtk_widget_set_margin_right (GTK_WIDGET(item_edit->editor),
+                                 gnc_item_edit_get_margin (item_edit, right));
+#endif
+    gtk_widget_set_margin_top (GTK_WIDGET(item_edit->editor),
+                               gnc_item_edit_get_margin (item_edit, top));
+    gtk_widget_set_margin_bottom (GTK_WIDGET(item_edit->editor),
+                                  gnc_item_edit_get_margin (item_edit, bottom));
+#endif
+
     // Connect to the draw signal so we can draw a cursor
     g_signal_connect_after (item_edit->editor, "draw",
-                            G_CALLBACK (draw_text_cursor_cb), NULL);
+                            G_CALLBACK (draw_text_cursor_cb), item_edit);
 
     // Fill in the background so the underlying sheet cell can not be seen
     g_signal_connect (item_edit, "draw",
                             G_CALLBACK (draw_background_cb), item_edit);
 
-    /* Force padding on the entry to align with the rest of the register this
-       is done in the gnucash.css file which should be in line with sheet.h */
-
     /* Create the popup button
        It will only be displayed when the cell being edited provides
        a popup item (like a calendar or account list) */
     item_edit->popup_toggle.tbutton = gtk_toggle_button_new();
     gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (item_edit->popup_toggle.tbutton), FALSE);
 
-    /* Force padding on the button to keep it small and display as much as
-       possible of the arrow which is done in the gnucash.css file */
-
     /* Wrap the popup button in an event box to give it its own gdkwindow.
      * Without one the button would disappear behind the grid object. */
     item_edit->popup_toggle.ebox = gtk_event_box_new();
@@ -660,11 +737,13 @@ gnc_item_edit_new (GnucashSheet *sheet)
     gtk_container_add(GTK_CONTAINER(item_edit->popup_toggle.ebox),
                       item_edit->popup_toggle.tbutton);
 
-    gtk_box_pack_start (GTK_BOX(item_edit),
-                        item_edit->popup_toggle.ebox,
-                        FALSE, TRUE, 0);
-    gtk_widget_show_all(GTK_WIDGET(item_edit));
+    /* The button needs to be packed into a vertical box so that the height and position
+     * can be controlled in ealier than Gtk3.20 versions */
+    gtk_box_pack_start (GTK_BOX(vb), item_edit->popup_toggle.ebox,
+                        FALSE, FALSE, 0);
 
+    gtk_box_pack_start (GTK_BOX(item_edit), vb, FALSE, FALSE, 0);
+    gtk_widget_show_all(GTK_WIDGET(item_edit));
     return GTK_WIDGET(item_edit);
 }
 
diff --git a/gnucash/register/register-gnome/gnucash-item-edit.h b/gnucash/register/register-gnome/gnucash-item-edit.h
index 7b8969a..a2eae31 100644
--- a/gnucash/register/register-gnome/gnucash-item-edit.h
+++ b/gnucash/register/register-gnome/gnucash-item-edit.h
@@ -86,6 +86,10 @@ typedef struct
     PopupGetWidth    popup_get_width;
     gpointer         popup_user_data;
 
+    GtkBorder        padding;
+    GtkBorder        margin;
+    GtkBorder        border;
+
     /* Where are we */
     VirtualLocation virt_loc;
 
@@ -97,6 +101,15 @@ typedef struct
     GtkBoxClass parent_class;
 } GncItemEditClass;
 
+typedef enum
+{
+    left,
+    right,
+    top,
+    bottom,
+    left_right,
+    top_bottom,
+} Sides;
 
 GType gnc_item_edit_get_type (void);
 
@@ -130,5 +143,8 @@ gboolean gnc_item_edit_get_has_selection (GncItemEdit *item_edit);
 void gnc_item_edit_focus_in (GncItemEdit *item_edit);
 void gnc_item_edit_focus_out (GncItemEdit *item_edit);
 
+gint gnc_item_edit_get_margin (GncItemEdit *item_edit, Sides side);
+gint gnc_item_edit_get_padding_border (GncItemEdit *item_edit, Sides side);
+
 /** @} */
 #endif /* GNUCASH_ITEM_EDIT_H */

commit bbafb8184e76609dad4f78a36601fcbe4c68359e
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Thu Nov 23 13:49:00 2017 +0000

    Replace the cell foreground and background colour handlers
    
    By using CSS classes, there is no need to have separate handlers for
    the foreground and background colours so replace them with one being of
    a similar format to that of cell_border_handlers. This also involves
    changing the map of RegisterColors to CSS style classes to reflect the
    changes and reduce the get colour type to one call per class

diff --git a/gnucash/register/ledger-core/gncEntryLedgerModel.c b/gnucash/register/ledger-core/gncEntryLedgerModel.c
index 8c5207d..a638d06 100644
--- a/gnucash/register/ledger-core/gncEntryLedgerModel.c
+++ b/gnucash/register/ledger-core/gncEntryLedgerModel.c
@@ -915,65 +915,57 @@ static CellIOFlags get_qty_io_flags (VirtualLocation virt_loc, gpointer user_dat
     return flags;
 }
 
-/* GET BG_COLORS */
+/* GET COLORS */
 
 static guint32
-gnc_entry_ledger_get_color_internal (VirtualLocation virt_loc,
-                                     GncEntryLedger *ledger,
-                                     gboolean foreground)
+gnc_entry_ledger_get_cell_color_internal (VirtualLocation virt_loc,
+                                          GncEntryLedger *ledger)
 {
     VirtualCell *vcell;
     gboolean is_current;
-    guint32 colorbase = 0; /* By default return background colors */
+    guint32 colorbase = 0;
 
-    if (foreground)
-        colorbase = COLOR_UNKNOWN_FG; /* a bit of enum arithmetic */
+    /* a bit of enum arithmetic */
+
+    // There are negative numbers
 
     if (!ledger)
-        return (colorbase + COLOR_UNKNOWN_BG);
+        return (colorbase + COLOR_UNDEFINED);
 
     if (gnc_table_virtual_location_in_header (ledger->table, virt_loc))
-        return (colorbase + COLOR_HEADER_BG);
+        return (colorbase + COLOR_HEADER);
 
     vcell = gnc_table_get_virtual_cell (ledger->table, virt_loc.vcell_loc);
     if (!vcell || !vcell->cellblock)
-        return (colorbase + COLOR_UNKNOWN_BG);
+        return (colorbase + COLOR_UNDEFINED);
 
     if ((virt_loc.phys_col_offset < vcell->cellblock->start_col) ||
             (virt_loc.phys_col_offset > vcell->cellblock->stop_col))
-        return (colorbase + COLOR_UNKNOWN_BG);
+        return (colorbase + COLOR_UNDEFINED);
 
     is_current = virt_cell_loc_equal (ledger->table->current_cursor_loc.vcell_loc,
                                       virt_loc.vcell_loc);
 
     if (is_current)
         return vcell->start_primary_color ?
-                (colorbase + COLOR_PRIMARY_BG_ACTIVE) :
-                (colorbase + COLOR_SECONDARY_BG_ACTIVE);
+                (colorbase + COLOR_PRIMARY_ACTIVE) :
+                (colorbase + COLOR_SECONDARY_ACTIVE);
 
     return vcell->start_primary_color ?
-            (colorbase + COLOR_PRIMARY_BG) : (colorbase + COLOR_SECONDARY_BG);
+            (colorbase + COLOR_PRIMARY) : (colorbase + COLOR_SECONDARY);
 
 }
 
 static guint32
-gnc_entry_ledger_get_fg_color (VirtualLocation virt_loc,
-                               gpointer user_data)
-{
-    GncEntryLedger *ledger = user_data;
-    return gnc_entry_ledger_get_color_internal (virt_loc, ledger, TRUE);
-}
-
-static guint32
-gnc_entry_ledger_get_bg_color (VirtualLocation virt_loc,
-                               gboolean *hatching, gpointer user_data)
+gnc_entry_ledger_get_cell_color (VirtualLocation virt_loc,
+                                 gboolean *hatching, gpointer user_data)
 {
     GncEntryLedger *ledger = user_data;
 
     if (hatching)
         *hatching = FALSE;
 
-    return gnc_entry_ledger_get_color_internal (virt_loc, ledger, FALSE);
+    return gnc_entry_ledger_get_cell_color_internal (virt_loc, ledger);
 }
 
 /* SAVE CELLS */
@@ -1225,11 +1217,8 @@ static void gnc_entry_ledger_model_new_handlers (TableModel *model,
     };
     unsigned int i;
 
-    gnc_table_model_set_default_fg_color_handler
-    (model, gnc_entry_ledger_get_fg_color);
-
-    gnc_table_model_set_default_bg_color_handler
-    (model, gnc_entry_ledger_get_bg_color);
+    // Set the cell color handler
+    gnc_table_model_set_default_cell_color_handler (model, gnc_entry_ledger_get_cell_color);
 
     for (i = 0; i < (sizeof(models) / sizeof(*models)); i++)
     {
diff --git a/gnucash/register/ledger-core/split-register-model.c b/gnucash/register/ledger-core/split-register-model.c
index 3a2fac4..f8b6614 100644
--- a/gnucash/register/ledger-core/split-register-model.c
+++ b/gnucash/register/ledger-core/split-register-model.c
@@ -514,33 +514,85 @@ get_trans_total_balance (SplitRegister *reg, Transaction *trans)
     return xaccTransGetAccountBalance(trans, account);
 }
 
+static gboolean
+gnc_split_register_use_negative_color (VirtualLocation virt_loc,
+                                       SplitRegister *reg)
+{
+    const char * cell_name;
+    gnc_numeric value;
+    Split *split;
+
+    if (!use_red_for_negative)
+        return FALSE;
+
+    split = gnc_split_register_get_split (reg, virt_loc.vcell_loc);
+    if (!split)
+        return FALSE;
+
+    cell_name = gnc_table_get_cell_name (reg->table, virt_loc);
+
+    if (gnc_cell_name_equal (cell_name, TSHRS_CELL))
+        value = get_trans_total_amount (reg, xaccSplitGetParent (split));
+    else if (gnc_cell_name_equal (cell_name, SHRS_CELL))
+    {
+        if (virt_cell_loc_equal (reg->table->current_cursor_loc.vcell_loc,
+                                      virt_loc.vcell_loc))
+            value = gnc_price_cell_get_value
+                     ((PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
+                             SHRS_CELL));
+        else
+            value = xaccSplitGetAmount (split);
+    }
+    else if (gnc_cell_name_equal (cell_name, BALN_CELL))
+        value = xaccSplitGetBalance (split);
+    else if (gnc_cell_name_equal (cell_name, RBALN_CELL))
+        value = gnc_split_register_get_rbaln (virt_loc, reg, TRUE);
+    else if (gnc_cell_name_equal (cell_name, TBALN_CELL))
+        value = get_trans_total_balance (reg, xaccSplitGetParent (split));
+
+    if ((gnc_cell_name_equal (cell_name, BALN_CELL)) ||
+            (gnc_cell_name_equal (cell_name, RBALN_CELL)) ||
+            (gnc_cell_name_equal (cell_name, TBALN_CELL)))
+        {
+            Account *account = xaccSplitGetAccount (split);
+            if (gnc_reverse_balance (account))
+                value = gnc_numeric_neg (value);
+        }
+
+    if (gnc_numeric_negative_p (value))
+        return TRUE;
+
+    return FALSE;
+}
+
 static guint32
-gnc_split_register_get_color_internal (VirtualLocation virt_loc,
-                                       SplitRegister *reg,
-                                       gboolean foreground)
+gnc_split_register_get_cell_color_internal (VirtualLocation virt_loc,
+                                            SplitRegister *reg)
 {
     const char *cursor_name;
     VirtualCell *vcell;
     gboolean is_current;
     gboolean double_alternate_virt;
-    guint32 colorbase = 0; /* By default return background colors */
+    guint32 colorbase = 0;
 
-    if (foreground)
-        colorbase = COLOR_UNKNOWN_FG; /* a bit of enum arithmetic */
+     /* a bit of enum arithmetic */
+
+    if (gnc_split_register_use_negative_color (virt_loc, reg))
+        colorbase = COLOR_NEGATIVE; // Requires Negative fg color
 
     if (!reg)
-        return (colorbase + COLOR_UNKNOWN_BG);
+        return (colorbase + COLOR_UNDEFINED);
 
     if (gnc_table_virtual_location_in_header (reg->table, virt_loc))
-        return (colorbase + COLOR_HEADER_BG);
+        return (colorbase + COLOR_HEADER);
 
     vcell = gnc_table_get_virtual_cell (reg->table, virt_loc.vcell_loc);
     if (!vcell || !vcell->cellblock)
-        return (colorbase + COLOR_UNKNOWN_BG);
+        return (colorbase + COLOR_UNDEFINED);
 
     if ((virt_loc.phys_col_offset < vcell->cellblock->start_col) ||
             (virt_loc.phys_col_offset > vcell->cellblock->stop_col))
-        return (colorbase + COLOR_UNKNOWN_BG);
+        return (colorbase + COLOR_UNDEFINED);
 
     is_current = virt_cell_loc_equal (reg->table->current_cursor_loc.vcell_loc,
                                       virt_loc.vcell_loc);
@@ -552,11 +604,11 @@ gnc_split_register_get_color_internal (VirtualLocation virt_loc,
     {
         if (is_current)
             return vcell->start_primary_color ?
-                    (colorbase + COLOR_PRIMARY_BG_ACTIVE) :
-                    (colorbase + COLOR_SECONDARY_BG_ACTIVE);
+                    (colorbase + COLOR_PRIMARY_ACTIVE) :
+                    (colorbase + COLOR_SECONDARY_ACTIVE);
 
         return vcell->start_primary_color ?
-                (colorbase + COLOR_PRIMARY_BG) : (colorbase + COLOR_SECONDARY_BG);
+                (colorbase + COLOR_PRIMARY) : (colorbase + COLOR_SECONDARY);
     }
 
     if (g_strcmp0 (cursor_name, CURSOR_DOUBLE_JOURNAL) == 0 ||
@@ -570,101 +622,40 @@ gnc_split_register_get_color_internal (VirtualLocation virt_loc,
         {
             if (double_alternate_virt)
                 return vcell->start_primary_color ?
-                        (colorbase + COLOR_PRIMARY_BG_ACTIVE) :
-                        (colorbase + COLOR_SECONDARY_BG_ACTIVE);
+                        (colorbase + COLOR_PRIMARY_ACTIVE) :
+                        (colorbase + COLOR_SECONDARY_ACTIVE);
 
             return (virt_loc.phys_row_offset % 2 == 0) ?
-                    (colorbase + COLOR_PRIMARY_BG_ACTIVE) :
-                    (colorbase + COLOR_SECONDARY_BG_ACTIVE);
+                    (colorbase + COLOR_PRIMARY_ACTIVE) :
+                    (colorbase + COLOR_SECONDARY_ACTIVE);
         }
 
         if (double_alternate_virt)
             return vcell->start_primary_color ?
-                    (colorbase + COLOR_PRIMARY_BG) :
-                    (colorbase + COLOR_SECONDARY_BG);
+                    (colorbase + COLOR_PRIMARY) :
+                    (colorbase + COLOR_SECONDARY);
 
         return (virt_loc.phys_row_offset % 2 == 0) ?
-                (colorbase + COLOR_PRIMARY_BG) :
-                (colorbase + COLOR_SECONDARY_BG);
+                (colorbase + COLOR_PRIMARY) :
+                (colorbase + COLOR_SECONDARY);
     }
 
     if (g_strcmp0 (cursor_name, CURSOR_SPLIT) == 0)
     {
         if (is_current)
-            return (colorbase + COLOR_SPLIT_BG_ACTIVE);
+            return (colorbase + COLOR_SPLIT_ACTIVE);
 
-        return (colorbase + COLOR_SPLIT_BG);
+        return (colorbase + COLOR_SPLIT);
     }
 
     PWARN ("Unexpected cursor: %s\n", cursor_name);
 
-    return (colorbase + COLOR_UNKNOWN_BG);
+    return (colorbase + COLOR_UNDEFINED);
 }
 
+// Get Color for non numeric cells, no hatching required
 static guint32
-gnc_split_register_get_fg_color_internal (VirtualLocation virt_loc,
-                                          SplitRegister *reg)
-{
-    guint32 fg_color;
-    const char * cell_name;
-    gnc_numeric value;
-    Split *split;
-
-    fg_color = gnc_split_register_get_color_internal (virt_loc, reg, TRUE);
-
-    if (!use_red_for_negative)
-        return fg_color;
-
-    split = gnc_split_register_get_split (reg, virt_loc.vcell_loc);
-    if (!split)
-        return fg_color;
-
-    cell_name = gnc_table_get_cell_name (reg->table, virt_loc);
-
-    if (gnc_cell_name_equal (cell_name, TSHRS_CELL))
-        value = get_trans_total_amount (reg, xaccSplitGetParent (split));
-    else if (gnc_cell_name_equal (cell_name, SHRS_CELL))
-    {
-        if (virt_cell_loc_equal (reg->table->current_cursor_loc.vcell_loc,
-                                      virt_loc.vcell_loc))
-            value = gnc_price_cell_get_value
-                     ((PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
-                             SHRS_CELL));
-        else
-            value = xaccSplitGetAmount (split);
-    }
-    else if (gnc_cell_name_equal (cell_name, BALN_CELL))
-        value = xaccSplitGetBalance (split);
-    else if (gnc_cell_name_equal (cell_name, RBALN_CELL))
-        value = gnc_split_register_get_rbaln (virt_loc, reg, TRUE);
-    else if (gnc_cell_name_equal (cell_name, TBALN_CELL))
-        value = get_trans_total_balance (reg, xaccSplitGetParent (split));
-
-    if ((gnc_cell_name_equal (cell_name, BALN_CELL)) ||
-            (gnc_cell_name_equal (cell_name, RBALN_CELL)) ||
-            (gnc_cell_name_equal (cell_name, TBALN_CELL)))
-        {
-            Account *account = xaccSplitGetAccount (split);
-            if (gnc_reverse_balance (account))
-                value = gnc_numeric_neg (value);
-        }
-
-    if (gnc_numeric_negative_p (value))
-        return COLOR_NEGATIVE;
-
-    return fg_color;
-}
-
-static guint32
-gnc_split_register_get_fg_color (VirtualLocation virt_loc,
-                                 gpointer user_data)
-{
-    SplitRegister *reg = user_data;
-    return gnc_split_register_get_fg_color_internal (virt_loc, reg);
-}
-
-static guint32
-gnc_split_register_get_bg_color (VirtualLocation virt_loc,
+gnc_split_register_get_cell_color (VirtualLocation virt_loc,
         gboolean *hatching,
         gpointer user_data)
 {
@@ -673,11 +664,12 @@ gnc_split_register_get_bg_color (VirtualLocation virt_loc,
     if (hatching)
         *hatching = FALSE;
 
-    return gnc_split_register_get_color_internal (virt_loc, reg, FALSE);
+    return gnc_split_register_get_cell_color_internal (virt_loc, reg);
 }
 
+// Get Color for numeric cells, update hatching
 static guint32
-gnc_split_register_get_debcred_bg_color (VirtualLocation virt_loc,
+gnc_split_register_get_debcred_color (VirtualLocation virt_loc,
         gboolean *hatching,
         gpointer user_data)
 {
@@ -694,8 +686,7 @@ gnc_split_register_get_debcred_bg_color (VirtualLocation virt_loc,
         else
             *hatching = FALSE;
     }
-
-    return gnc_split_register_get_bg_color (virt_loc, NULL, user_data);
+    return gnc_split_register_get_cell_color_internal (virt_loc, reg);
 }
 
 static void
@@ -2623,42 +2614,26 @@ gnc_split_register_model_new (void)
         model, gnc_split_register_get_security_io_flags, SHRS_CELL);
 
 
-    gnc_table_model_set_fg_color_handler(
-        model, gnc_split_register_get_fg_color, SHRS_CELL);
-
-    gnc_table_model_set_fg_color_handler(
-        model, gnc_split_register_get_fg_color, TSHRS_CELL);
-
-    gnc_table_model_set_fg_color_handler(
-        model, gnc_split_register_get_fg_color, BALN_CELL);
-
-    gnc_table_model_set_fg_color_handler(
-        model, gnc_split_register_get_fg_color, TBALN_CELL);
-
-    gnc_table_model_set_fg_color_handler(
-        model, gnc_split_register_get_fg_color, RBALN_CELL);
-
-
-    gnc_table_model_set_default_bg_color_handler(
-        model, gnc_split_register_get_bg_color);
+    gnc_table_model_set_default_cell_color_handler(
+        model, gnc_split_register_get_cell_color);
 
-    gnc_table_model_set_bg_color_handler(
-        model, gnc_split_register_get_debcred_bg_color, DEBT_CELL);
+    gnc_table_model_set_cell_color_handler(
+        model, gnc_split_register_get_debcred_color, DEBT_CELL);
 
-    gnc_table_model_set_bg_color_handler(
-        model, gnc_split_register_get_debcred_bg_color, CRED_CELL);
+    gnc_table_model_set_cell_color_handler(
+        model, gnc_split_register_get_debcred_color, CRED_CELL);
 
-    gnc_table_model_set_bg_color_handler(
-        model, gnc_split_register_get_debcred_bg_color, TDEBT_CELL);
+    gnc_table_model_set_cell_color_handler(
+        model, gnc_split_register_get_debcred_color, TDEBT_CELL);
 
-    gnc_table_model_set_bg_color_handler(
-        model, gnc_split_register_get_debcred_bg_color, TCRED_CELL);
+    gnc_table_model_set_cell_color_handler(
+        model, gnc_split_register_get_debcred_color, TCRED_CELL);
 
-    gnc_table_model_set_bg_color_handler(
-        model, gnc_split_register_get_debcred_bg_color, FCRED_CELL);
+    gnc_table_model_set_cell_color_handler(
+        model, gnc_split_register_get_debcred_color, FCRED_CELL);
 
-    gnc_table_model_set_bg_color_handler(
-        model, gnc_split_register_get_debcred_bg_color, FDEBT_CELL);
+    gnc_table_model_set_cell_color_handler(
+        model, gnc_split_register_get_debcred_color, FDEBT_CELL);
 
 
     gnc_table_model_set_default_cell_border_handler(
diff --git a/gnucash/register/register-core/table-allgui.c b/gnucash/register/register-core/table-allgui.c
index 7e407db..038d3b0 100644
--- a/gnucash/register/register-core/table-allgui.c
+++ b/gnucash/register/register-core/table-allgui.c
@@ -345,68 +345,29 @@ gnc_table_get_label (Table *table, VirtualLocation virt_loc)
     return label;
 }
 
-static guint32
-gnc_table_get_fg_color_internal (Table *table, VirtualLocation virt_loc)
-{
-    TableGetFGColorHandler fg_color_handler;
-    const char *handler_name;
-
-    if (!table || !table->model)
-        return COLOR_UNKNOWN_FG;
-
-    handler_name = gnc_table_get_cell_name (table, virt_loc);
-
-    fg_color_handler = gnc_table_model_get_fg_color_handler (table->model,
-                       handler_name);
-    if (!fg_color_handler)
-    {
-        TableGetBGColorHandler bg_color_handler =
-            gnc_table_model_get_bg_color_handler (table->model, handler_name);
-
-        guint32 bg_color =
-            bg_color_handler (virt_loc, NULL, table->model->handler_user_data);
-        return bg_color + COLOR_UNKNOWN_FG;
-    }
-
-    return fg_color_handler (virt_loc, table->model->handler_user_data);
-}
-
 guint32
-gnc_table_get_fg_color (Table *table, VirtualLocation virt_loc)
-{
-    return gnc_table_get_fg_color_internal (table, virt_loc);
-}
-
-static guint32
-gnc_table_get_bg_color_internal (Table *table, VirtualLocation virt_loc,
+gnc_table_get_color (Table *table, VirtualLocation virt_loc,
                                  gboolean *hatching)
 {
-    TableGetBGColorHandler bg_color_handler;
+    TableGetCellColorHandler color_handler;
     const char *handler_name;
 
     if (hatching)
         *hatching = FALSE;
 
     if (!table || !table->model)
-        return COLOR_UNKNOWN_BG;
+        return COLOR_UNDEFINED;
 
     handler_name = gnc_table_get_cell_name (table, virt_loc);
 
-    bg_color_handler = gnc_table_model_get_bg_color_handler (table->model,
-            handler_name);
-
-    if (!bg_color_handler)
-        return COLOR_UNKNOWN_BG;
+    color_handler = gnc_table_model_get_cell_color_handler (table->model,
+                                                            handler_name);
 
-    return bg_color_handler (virt_loc, hatching,
-                             table->model->handler_user_data);
-}
+    if (!color_handler)
+        return COLOR_UNDEFINED;
 
-guint32
-gnc_table_get_bg_color (Table *table, VirtualLocation virt_loc,
-                        gboolean *hatching)
-{
-    return gnc_table_get_bg_color_internal (table, virt_loc, hatching);
+    return color_handler (virt_loc, hatching,
+                          table->model->handler_user_data);
 }
 
 void
diff --git a/gnucash/register/register-core/table-allgui.h b/gnucash/register/register-core/table-allgui.h
index d827fd5..3b4fa26 100644
--- a/gnucash/register/register-core/table-allgui.h
+++ b/gnucash/register/register-core/table-allgui.h
@@ -179,35 +179,19 @@ struct table
 };
 
 /** Color definitions used for table elements */
-typedef enum
-{
-    /* Colors used for background drawing */
-    COLOR_UNKNOWN_BG,          // 0
-    COLOR_HEADER_BG,           // 1
-    COLOR_PRIMARY_BG,          // 2
-    COLOR_PRIMARY_BG_ACTIVE,   // 3
-    COLOR_SECONDARY_BG,        // 4
-    COLOR_SECONDARY_BG_ACTIVE, // 5
-    COLOR_SPLIT_BG,            // 6
-    COLOR_SPLIT_BG_ACTIVE,     // 7
-
-    /* Colors used for foreground drawing (text etc)
-     * ATTENTION: the background and foreground lists should have
-     *            the same types (the same amount of entries) !
-     *            The code relies on this ! */
-    COLOR_UNKNOWN_FG,          // 8
-    COLOR_HEADER_FG,           // 9
-    COLOR_PRIMARY_FG,          // 10
-    COLOR_PRIMARY_FG_ACTIVE,   // 11
-    COLOR_SECONDARY_FG,        // 12
-    COLOR_SECONDARY_FG_ACTIVE, // 13
-    COLOR_SPLIT_FG,            // 14
-    COLOR_SPLIT_FG_ACTIVE,     // 15
-
-    /* Other colors */
-    COLOR_NEGATIVE,            // 16 Color to use for negative numbers
+typedef enum {
+    COLOR_UNDEFINED = 0,      // 0
+    COLOR_HEADER,             // 1
+    COLOR_PRIMARY,            // 2
+    COLOR_PRIMARY_ACTIVE,     // 3
+    COLOR_SECONDARY,          // 4
+    COLOR_SECONDARY_ACTIVE,   // 5
+    COLOR_SPLIT,              // 6
+    COLOR_SPLIT_ACTIVE,       // 7
+    COLOR_NEGATIVE = 16,      // 16
 } RegisterColor;
 
+
 /** Set the default gui handlers used by new tables. */
 void gnc_table_set_default_gui_handlers (TableGUIHandlers *gui_handlers);
 
@@ -258,9 +242,7 @@ const char *   gnc_table_get_label (Table *table, VirtualLocation virt_loc);
 
 CellIOFlags    gnc_table_get_io_flags (Table *table, VirtualLocation virt_loc);
 
-guint32        gnc_table_get_fg_color (Table *table, VirtualLocation virt_loc);
-
-guint32        gnc_table_get_bg_color (Table *table, VirtualLocation virt_loc,
+guint32        gnc_table_get_color (Table *table, VirtualLocation virt_loc,
                                        gboolean *hatching);
 
 void           gnc_table_get_borders (Table *table, VirtualLocation virt_loc,
diff --git a/gnucash/register/register-core/table-model.c b/gnucash/register/register-core/table-model.c
index c76310e..a5baee2 100644
--- a/gnucash/register/register-core/table-model.c
+++ b/gnucash/register/register-core/table-model.c
@@ -134,8 +134,7 @@ gnc_table_model_new (void)
     model->label_handlers = gnc_table_model_handler_hash_new ();
     model->help_handlers = gnc_table_model_handler_hash_new ();
     model->io_flags_handlers = gnc_table_model_handler_hash_new ();
-    model->fg_color_handlers = gnc_table_model_handler_hash_new ();
-    model->bg_color_handlers = gnc_table_model_handler_hash_new ();
+    model->cell_color_handlers = gnc_table_model_handler_hash_new ();
     model->cell_border_handlers = gnc_table_model_handler_hash_new ();
     model->confirm_handlers = gnc_table_model_handler_hash_new ();
     model->save_handlers = gnc_table_model_handler_hash_new ();
@@ -165,11 +164,8 @@ gnc_table_model_destroy (TableModel *model)
     gnc_table_model_handler_hash_destroy (model->io_flags_handlers);
     model->io_flags_handlers = NULL;
 
-    gnc_table_model_handler_hash_destroy (model->fg_color_handlers);
-    model->fg_color_handlers = NULL;
-
-    gnc_table_model_handler_hash_destroy (model->bg_color_handlers);
-    model->bg_color_handlers = NULL;
+    gnc_table_model_handler_hash_destroy (model->cell_color_handlers);
+    model->cell_color_handlers = NULL;
 
     gnc_table_model_handler_hash_destroy (model->cell_border_handlers);
     model->cell_border_handlers = NULL;
@@ -334,75 +330,39 @@ gnc_table_model_get_io_flags_handler (TableModel *model,
 }
 
 void
-gnc_table_model_set_fg_color_handler
+gnc_table_model_set_cell_color_handler
 (TableModel *model,
- TableGetFGColorHandler fg_color_handler,
+ TableGetCellColorHandler color_handler,
  const char * cell_name)
 {
     g_return_if_fail (model != NULL);
     g_return_if_fail (cell_name != NULL);
 
-    gnc_table_model_handler_hash_insert (model->fg_color_handlers,
+    gnc_table_model_handler_hash_insert (model->cell_color_handlers,
                                          cell_name,
-                                         fg_color_handler);
+                                         color_handler);
 }
 
 void
-gnc_table_model_set_default_fg_color_handler
+gnc_table_model_set_default_cell_color_handler
 (TableModel *model,
- TableGetFGColorHandler fg_color_handler)
+ TableGetCellColorHandler color_handler)
 {
     g_return_if_fail (model != NULL);
 
-    gnc_table_model_handler_hash_insert (model->fg_color_handlers,
+    gnc_table_model_handler_hash_insert (model->cell_color_handlers,
                                          DEFAULT_HANDLER,
-                                         fg_color_handler);
-}
-
-TableGetFGColorHandler
-gnc_table_model_get_fg_color_handler (TableModel *model,
-                                      const char * cell_name)
-{
-    g_return_val_if_fail (model != NULL, NULL);
-
-    return gnc_table_model_handler_hash_lookup (model->fg_color_handlers,
-            cell_name);
+                                         color_handler);
 }
 
-void
-gnc_table_model_set_bg_color_handler
-(TableModel *model,
- TableGetBGColorHandler bg_color_handler,
- const char * cell_name)
-{
-    g_return_if_fail (model != NULL);
-    g_return_if_fail (cell_name != NULL);
-
-    gnc_table_model_handler_hash_insert (model->bg_color_handlers,
-                                         cell_name,
-                                         bg_color_handler);
-}
-
-void
-gnc_table_model_set_default_bg_color_handler
-(TableModel *model,
- TableGetBGColorHandler bg_color_handler)
-{
-    g_return_if_fail (model != NULL);
-
-    gnc_table_model_handler_hash_insert (model->bg_color_handlers,
-                                         DEFAULT_HANDLER,
-                                         bg_color_handler);
-}
-
-TableGetBGColorHandler
-gnc_table_model_get_bg_color_handler (TableModel *model,
-                                      const char * cell_name)
+TableGetCellColorHandler
+gnc_table_model_get_cell_color_handler (TableModel *model,
+                                   const char * cell_name)
 {
     g_return_val_if_fail (model != NULL, NULL);
 
-    return gnc_table_model_handler_hash_lookup (model->bg_color_handlers,
-            cell_name);
+    return gnc_table_model_handler_hash_lookup (model->cell_color_handlers,
+                                                cell_name);
 }
 
 void
diff --git a/gnucash/register/register-core/table-model.h b/gnucash/register/register-core/table-model.h
index 268757e..2d489a6 100644
--- a/gnucash/register/register-core/table-model.h
+++ b/gnucash/register/register-core/table-model.h
@@ -76,10 +76,7 @@ typedef char * (*TableGetHelpHandler) (VirtualLocation virt_loc,
 typedef CellIOFlags (*TableGetCellIOFlagsHandler) (VirtualLocation virt_loc,
         gpointer user_data);
 
-typedef guint32 (*TableGetFGColorHandler) (VirtualLocation virt_loc,
-        gpointer user_data);
-
-typedef guint32 (*TableGetBGColorHandler) (VirtualLocation virt_loc,
+typedef guint32 (*TableGetCellColorHandler) (VirtualLocation virt_loc,
         gboolean *hatching,
         gpointer user_data);
 
@@ -107,8 +104,7 @@ typedef struct
     GHashTable *label_handlers;
     GHashTable *help_handlers;
     GHashTable *io_flags_handlers;
-    GHashTable *fg_color_handlers;
-    GHashTable *bg_color_handlers;
+    GHashTable *cell_color_handlers;
     GHashTable *cell_border_handlers;
     GHashTable *confirm_handlers;
 
@@ -189,25 +185,14 @@ TableGetCellIOFlagsHandler gnc_table_model_get_io_flags_handler
 (TableModel *model,
  const char * cell_name);
 
-void gnc_table_model_set_fg_color_handler
-(TableModel *model,
- TableGetFGColorHandler io_flags_handler,
- const char * cell_name);
-void gnc_table_model_set_default_fg_color_handler
-(TableModel *model,
- TableGetFGColorHandler io_flags_handler);
-TableGetFGColorHandler gnc_table_model_get_fg_color_handler
-(TableModel *model,
- const char * cell_name);
-
-void gnc_table_model_set_bg_color_handler
+void gnc_table_model_set_cell_color_handler
 (TableModel *model,
- TableGetBGColorHandler io_flags_handler,
+ TableGetCellColorHandler io_flags_handler,
  const char * cell_name);
-void gnc_table_model_set_default_bg_color_handler
+ void gnc_table_model_set_default_cell_color_handler
 (TableModel *model,
- TableGetBGColorHandler io_flags_handler);
-TableGetBGColorHandler gnc_table_model_get_bg_color_handler
+ TableGetCellColorHandler io_flags_handler);
+TableGetCellColorHandler gnc_table_model_get_cell_color_handler
 (TableModel *model,
  const char * cell_name);
 
diff --git a/gnucash/register/register-gnome/gnucash-header.c b/gnucash/register/register-gnome/gnucash-header.c
index 247d08f..2f6d4d2 100644
--- a/gnucash/register/register-gnome/gnucash-header.c
+++ b/gnucash/register/register-gnome/gnucash-header.c
@@ -87,8 +87,8 @@ gnc_header_draw_offscreen (GncHeader *header)
 
     gtk_style_context_save (stylectxt);
 
-    // Get the background color type and apply the css class
-    color_type = gnc_table_get_bg_color (table, virt_loc, NULL);
+    // Get the color type and apply the css class
+    color_type = gnc_table_get_color (table, virt_loc, NULL);
     gnucash_get_style_classes (header->sheet, stylectxt, color_type);
 
     if (header->surface)
diff --git a/gnucash/register/register-gnome/gnucash-item-edit.c b/gnucash/register/register-gnome/gnucash-item-edit.c
index 91aa497..3770dc5 100644
--- a/gnucash/register/register-gnome/gnucash-item-edit.c
+++ b/gnucash/register/register-gnome/gnucash-item-edit.c
@@ -344,11 +344,8 @@ draw_background_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data)
 
     gtk_style_context_save (stylectxt);
 
-    // Get the background and foreground color types and apply the css class
-    color_type = gnc_table_get_bg_color (item_edit->sheet->table, item_edit->virt_loc, NULL);
-    gnucash_get_style_classes (item_edit->sheet, stylectxt, color_type);
-
-    color_type = gnc_table_get_fg_color (item_edit->sheet->table, item_edit->virt_loc);
+    // Get the color type and apply the css class
+    color_type = gnc_table_get_color (item_edit->sheet->table, item_edit->virt_loc, NULL);
     gnucash_get_style_classes (item_edit->sheet, stylectxt, color_type);
 
     gtk_render_background (stylectxt, cr, 0, 1, width, height - 2);
diff --git a/gnucash/register/register-gnome/gnucash-sheet-private.c b/gnucash/register/register-gnome/gnucash-sheet-private.c
index a286abe..8b0d067 100644
--- a/gnucash/register/register-gnome/gnucash-sheet-private.c
+++ b/gnucash/register/register-gnome/gnucash-sheet-private.c
@@ -398,11 +398,8 @@ draw_cell (GnucashSheet *sheet,
 
     gtk_style_context_save (stylectxt);
 
-    // Get the background and foreground color types and apply the css class
-    color_type = gnc_table_get_bg_color (table, virt_loc, &hatching);
-    gnucash_get_style_classes (sheet, stylectxt, color_type);
-
-    color_type = gnc_table_get_fg_color (table, virt_loc);
+    // Get the color type and apply the css class
+    color_type = gnc_table_get_color (table, virt_loc, &hatching);
     gnucash_get_style_classes (sheet, stylectxt, color_type);
 
     // Are we in a read-only row? Then make the background color somewhat more grey.
diff --git a/gnucash/register/register-gnome/gnucash-sheet.c b/gnucash/register/register-gnome/gnucash-sheet.c
index d8a6cea..e2a759a 100644
--- a/gnucash/register/register-gnome/gnucash-sheet.c
+++ b/gnucash/register/register-gnome/gnucash-sheet.c
@@ -2407,52 +2407,46 @@ gnucash_sheet_table_load (GnucashSheet *sheet, gboolean do_scroll)
 
 /*************************************************************/
 
-/** Map a cell type to a css style class. */
+/** Map a cell color type to a css style class. */
 void
 gnucash_get_style_classes (GnucashSheet *sheet, GtkStyleContext *stylectxt,
                            RegisterColor field_type)
 {
     gchar *full_class, *style_class = NULL;
 
+    if (field_type >= COLOR_NEGATIVE) // Require a Negative fg color
+    {
+        gtk_style_context_add_class (stylectxt, "negative-numbers");
+        field_type -= COLOR_NEGATIVE;
+    }
+
     switch (field_type)
     {
     default:
-    case COLOR_UNKNOWN_BG:
-    case COLOR_UNKNOWN_FG:
+    case COLOR_UNDEFINED:
         gtk_style_context_add_class (stylectxt, GTK_STYLE_CLASS_BACKGROUND);
         return;
 
-    case COLOR_NEGATIVE:
-        gtk_style_context_add_class (stylectxt, "negative-numbers");
-        return;
-
-    case COLOR_HEADER_BG:
-    case COLOR_HEADER_FG:
+    case COLOR_HEADER:
         style_class = "header";
         break;
 
-    case COLOR_PRIMARY_BG:
-    case COLOR_PRIMARY_FG:
+    case COLOR_PRIMARY:
         style_class = "primary";
         break;
 
-    case COLOR_PRIMARY_BG_ACTIVE:
-    case COLOR_PRIMARY_FG_ACTIVE:
-    case COLOR_SECONDARY_BG_ACTIVE:
-    case COLOR_SECONDARY_FG_ACTIVE:
-    case COLOR_SPLIT_BG_ACTIVE:
-    case COLOR_SPLIT_FG_ACTIVE:
+    case COLOR_PRIMARY_ACTIVE:
+    case COLOR_SECONDARY_ACTIVE:
+    case COLOR_SPLIT_ACTIVE:
         gtk_style_context_set_state (stylectxt, GTK_STATE_FLAG_SELECTED);
         style_class = "cursor";
         break;
 
-    case COLOR_SECONDARY_BG:
-    case COLOR_SECONDARY_FG:
+    case COLOR_SECONDARY:
         style_class = "secondary";
         break;
 
-    case COLOR_SPLIT_BG:
-    case COLOR_SPLIT_FG:
+    case COLOR_SPLIT:
         style_class = "split";
         break;
     }

commit 9cd2c6d17fcac36941e189560d1a7c7de036cb1f
Author: Robert Fewell <14uBobIT at gmail.com>
Date:   Wed Nov 1 12:17:19 2017 +0000

    Test the widget state to get the correct background colour.
    
    When the cell borders are not displayed, the border colour is set to
    the background colour so test for the widget being in an insensitive
    state to get the correct background colour.

diff --git a/gnucash/register/register-gnome/gnucash-sheet-private.c b/gnucash/register/register-gnome/gnucash-sheet-private.c
index 955f607..a286abe 100644
--- a/gnucash/register/register-gnome/gnucash-sheet-private.c
+++ b/gnucash/register/register-gnome/gnucash-sheet-private.c
@@ -417,7 +417,8 @@ draw_cell (GnucashSheet *sheet,
     gtk_render_background (stylectxt, cr, x, y, width, height);
 
     gdk_rgba_parse (&color, "black");
-    gnc_style_context_get_background_color (stylectxt, GTK_STATE_FLAG_NORMAL, &color);
+    gnc_style_context_get_background_color (stylectxt, gtk_style_context_get_state (stylectxt),
+                                            &color);
     bg_color = &color;
 
     get_cell_borders (sheet, virt_loc, &borders);

commit 937f8c508301a26ede211ee4ed06ad7a91bd2198
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Nov 21 18:12:30 2017 -0800

    Set GncSqlObjectBackend::m_version to the appropriate TABLE_VERSION.
    
    For each subclass, getting rid of GNC_SQL_OBJECT_BACKEND_VERSION which
    was a bit misguided.
    
    Also remove the bogus test the skipped loading a table if its version
    didn't match GNC_SQL_OBJECT_BACKEND_VERSION which was even more misguided.

diff --git a/libgnucash/backend/sql/gnc-account-sql.cpp b/libgnucash/backend/sql/gnc-account-sql.cpp
index 7f2bde0..f0113ed 100644
--- a/libgnucash/backend/sql/gnc-account-sql.cpp
+++ b/libgnucash/backend/sql/gnc-account-sql.cpp
@@ -101,7 +101,7 @@ static EntryVec parent_col_table
 });
 
 GncSqlAccountBackend::GncSqlAccountBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_ACCOUNT,
+    GncSqlObjectBackend(TABLE_VERSION, GNC_ID_ACCOUNT,
                         TABLE_NAME, col_table) {}
 
 struct ParentGuid
diff --git a/libgnucash/backend/sql/gnc-bill-term-sql.cpp b/libgnucash/backend/sql/gnc-bill-term-sql.cpp
index 8d77b94..ae813d8 100644
--- a/libgnucash/backend/sql/gnc-bill-term-sql.cpp
+++ b/libgnucash/backend/sql/gnc-bill-term-sql.cpp
@@ -103,7 +103,7 @@ static EntryVec billterm_parent_col_table
 };
 
 GncSqlBillTermBackend::GncSqlBillTermBackend() :
-        GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_BILLTERM,
+        GncSqlObjectBackend(TABLE_VERSION, GNC_ID_BILLTERM,
                             TABLE_NAME, col_table) {}
 
 struct BillTermParentGuid
@@ -315,7 +315,7 @@ GncSqlBillTermBackend::create_tables (GncSqlBackend* sql_be)
     {
         sql_be->create_table(TABLE_NAME, TABLE_VERSION, col_table);
     }
-    else if (version == 1)
+    else if (version < m_version)
     {
         /* Upgrade 64 bit int handling */
         sql_be->upgrade_table(TABLE_NAME, col_table);
diff --git a/libgnucash/backend/sql/gnc-book-sql.cpp b/libgnucash/backend/sql/gnc-book-sql.cpp
index bfe8ee6..d38487d 100644
--- a/libgnucash/backend/sql/gnc-book-sql.cpp
+++ b/libgnucash/backend/sql/gnc-book-sql.cpp
@@ -73,7 +73,7 @@ static const EntryVec col_table
 };
 
 GncSqlBookBackend::GncSqlBookBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_BOOK,
+    GncSqlObjectBackend(TABLE_VERSION, GNC_ID_BOOK,
                         BOOK_TABLE, col_table) {}
 
 /* ================================================================= */
diff --git a/libgnucash/backend/sql/gnc-budget-sql.cpp b/libgnucash/backend/sql/gnc-budget-sql.cpp
index 48f1a8e..9ad5fba 100644
--- a/libgnucash/backend/sql/gnc-budget-sql.cpp
+++ b/libgnucash/backend/sql/gnc-budget-sql.cpp
@@ -81,7 +81,7 @@ static gnc_numeric get_amount (gpointer pObj);
 static void set_amount (gpointer pObj, gnc_numeric value);
 
 GncSqlBudgetBackend::GncSqlBudgetBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_BUDGET,
+    GncSqlObjectBackend(TABLE_VERSION, GNC_ID_BUDGET,
                         BUDGET_TABLE, col_table) {}
 
 typedef struct
diff --git a/libgnucash/backend/sql/gnc-commodity-sql.cpp b/libgnucash/backend/sql/gnc-commodity-sql.cpp
index 45a710d..dad6877 100644
--- a/libgnucash/backend/sql/gnc-commodity-sql.cpp
+++ b/libgnucash/backend/sql/gnc-commodity-sql.cpp
@@ -88,7 +88,7 @@ static const EntryVec col_table
 };
 
 GncSqlCommodityBackend::GncSqlCommodityBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_COMMODITY,
+    GncSqlObjectBackend(TABLE_VERSION, GNC_ID_COMMODITY,
                         COMMODITIES_TABLE, col_table) {}
 /* ================================================================= */
 
diff --git a/libgnucash/backend/sql/gnc-customer-sql.cpp b/libgnucash/backend/sql/gnc-customer-sql.cpp
index ce19873..de713eb 100644
--- a/libgnucash/backend/sql/gnc-customer-sql.cpp
+++ b/libgnucash/backend/sql/gnc-customer-sql.cpp
@@ -94,7 +94,7 @@ static EntryVec col_table
 });
 
 GncSqlCustomerBackend::GncSqlCustomerBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_CUSTOMER,
+    GncSqlObjectBackend(TABLE_VERSION, GNC_ID_CUSTOMER,
                         TABLE_NAME, col_table) {}
 
 static GncCustomer*
@@ -152,7 +152,7 @@ GncSqlCustomerBackend::create_tables (GncSqlBackend* sql_be)
     {
         sql_be->create_table(TABLE_NAME, TABLE_VERSION, col_table);
     }
-    else if (version == 1)
+    else if (version < m_version)
     {
         /* Upgrade 64 bit int handling */
         sql_be->upgrade_table(TABLE_NAME, col_table);
diff --git a/libgnucash/backend/sql/gnc-employee-sql.cpp b/libgnucash/backend/sql/gnc-employee-sql.cpp
index 6b72eba..79c6346 100644
--- a/libgnucash/backend/sql/gnc-employee-sql.cpp
+++ b/libgnucash/backend/sql/gnc-employee-sql.cpp
@@ -79,7 +79,7 @@ static EntryVec col_table
 });
 
 GncSqlEmployeeBackend::GncSqlEmployeeBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_EMPLOYEE,
+    GncSqlObjectBackend(TABLE_VERSION, GNC_ID_EMPLOYEE,
                         TABLE_NAME, col_table) {}
 
 static GncEmployee*
@@ -138,7 +138,7 @@ GncSqlEmployeeBackend::create_tables (GncSqlBackend* sql_be)
     {
         sql_be->create_table(TABLE_NAME, TABLE_VERSION, col_table);
     }
-    else if (version == 1)
+    else if (version < m_version)
     {
         /* Upgrade 64 bit int handling */
         sql_be->upgrade_table(TABLE_NAME, col_table);
diff --git a/libgnucash/backend/sql/gnc-entry-sql.cpp b/libgnucash/backend/sql/gnc-entry-sql.cpp
index dd40f22..c8be0d9 100644
--- a/libgnucash/backend/sql/gnc-entry-sql.cpp
+++ b/libgnucash/backend/sql/gnc-entry-sql.cpp
@@ -129,7 +129,7 @@ static EntryVec col_table
 });
 
 GncSqlEntryBackend::GncSqlEntryBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_ENTRY,
+    GncSqlObjectBackend(TABLE_VERSION, GNC_ID_ENTRY,
                         TABLE_NAME, col_table) {}
 
 static void
diff --git a/libgnucash/backend/sql/gnc-invoice-sql.cpp b/libgnucash/backend/sql/gnc-invoice-sql.cpp
index 662b30f..5cfffad 100644
--- a/libgnucash/backend/sql/gnc-invoice-sql.cpp
+++ b/libgnucash/backend/sql/gnc-invoice-sql.cpp
@@ -101,7 +101,7 @@ static EntryVec col_table
 });
 
 GncSqlInvoiceBackend::GncSqlInvoiceBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_INVOICE,
+    GncSqlObjectBackend(TABLE_VERSION, GNC_ID_INVOICE,
                         TABLE_NAME, col_table) {}
 
 static GncInvoice*
diff --git a/libgnucash/backend/sql/gnc-job-sql.cpp b/libgnucash/backend/sql/gnc-job-sql.cpp
index bb0589f..dd4d9f5 100644
--- a/libgnucash/backend/sql/gnc-job-sql.cpp
+++ b/libgnucash/backend/sql/gnc-job-sql.cpp
@@ -73,7 +73,7 @@ static EntryVec col_table
 });
 
 GncSqlJobBackend::GncSqlJobBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_JOB,
+    GncSqlObjectBackend(TABLE_VERSION, GNC_ID_JOB,
                         TABLE_NAME, col_table) {}
 
 static GncJob*
diff --git a/libgnucash/backend/sql/gnc-lots-sql.cpp b/libgnucash/backend/sql/gnc-lots-sql.cpp
index f341f6c..322ff85 100644
--- a/libgnucash/backend/sql/gnc-lots-sql.cpp
+++ b/libgnucash/backend/sql/gnc-lots-sql.cpp
@@ -68,7 +68,7 @@ static const EntryVec col_table
 });
 
 GncSqlLotsBackend::GncSqlLotsBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_LOT,
+    GncSqlObjectBackend(TABLE_VERSION, GNC_ID_LOT,
                         TABLE_NAME, col_table) {}
 
 /* ================================================================= */
@@ -156,7 +156,7 @@ GncSqlLotsBackend::create_tables (GncSqlBackend* sql_be)
         /* The table doesn't exist, so create it */
         (void)sql_be->create_table(TABLE_NAME, TABLE_VERSION, col_table);
     }
-    else if (version == 1)
+    else if (version < m_version)
     {
         /* Version 1 -> 2 removes the 'NOT NULL' constraint on the account_guid
         field.
diff --git a/libgnucash/backend/sql/gnc-order-sql.cpp b/libgnucash/backend/sql/gnc-order-sql.cpp
index bd7c252..b870a22 100644
--- a/libgnucash/backend/sql/gnc-order-sql.cpp
+++ b/libgnucash/backend/sql/gnc-order-sql.cpp
@@ -75,7 +75,7 @@ static EntryVec col_table
 });
 
 GncSqlOrderBackend::GncSqlOrderBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_ORDER,
+    GncSqlObjectBackend(TABLE_VERSION, GNC_ID_ORDER,
                         TABLE_NAME, col_table) {}
 
 static GncOrder*
diff --git a/libgnucash/backend/sql/gnc-price-sql.cpp b/libgnucash/backend/sql/gnc-price-sql.cpp
index ffcc691..eaf99eb 100644
--- a/libgnucash/backend/sql/gnc-price-sql.cpp
+++ b/libgnucash/backend/sql/gnc-price-sql.cpp
@@ -71,7 +71,7 @@ static const EntryVec col_table
 });
 
 GncSqlPriceBackend::GncSqlPriceBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_PRICE,
+    GncSqlObjectBackend(TABLE_VERSION, GNC_ID_PRICE,
                         TABLE_NAME, col_table) {}
 
 /* ================================================================= */
@@ -146,7 +146,7 @@ GncSqlPriceBackend::create_tables (GncSqlBackend* sql_be)
     {
         (void)sql_be->create_table(TABLE_NAME, TABLE_VERSION, col_table);
     }
-    else if (version == 1)
+    else if (version < m_version)
     {
         /* Upgrade 64 bit int handling */
         sql_be->upgrade_table(TABLE_NAME, col_table);
diff --git a/libgnucash/backend/sql/gnc-recurrence-sql.cpp b/libgnucash/backend/sql/gnc-recurrence-sql.cpp
index e6c9f76..892b83d 100644
--- a/libgnucash/backend/sql/gnc-recurrence-sql.cpp
+++ b/libgnucash/backend/sql/gnc-recurrence-sql.cpp
@@ -117,7 +117,7 @@ static const EntryVec weekend_adjust_col_table
  * write() implementation is also a no-op.
  */
 GncSqlRecurrenceBackend::GncSqlRecurrenceBackend() :
-        GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_ACCOUNT, TABLE_NAME, col_table) {}
+        GncSqlObjectBackend(TABLE_VERSION, GNC_ID_ACCOUNT, TABLE_NAME, col_table) {}
 
 /* ================================================================= */
 
@@ -415,7 +415,7 @@ GncSqlRecurrenceBackend::create_tables (GncSqlBackend* sql_be)
         /* Upgrade:
             1->2: Add recurrence_weekend_adjust field (mandatory, non-null field)
         */
-        if (version == 1)
+        if (version < m_version)
         {
             upgrade_recurrence_table_1_2 (sql_be);
         }
diff --git a/libgnucash/backend/sql/gnc-schedxaction-sql.cpp b/libgnucash/backend/sql/gnc-schedxaction-sql.cpp
index a4ec238..f7909fd 100644
--- a/libgnucash/backend/sql/gnc-schedxaction-sql.cpp
+++ b/libgnucash/backend/sql/gnc-schedxaction-sql.cpp
@@ -85,7 +85,7 @@ static const EntryVec col_table
 });
 
 GncSqlSchedXactionBackend::GncSqlSchedXactionBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_SCHEDXACTION,
+    GncSqlObjectBackend(TABLE_VERSION, GNC_ID_SCHEDXACTION,
                         SCHEDXACTION_TABLE, col_table) {}
 
 /* ================================================================= */
diff --git a/libgnucash/backend/sql/gnc-slots-sql.cpp b/libgnucash/backend/sql/gnc-slots-sql.cpp
index 79cc038..7cd80fd 100644
--- a/libgnucash/backend/sql/gnc-slots-sql.cpp
+++ b/libgnucash/backend/sql/gnc-slots-sql.cpp
@@ -180,7 +180,7 @@ static const EntryVec gdate_col_table
 };
 
 GncSqlSlotsBackend::GncSqlSlotsBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_ACCOUNT,
+    GncSqlObjectBackend(TABLE_VERSION, GNC_ID_ACCOUNT,
                         TABLE_NAME, col_table) {}
 
 /* ================================================================= */
@@ -982,6 +982,10 @@ GncSqlSlotsBackend::create_tables (GncSqlBackend* sql_be)
                 PERR ("Unable to add gdate column\n");
             }
         }
+        else if (version < m_version)
+        {
+            sql_be->upgrade_table(TABLE_NAME, col_table);
+        }
         sql_be->set_table_version (TABLE_NAME, TABLE_VERSION);
         PINFO ("Slots table upgraded from version %d to version %d\n", version,
                TABLE_VERSION);
diff --git a/libgnucash/backend/sql/gnc-sql-backend.cpp b/libgnucash/backend/sql/gnc-sql-backend.cpp
index 2acf218..3af2d3e 100644
--- a/libgnucash/backend/sql/gnc-sql-backend.cpp
+++ b/libgnucash/backend/sql/gnc-sql-backend.cpp
@@ -224,7 +224,6 @@ GncSqlBackend::ObjectBackendRegistry::load_remaining(GncSqlBackend* sql_be)
         std::string type;
         GncSqlObjectBackendPtr obe = nullptr;
         std::tie(type, obe) = entry;
-        if (!obe->is_version(GNC_SQL_BACKEND_VERSION)) continue;
 
         /* Don't need to load anything if it has already been loaded with
          * the fixed order.
diff --git a/libgnucash/backend/sql/gnc-sql-object-backend.hpp b/libgnucash/backend/sql/gnc-sql-object-backend.hpp
index 59d10ce..b6a007e 100644
--- a/libgnucash/backend/sql/gnc-sql-object-backend.hpp
+++ b/libgnucash/backend/sql/gnc-sql-object-backend.hpp
@@ -38,7 +38,6 @@ using GncSqlColumnTableEntryPtr = std::shared_ptr<GncSqlColumnTableEntry>;
 using EntryVec = std::vector<GncSqlColumnTableEntryPtr>;
 
 #define GNC_SQL_BACKEND "gnc:sql:1"
-#define GNC_SQL_BACKEND_VERSION 1
 
 /**
  * Encapsulates per-class table schema with functions to load, create a table,
diff --git a/libgnucash/backend/sql/gnc-tax-table-sql.cpp b/libgnucash/backend/sql/gnc-tax-table-sql.cpp
index 1030d2c..818ab84 100644
--- a/libgnucash/backend/sql/gnc-tax-table-sql.cpp
+++ b/libgnucash/backend/sql/gnc-tax-table-sql.cpp
@@ -121,7 +121,7 @@ static EntryVec guid_col_table
 });
 
 GncSqlTaxTableBackend::GncSqlTaxTableBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_TAXTABLE,
+    GncSqlObjectBackend(TT_TABLE_VERSION, GNC_ID_TAXTABLE,
                         TT_TABLE_NAME, tt_col_table) {}
 
 struct TaxTblParentGuid
@@ -345,7 +345,7 @@ GncSqlTaxTableBackend::create_tables (GncSqlBackend* sql_be)
     {
         sql_be->create_table(TT_TABLE_NAME, TT_TABLE_VERSION, tt_col_table);
     }
-    else if (version == 1)
+    else if (version < m_version)
     {
         /* Upgrade 64 bit int handling */
         sql_be->upgrade_table(TT_TABLE_NAME, tt_col_table);
@@ -360,7 +360,7 @@ GncSqlTaxTableBackend::create_tables (GncSqlBackend* sql_be)
         sql_be->create_table(TTENTRIES_TABLE_NAME, TTENTRIES_TABLE_VERSION,
                               ttentries_col_table);
     }
-    else if (version == 1)
+    else if (version < TTENTRIES_TABLE_VERSION)
     {
         /* Upgrade 64 bit int handling */
         sql_be->upgrade_table(TTENTRIES_TABLE_NAME, ttentries_col_table);
diff --git a/libgnucash/backend/sql/gnc-transaction-sql.cpp b/libgnucash/backend/sql/gnc-transaction-sql.cpp
index 5fc8a43..e3ff00f 100644
--- a/libgnucash/backend/sql/gnc-transaction-sql.cpp
+++ b/libgnucash/backend/sql/gnc-transaction-sql.cpp
@@ -143,11 +143,11 @@ static const EntryVec tx_guid_col_table
 };
 
 GncSqlTransBackend::GncSqlTransBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_TRANS,
+    GncSqlObjectBackend(TX_TABLE_VERSION, GNC_ID_TRANS,
                         TRANSACTION_TABLE, tx_col_table) {}
 
 GncSqlSplitBackend::GncSqlSplitBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_SPLIT,
+    GncSqlObjectBackend(SPLIT_TABLE_VERSION, GNC_ID_SPLIT,
                         SPLIT_TABLE, split_col_table) {}
 
 /* These functions exist but have not been tested.
diff --git a/libgnucash/backend/sql/gnc-vendor-sql.cpp b/libgnucash/backend/sql/gnc-vendor-sql.cpp
index 9bdb07b..ae60b3a 100644
--- a/libgnucash/backend/sql/gnc-vendor-sql.cpp
+++ b/libgnucash/backend/sql/gnc-vendor-sql.cpp
@@ -83,7 +83,7 @@ static EntryVec col_table
 });
 
 GncSqlVendorBackend::GncSqlVendorBackend() :
-    GncSqlObjectBackend(GNC_SQL_BACKEND_VERSION, GNC_ID_VENDOR,
+    GncSqlObjectBackend(TABLE_VERSION, GNC_ID_VENDOR,
                         TABLE_NAME, col_table) {}
 
 static GncVendor*

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 2cbfc5bbac9bda4ef1206db5a437b45cb79bc373
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Tue Nov 21 22:11:38 2017 +0100

    Revert "Merge branch 'gtk3-update8' of https://github.com/Bob-IT/gnucash into unstable"
    
    This reverts commit cdb764fec525642bbe85dd5a0a49ec967c55f089, reversing
    changes made to 169677a8d753ba26a447d22d2b2ec565bfe4798b.

diff --git a/gnucash/gnucash-310.css b/gnucash/gnucash-310.css
index 76b7232..e4a37a3 100644
--- a/gnucash/gnucash-310.css
+++ b/gnucash/gnucash-310.css
@@ -21,14 +21,13 @@
   color: mix (currentColor, grey, 0.2);
 }
 
-/* Register Cursor settings, top, right, bottom, left */
-.cursor .entry {
-  margin: 2px 5px 2px 5px;  /* this only works by doing it in code, yellow area */
-  padding: 2px 2px 2px 2px; /* all work with different values, around the text blue area */
+/* Register Cursor padding settings, make sure entry matches sheet.h */
+cursor entry {
+  padding: 2px 5px 2px 5px;
 }
 
-.cursor .toggle-button {
-  margin: 1px 1px 1px 1px; /* does not work, not used, here for completeness */
+cursor button {
+  padding: 1px 1px 1px 1px;
 }
 
 /* Register defaults */
@@ -38,7 +37,7 @@
 @define-color register_split_bg_color #EDE7D3;
 @define-color register_cursor_bg_color #FFEF98;
 
-*.register-header {
+.register-header {
   background-color: @register_header_bg_color;
 }
 
diff --git a/gnucash/gnucash-320.css b/gnucash/gnucash-320.css
index 51f197c..d7e0495 100644
--- a/gnucash/gnucash-320.css
+++ b/gnucash/gnucash-320.css
@@ -12,14 +12,13 @@
   color: @negative-numbers;
 }
 
-/* Register Cursor settings, top, right, bottom, left */
+/* Register Cursor padding settings, make sure entry matches sheet.h */
 cursor entry {
-  margin: 2px 5px 2px 5px;
-  padding: 0px 2px 0px 2px;
+  padding: 2px 5px 2px 5px;
 }
 
-cursor toggle-button {
-  margin: 1px 1px 1px 1px;
+cursor button {
+  padding: 1px 1px 1px 1px;
 }
 
 /* Register defaults */
@@ -29,7 +28,7 @@ cursor toggle-button {
 @define-color register_split_bg_color #EDE7D3;
 @define-color register_cursor_bg_color #FFEF98;
 
-*.register-header {
+.register-header {
   background-color: @register_header_bg_color;
 }
 
diff --git a/gnucash/register/ledger-core/gncEntryLedgerModel.c b/gnucash/register/ledger-core/gncEntryLedgerModel.c
index a638d06..8c5207d 100644
--- a/gnucash/register/ledger-core/gncEntryLedgerModel.c
+++ b/gnucash/register/ledger-core/gncEntryLedgerModel.c
@@ -915,57 +915,65 @@ static CellIOFlags get_qty_io_flags (VirtualLocation virt_loc, gpointer user_dat
     return flags;
 }
 
-/* GET COLORS */
+/* GET BG_COLORS */
 
 static guint32
-gnc_entry_ledger_get_cell_color_internal (VirtualLocation virt_loc,
-                                          GncEntryLedger *ledger)
+gnc_entry_ledger_get_color_internal (VirtualLocation virt_loc,
+                                     GncEntryLedger *ledger,
+                                     gboolean foreground)
 {
     VirtualCell *vcell;
     gboolean is_current;
-    guint32 colorbase = 0;
+    guint32 colorbase = 0; /* By default return background colors */
 
-    /* a bit of enum arithmetic */
-
-    // There are negative numbers
+    if (foreground)
+        colorbase = COLOR_UNKNOWN_FG; /* a bit of enum arithmetic */
 
     if (!ledger)
-        return (colorbase + COLOR_UNDEFINED);
+        return (colorbase + COLOR_UNKNOWN_BG);
 
     if (gnc_table_virtual_location_in_header (ledger->table, virt_loc))
-        return (colorbase + COLOR_HEADER);
+        return (colorbase + COLOR_HEADER_BG);
 
     vcell = gnc_table_get_virtual_cell (ledger->table, virt_loc.vcell_loc);
     if (!vcell || !vcell->cellblock)
-        return (colorbase + COLOR_UNDEFINED);
+        return (colorbase + COLOR_UNKNOWN_BG);
 
     if ((virt_loc.phys_col_offset < vcell->cellblock->start_col) ||
             (virt_loc.phys_col_offset > vcell->cellblock->stop_col))
-        return (colorbase + COLOR_UNDEFINED);
+        return (colorbase + COLOR_UNKNOWN_BG);
 
     is_current = virt_cell_loc_equal (ledger->table->current_cursor_loc.vcell_loc,
                                       virt_loc.vcell_loc);
 
     if (is_current)
         return vcell->start_primary_color ?
-                (colorbase + COLOR_PRIMARY_ACTIVE) :
-                (colorbase + COLOR_SECONDARY_ACTIVE);
+                (colorbase + COLOR_PRIMARY_BG_ACTIVE) :
+                (colorbase + COLOR_SECONDARY_BG_ACTIVE);
 
     return vcell->start_primary_color ?
-            (colorbase + COLOR_PRIMARY) : (colorbase + COLOR_SECONDARY);
+            (colorbase + COLOR_PRIMARY_BG) : (colorbase + COLOR_SECONDARY_BG);
 
 }
 
 static guint32
-gnc_entry_ledger_get_cell_color (VirtualLocation virt_loc,
-                                 gboolean *hatching, gpointer user_data)
+gnc_entry_ledger_get_fg_color (VirtualLocation virt_loc,
+                               gpointer user_data)
+{
+    GncEntryLedger *ledger = user_data;
+    return gnc_entry_ledger_get_color_internal (virt_loc, ledger, TRUE);
+}
+
+static guint32
+gnc_entry_ledger_get_bg_color (VirtualLocation virt_loc,
+                               gboolean *hatching, gpointer user_data)
 {
     GncEntryLedger *ledger = user_data;
 
     if (hatching)
         *hatching = FALSE;
 
-    return gnc_entry_ledger_get_cell_color_internal (virt_loc, ledger);
+    return gnc_entry_ledger_get_color_internal (virt_loc, ledger, FALSE);
 }
 
 /* SAVE CELLS */
@@ -1217,8 +1225,11 @@ static void gnc_entry_ledger_model_new_handlers (TableModel *model,
     };
     unsigned int i;
 
-    // Set the cell color handler
-    gnc_table_model_set_default_cell_color_handler (model, gnc_entry_ledger_get_cell_color);
+    gnc_table_model_set_default_fg_color_handler
+    (model, gnc_entry_ledger_get_fg_color);
+
+    gnc_table_model_set_default_bg_color_handler
+    (model, gnc_entry_ledger_get_bg_color);
 
     for (i = 0; i < (sizeof(models) / sizeof(*models)); i++)
     {
diff --git a/gnucash/register/ledger-core/split-register-model.c b/gnucash/register/ledger-core/split-register-model.c
index f8b6614..3a2fac4 100644
--- a/gnucash/register/ledger-core/split-register-model.c
+++ b/gnucash/register/ledger-core/split-register-model.c
@@ -514,85 +514,33 @@ get_trans_total_balance (SplitRegister *reg, Transaction *trans)
     return xaccTransGetAccountBalance(trans, account);
 }
 
-static gboolean
-gnc_split_register_use_negative_color (VirtualLocation virt_loc,
-                                       SplitRegister *reg)
-{
-    const char * cell_name;
-    gnc_numeric value;
-    Split *split;
-
-    if (!use_red_for_negative)
-        return FALSE;
-
-    split = gnc_split_register_get_split (reg, virt_loc.vcell_loc);
-    if (!split)
-        return FALSE;
-
-    cell_name = gnc_table_get_cell_name (reg->table, virt_loc);
-
-    if (gnc_cell_name_equal (cell_name, TSHRS_CELL))
-        value = get_trans_total_amount (reg, xaccSplitGetParent (split));
-    else if (gnc_cell_name_equal (cell_name, SHRS_CELL))
-    {
-        if (virt_cell_loc_equal (reg->table->current_cursor_loc.vcell_loc,
-                                      virt_loc.vcell_loc))
-            value = gnc_price_cell_get_value
-                     ((PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
-                             SHRS_CELL));
-        else
-            value = xaccSplitGetAmount (split);
-    }
-    else if (gnc_cell_name_equal (cell_name, BALN_CELL))
-        value = xaccSplitGetBalance (split);
-    else if (gnc_cell_name_equal (cell_name, RBALN_CELL))
-        value = gnc_split_register_get_rbaln (virt_loc, reg, TRUE);
-    else if (gnc_cell_name_equal (cell_name, TBALN_CELL))
-        value = get_trans_total_balance (reg, xaccSplitGetParent (split));
-
-    if ((gnc_cell_name_equal (cell_name, BALN_CELL)) ||
-            (gnc_cell_name_equal (cell_name, RBALN_CELL)) ||
-            (gnc_cell_name_equal (cell_name, TBALN_CELL)))
-        {
-            Account *account = xaccSplitGetAccount (split);
-            if (gnc_reverse_balance (account))
-                value = gnc_numeric_neg (value);
-        }
-
-    if (gnc_numeric_negative_p (value))
-        return TRUE;
-
-    return FALSE;
-}
-
 static guint32
-gnc_split_register_get_cell_color_internal (VirtualLocation virt_loc,
-                                            SplitRegister *reg)
+gnc_split_register_get_color_internal (VirtualLocation virt_loc,
+                                       SplitRegister *reg,
+                                       gboolean foreground)
 {
     const char *cursor_name;
     VirtualCell *vcell;
     gboolean is_current;
     gboolean double_alternate_virt;
-    guint32 colorbase = 0;
+    guint32 colorbase = 0; /* By default return background colors */
 
-     /* a bit of enum arithmetic */
-
-    if (gnc_split_register_use_negative_color (virt_loc, reg))
-        colorbase = COLOR_NEGATIVE; // Requires Negative fg color
+    if (foreground)
+        colorbase = COLOR_UNKNOWN_FG; /* a bit of enum arithmetic */
 
     if (!reg)
-        return (colorbase + COLOR_UNDEFINED);
+        return (colorbase + COLOR_UNKNOWN_BG);
 
     if (gnc_table_virtual_location_in_header (reg->table, virt_loc))
-        return (colorbase + COLOR_HEADER);
+        return (colorbase + COLOR_HEADER_BG);
 
     vcell = gnc_table_get_virtual_cell (reg->table, virt_loc.vcell_loc);
     if (!vcell || !vcell->cellblock)
-        return (colorbase + COLOR_UNDEFINED);
+        return (colorbase + COLOR_UNKNOWN_BG);
 
     if ((virt_loc.phys_col_offset < vcell->cellblock->start_col) ||
             (virt_loc.phys_col_offset > vcell->cellblock->stop_col))
-        return (colorbase + COLOR_UNDEFINED);
+        return (colorbase + COLOR_UNKNOWN_BG);
 
     is_current = virt_cell_loc_equal (reg->table->current_cursor_loc.vcell_loc,
                                       virt_loc.vcell_loc);
@@ -604,11 +552,11 @@ gnc_split_register_get_cell_color_internal (VirtualLocation virt_loc,
     {
         if (is_current)
             return vcell->start_primary_color ?
-                    (colorbase + COLOR_PRIMARY_ACTIVE) :
-                    (colorbase + COLOR_SECONDARY_ACTIVE);
+                    (colorbase + COLOR_PRIMARY_BG_ACTIVE) :
+                    (colorbase + COLOR_SECONDARY_BG_ACTIVE);
 
         return vcell->start_primary_color ?
-                (colorbase + COLOR_PRIMARY) : (colorbase + COLOR_SECONDARY);
+                (colorbase + COLOR_PRIMARY_BG) : (colorbase + COLOR_SECONDARY_BG);
     }
 
     if (g_strcmp0 (cursor_name, CURSOR_DOUBLE_JOURNAL) == 0 ||
@@ -622,40 +570,101 @@ gnc_split_register_get_cell_color_internal (VirtualLocation virt_loc,
         {
             if (double_alternate_virt)
                 return vcell->start_primary_color ?
-                        (colorbase + COLOR_PRIMARY_ACTIVE) :
-                        (colorbase + COLOR_SECONDARY_ACTIVE);
+                        (colorbase + COLOR_PRIMARY_BG_ACTIVE) :
+                        (colorbase + COLOR_SECONDARY_BG_ACTIVE);
 
             return (virt_loc.phys_row_offset % 2 == 0) ?
-                    (colorbase + COLOR_PRIMARY_ACTIVE) :
-                    (colorbase + COLOR_SECONDARY_ACTIVE);
+                    (colorbase + COLOR_PRIMARY_BG_ACTIVE) :
+                    (colorbase + COLOR_SECONDARY_BG_ACTIVE);
         }
 
         if (double_alternate_virt)
             return vcell->start_primary_color ?
-                    (colorbase + COLOR_PRIMARY) :
-                    (colorbase + COLOR_SECONDARY);
+                    (colorbase + COLOR_PRIMARY_BG) :
+                    (colorbase + COLOR_SECONDARY_BG);
 
         return (virt_loc.phys_row_offset % 2 == 0) ?
-                (colorbase + COLOR_PRIMARY) :
-                (colorbase + COLOR_SECONDARY);
+                (colorbase + COLOR_PRIMARY_BG) :
+                (colorbase + COLOR_SECONDARY_BG);
     }
 
     if (g_strcmp0 (cursor_name, CURSOR_SPLIT) == 0)
     {
         if (is_current)
-            return (colorbase + COLOR_SPLIT_ACTIVE);
+            return (colorbase + COLOR_SPLIT_BG_ACTIVE);
 
-        return (colorbase + COLOR_SPLIT);
+        return (colorbase + COLOR_SPLIT_BG);
     }
 
     PWARN ("Unexpected cursor: %s\n", cursor_name);
 
-    return (colorbase + COLOR_UNDEFINED);
+    return (colorbase + COLOR_UNKNOWN_BG);
 }
 
-// Get Color for non numeric cells, no hatching required
 static guint32
-gnc_split_register_get_cell_color (VirtualLocation virt_loc,
+gnc_split_register_get_fg_color_internal (VirtualLocation virt_loc,
+                                          SplitRegister *reg)
+{
+    guint32 fg_color;
+    const char * cell_name;
+    gnc_numeric value;
+    Split *split;
+
+    fg_color = gnc_split_register_get_color_internal (virt_loc, reg, TRUE);
+
+    if (!use_red_for_negative)
+        return fg_color;
+
+    split = gnc_split_register_get_split (reg, virt_loc.vcell_loc);
+    if (!split)
+        return fg_color;
+
+    cell_name = gnc_table_get_cell_name (reg->table, virt_loc);
+
+    if (gnc_cell_name_equal (cell_name, TSHRS_CELL))
+        value = get_trans_total_amount (reg, xaccSplitGetParent (split));
+    else if (gnc_cell_name_equal (cell_name, SHRS_CELL))
+    {
+        if (virt_cell_loc_equal (reg->table->current_cursor_loc.vcell_loc,
+                                      virt_loc.vcell_loc))
+            value = gnc_price_cell_get_value
+                     ((PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
+                             SHRS_CELL));
+        else
+            value = xaccSplitGetAmount (split);
+    }
+    else if (gnc_cell_name_equal (cell_name, BALN_CELL))
+        value = xaccSplitGetBalance (split);
+    else if (gnc_cell_name_equal (cell_name, RBALN_CELL))
+        value = gnc_split_register_get_rbaln (virt_loc, reg, TRUE);
+    else if (gnc_cell_name_equal (cell_name, TBALN_CELL))
+        value = get_trans_total_balance (reg, xaccSplitGetParent (split));
+
+    if ((gnc_cell_name_equal (cell_name, BALN_CELL)) ||
+            (gnc_cell_name_equal (cell_name, RBALN_CELL)) ||
+            (gnc_cell_name_equal (cell_name, TBALN_CELL)))
+        {
+            Account *account = xaccSplitGetAccount (split);
+            if (gnc_reverse_balance (account))
+                value = gnc_numeric_neg (value);
+        }
+
+    if (gnc_numeric_negative_p (value))
+        return COLOR_NEGATIVE;
+
+    return fg_color;
+}
+
+static guint32
+gnc_split_register_get_fg_color (VirtualLocation virt_loc,
+                                 gpointer user_data)
+{
+    SplitRegister *reg = user_data;
+    return gnc_split_register_get_fg_color_internal (virt_loc, reg);
+}
+
+static guint32
+gnc_split_register_get_bg_color (VirtualLocation virt_loc,
         gboolean *hatching,
         gpointer user_data)
 {
@@ -664,12 +673,11 @@ gnc_split_register_get_cell_color (VirtualLocation virt_loc,
     if (hatching)
         *hatching = FALSE;
 
-    return gnc_split_register_get_cell_color_internal (virt_loc, reg);
+    return gnc_split_register_get_color_internal (virt_loc, reg, FALSE);
 }
 
-// Get Color for numeric cells, update hatching
 static guint32
-gnc_split_register_get_debcred_color (VirtualLocation virt_loc,
+gnc_split_register_get_debcred_bg_color (VirtualLocation virt_loc,
         gboolean *hatching,
         gpointer user_data)
 {
@@ -686,7 +694,8 @@ gnc_split_register_get_debcred_color (VirtualLocation virt_loc,
         else
             *hatching = FALSE;
     }
-    return gnc_split_register_get_cell_color_internal (virt_loc, reg);
+
+    return gnc_split_register_get_bg_color (virt_loc, NULL, user_data);
 }
 
 static void
@@ -2614,26 +2623,42 @@ gnc_split_register_model_new (void)
         model, gnc_split_register_get_security_io_flags, SHRS_CELL);
 
 
-    gnc_table_model_set_default_cell_color_handler(
-        model, gnc_split_register_get_cell_color);
+    gnc_table_model_set_fg_color_handler(
+        model, gnc_split_register_get_fg_color, SHRS_CELL);
+
+    gnc_table_model_set_fg_color_handler(
+        model, gnc_split_register_get_fg_color, TSHRS_CELL);
+
+    gnc_table_model_set_fg_color_handler(
+        model, gnc_split_register_get_fg_color, BALN_CELL);
+
+    gnc_table_model_set_fg_color_handler(
+        model, gnc_split_register_get_fg_color, TBALN_CELL);
+
+    gnc_table_model_set_fg_color_handler(
+        model, gnc_split_register_get_fg_color, RBALN_CELL);
+
+
+    gnc_table_model_set_default_bg_color_handler(
+        model, gnc_split_register_get_bg_color);
 
-    gnc_table_model_set_cell_color_handler(
-        model, gnc_split_register_get_debcred_color, DEBT_CELL);
+    gnc_table_model_set_bg_color_handler(
+        model, gnc_split_register_get_debcred_bg_color, DEBT_CELL);
 
-    gnc_table_model_set_cell_color_handler(
-        model, gnc_split_register_get_debcred_color, CRED_CELL);
+    gnc_table_model_set_bg_color_handler(
+        model, gnc_split_register_get_debcred_bg_color, CRED_CELL);
 
-    gnc_table_model_set_cell_color_handler(
-        model, gnc_split_register_get_debcred_color, TDEBT_CELL);
+    gnc_table_model_set_bg_color_handler(
+        model, gnc_split_register_get_debcred_bg_color, TDEBT_CELL);
 
-    gnc_table_model_set_cell_color_handler(
-        model, gnc_split_register_get_debcred_color, TCRED_CELL);
+    gnc_table_model_set_bg_color_handler(
+        model, gnc_split_register_get_debcred_bg_color, TCRED_CELL);
 
-    gnc_table_model_set_cell_color_handler(
-        model, gnc_split_register_get_debcred_color, FCRED_CELL);
+    gnc_table_model_set_bg_color_handler(
+        model, gnc_split_register_get_debcred_bg_color, FCRED_CELL);
 
-    gnc_table_model_set_cell_color_handler(
-        model, gnc_split_register_get_debcred_color, FDEBT_CELL);
+    gnc_table_model_set_bg_color_handler(
+        model, gnc_split_register_get_debcred_bg_color, FDEBT_CELL);
 
 
     gnc_table_model_set_default_cell_border_handler(
diff --git a/gnucash/register/register-core/table-allgui.c b/gnucash/register/register-core/table-allgui.c
index 038d3b0..7e407db 100644
--- a/gnucash/register/register-core/table-allgui.c
+++ b/gnucash/register/register-core/table-allgui.c
@@ -345,29 +345,68 @@ gnc_table_get_label (Table *table, VirtualLocation virt_loc)
     return label;
 }
 
+static guint32
+gnc_table_get_fg_color_internal (Table *table, VirtualLocation virt_loc)
+{
+    TableGetFGColorHandler fg_color_handler;
+    const char *handler_name;
+
+    if (!table || !table->model)
+        return COLOR_UNKNOWN_FG;
+
+    handler_name = gnc_table_get_cell_name (table, virt_loc);
+
+    fg_color_handler = gnc_table_model_get_fg_color_handler (table->model,
+                       handler_name);
+    if (!fg_color_handler)
+    {
+        TableGetBGColorHandler bg_color_handler =
+            gnc_table_model_get_bg_color_handler (table->model, handler_name);
+
+        guint32 bg_color =
+            bg_color_handler (virt_loc, NULL, table->model->handler_user_data);
+        return bg_color + COLOR_UNKNOWN_FG;
+    }
+
+    return fg_color_handler (virt_loc, table->model->handler_user_data);
+}
+
 guint32
-gnc_table_get_color (Table *table, VirtualLocation virt_loc,
+gnc_table_get_fg_color (Table *table, VirtualLocation virt_loc)
+{
+    return gnc_table_get_fg_color_internal (table, virt_loc);
+}
+
+static guint32
+gnc_table_get_bg_color_internal (Table *table, VirtualLocation virt_loc,
                                  gboolean *hatching)
 {
-    TableGetCellColorHandler color_handler;
+    TableGetBGColorHandler bg_color_handler;
     const char *handler_name;
 
     if (hatching)
         *hatching = FALSE;
 
     if (!table || !table->model)
-        return COLOR_UNDEFINED;
+        return COLOR_UNKNOWN_BG;
 
     handler_name = gnc_table_get_cell_name (table, virt_loc);
 
-    color_handler = gnc_table_model_get_cell_color_handler (table->model,
-                                                            handler_name);
+    bg_color_handler = gnc_table_model_get_bg_color_handler (table->model,
+            handler_name);
+
+    if (!bg_color_handler)
+        return COLOR_UNKNOWN_BG;
 
-    if (!color_handler)
-        return COLOR_UNDEFINED;
+    return bg_color_handler (virt_loc, hatching,
+                             table->model->handler_user_data);
+}
 
-    return color_handler (virt_loc, hatching,
-                          table->model->handler_user_data);
+guint32
+gnc_table_get_bg_color (Table *table, VirtualLocation virt_loc,
+                        gboolean *hatching)
+{
+    return gnc_table_get_bg_color_internal (table, virt_loc, hatching);
 }
 
 void
diff --git a/gnucash/register/register-core/table-allgui.h b/gnucash/register/register-core/table-allgui.h
index 3b4fa26..d827fd5 100644
--- a/gnucash/register/register-core/table-allgui.h
+++ b/gnucash/register/register-core/table-allgui.h
@@ -179,19 +179,35 @@ struct table
 };
 
 /** Color definitions used for table elements */
-typedef enum {
-    COLOR_UNDEFINED = 0,      // 0
-    COLOR_HEADER,             // 1
-    COLOR_PRIMARY,            // 2
-    COLOR_PRIMARY_ACTIVE,     // 3
-    COLOR_SECONDARY,          // 4
-    COLOR_SECONDARY_ACTIVE,   // 5
-    COLOR_SPLIT,              // 6
-    COLOR_SPLIT_ACTIVE,       // 7
-    COLOR_NEGATIVE = 16,      // 16
+typedef enum
+{
+    /* Colors used for background drawing */
+    COLOR_UNKNOWN_BG,          // 0
+    COLOR_HEADER_BG,           // 1
+    COLOR_PRIMARY_BG,          // 2
+    COLOR_PRIMARY_BG_ACTIVE,   // 3
+    COLOR_SECONDARY_BG,        // 4
+    COLOR_SECONDARY_BG_ACTIVE, // 5
+    COLOR_SPLIT_BG,            // 6
+    COLOR_SPLIT_BG_ACTIVE,     // 7
+
+    /* Colors used for foreground drawing (text etc)
+     * ATTENTION: the background and foreground lists should have
+     *            the same types (the same amount of entries) !
+     *            The code relies on this ! */
+    COLOR_UNKNOWN_FG,          // 8
+    COLOR_HEADER_FG,           // 9
+    COLOR_PRIMARY_FG,          // 10
+    COLOR_PRIMARY_FG_ACTIVE,   // 11
+    COLOR_SECONDARY_FG,        // 12
+    COLOR_SECONDARY_FG_ACTIVE, // 13
+    COLOR_SPLIT_FG,            // 14
+    COLOR_SPLIT_FG_ACTIVE,     // 15
+
+    /* Other colors */
+    COLOR_NEGATIVE,            // 16 Color to use for negative numbers
 } RegisterColor;
 
-
 /** Set the default gui handlers used by new tables. */
 void gnc_table_set_default_gui_handlers (TableGUIHandlers *gui_handlers);
 
@@ -242,7 +258,9 @@ const char *   gnc_table_get_label (Table *table, VirtualLocation virt_loc);
 
 CellIOFlags    gnc_table_get_io_flags (Table *table, VirtualLocation virt_loc);
 
-guint32        gnc_table_get_color (Table *table, VirtualLocation virt_loc,
+guint32        gnc_table_get_fg_color (Table *table, VirtualLocation virt_loc);
+
+guint32        gnc_table_get_bg_color (Table *table, VirtualLocation virt_loc,
                                        gboolean *hatching);
 
 void           gnc_table_get_borders (Table *table, VirtualLocation virt_loc,
diff --git a/gnucash/register/register-core/table-model.c b/gnucash/register/register-core/table-model.c
index a5baee2..c76310e 100644
--- a/gnucash/register/register-core/table-model.c
+++ b/gnucash/register/register-core/table-model.c
@@ -134,7 +134,8 @@ gnc_table_model_new (void)
     model->label_handlers = gnc_table_model_handler_hash_new ();
     model->help_handlers = gnc_table_model_handler_hash_new ();
     model->io_flags_handlers = gnc_table_model_handler_hash_new ();
-    model->cell_color_handlers = gnc_table_model_handler_hash_new ();
+    model->fg_color_handlers = gnc_table_model_handler_hash_new ();
+    model->bg_color_handlers = gnc_table_model_handler_hash_new ();
     model->cell_border_handlers = gnc_table_model_handler_hash_new ();
     model->confirm_handlers = gnc_table_model_handler_hash_new ();
     model->save_handlers = gnc_table_model_handler_hash_new ();
@@ -164,8 +165,11 @@ gnc_table_model_destroy (TableModel *model)
     gnc_table_model_handler_hash_destroy (model->io_flags_handlers);
     model->io_flags_handlers = NULL;
 
-    gnc_table_model_handler_hash_destroy (model->cell_color_handlers);
-    model->cell_color_handlers = NULL;
+    gnc_table_model_handler_hash_destroy (model->fg_color_handlers);
+    model->fg_color_handlers = NULL;
+
+    gnc_table_model_handler_hash_destroy (model->bg_color_handlers);
+    model->bg_color_handlers = NULL;
 
     gnc_table_model_handler_hash_destroy (model->cell_border_handlers);
     model->cell_border_handlers = NULL;
@@ -330,39 +334,75 @@ gnc_table_model_get_io_flags_handler (TableModel *model,
 }
 
 void
-gnc_table_model_set_cell_color_handler
+gnc_table_model_set_fg_color_handler
 (TableModel *model,
- TableGetCellColorHandler color_handler,
+ TableGetFGColorHandler fg_color_handler,
  const char * cell_name)
 {
     g_return_if_fail (model != NULL);
     g_return_if_fail (cell_name != NULL);
 
-    gnc_table_model_handler_hash_insert (model->cell_color_handlers,
+    gnc_table_model_handler_hash_insert (model->fg_color_handlers,
                                          cell_name,
-                                         color_handler);
+                                         fg_color_handler);
 }
 
 void
-gnc_table_model_set_default_cell_color_handler
+gnc_table_model_set_default_fg_color_handler
 (TableModel *model,
- TableGetCellColorHandler color_handler)
+ TableGetFGColorHandler fg_color_handler)
 {
     g_return_if_fail (model != NULL);
 
-    gnc_table_model_handler_hash_insert (model->cell_color_handlers,
+    gnc_table_model_handler_hash_insert (model->fg_color_handlers,
                                          DEFAULT_HANDLER,
-                                         color_handler);
+                                         fg_color_handler);
 }
 
-TableGetCellColorHandler
-gnc_table_model_get_cell_color_handler (TableModel *model,
-                                   const char * cell_name)
+TableGetFGColorHandler
+gnc_table_model_get_fg_color_handler (TableModel *model,
+                                      const char * cell_name)
 {
     g_return_val_if_fail (model != NULL, NULL);
 
-    return gnc_table_model_handler_hash_lookup (model->cell_color_handlers,
-                                                cell_name);
+    return gnc_table_model_handler_hash_lookup (model->fg_color_handlers,
+            cell_name);
+}
+
+void
+gnc_table_model_set_bg_color_handler
+(TableModel *model,
+ TableGetBGColorHandler bg_color_handler,
+ const char * cell_name)
+{
+    g_return_if_fail (model != NULL);
+    g_return_if_fail (cell_name != NULL);
+
+    gnc_table_model_handler_hash_insert (model->bg_color_handlers,
+                                         cell_name,
+                                         bg_color_handler);
+}
+
+void
+gnc_table_model_set_default_bg_color_handler
+(TableModel *model,
+ TableGetBGColorHandler bg_color_handler)
+{
+    g_return_if_fail (model != NULL);
+
+    gnc_table_model_handler_hash_insert (model->bg_color_handlers,
+                                         DEFAULT_HANDLER,
+                                         bg_color_handler);
+}
+
+TableGetBGColorHandler
+gnc_table_model_get_bg_color_handler (TableModel *model,
+                                      const char * cell_name)
+{
+    g_return_val_if_fail (model != NULL, NULL);
+
+    return gnc_table_model_handler_hash_lookup (model->bg_color_handlers,
+            cell_name);
 }
 
 void
diff --git a/gnucash/register/register-core/table-model.h b/gnucash/register/register-core/table-model.h
index 2d489a6..268757e 100644
--- a/gnucash/register/register-core/table-model.h
+++ b/gnucash/register/register-core/table-model.h
@@ -76,7 +76,10 @@ typedef char * (*TableGetHelpHandler) (VirtualLocation virt_loc,
 typedef CellIOFlags (*TableGetCellIOFlagsHandler) (VirtualLocation virt_loc,
         gpointer user_data);
 
-typedef guint32 (*TableGetCellColorHandler) (VirtualLocation virt_loc,
+typedef guint32 (*TableGetFGColorHandler) (VirtualLocation virt_loc,
+        gpointer user_data);
+
+typedef guint32 (*TableGetBGColorHandler) (VirtualLocation virt_loc,
         gboolean *hatching,
         gpointer user_data);
 
@@ -104,7 +107,8 @@ typedef struct
     GHashTable *label_handlers;
     GHashTable *help_handlers;
     GHashTable *io_flags_handlers;
-    GHashTable *cell_color_handlers;
+    GHashTable *fg_color_handlers;
+    GHashTable *bg_color_handlers;
     GHashTable *cell_border_handlers;
     GHashTable *confirm_handlers;
 
@@ -185,14 +189,25 @@ TableGetCellIOFlagsHandler gnc_table_model_get_io_flags_handler
 (TableModel *model,
  const char * cell_name);
 
-void gnc_table_model_set_cell_color_handler
+void gnc_table_model_set_fg_color_handler
+(TableModel *model,
+ TableGetFGColorHandler io_flags_handler,
+ const char * cell_name);
+void gnc_table_model_set_default_fg_color_handler
+(TableModel *model,
+ TableGetFGColorHandler io_flags_handler);
+TableGetFGColorHandler gnc_table_model_get_fg_color_handler
+(TableModel *model,
+ const char * cell_name);
+
+void gnc_table_model_set_bg_color_handler
 (TableModel *model,
- TableGetCellColorHandler io_flags_handler,
+ TableGetBGColorHandler io_flags_handler,
  const char * cell_name);
- void gnc_table_model_set_default_cell_color_handler
+void gnc_table_model_set_default_bg_color_handler
 (TableModel *model,
- TableGetCellColorHandler io_flags_handler);
-TableGetCellColorHandler gnc_table_model_get_cell_color_handler
+ TableGetBGColorHandler io_flags_handler);
+TableGetBGColorHandler gnc_table_model_get_bg_color_handler
 (TableModel *model,
  const char * cell_name);
 
diff --git a/gnucash/register/register-gnome/gnucash-header.c b/gnucash/register/register-gnome/gnucash-header.c
index 156ae68..247d08f 100644
--- a/gnucash/register/register-gnome/gnucash-header.c
+++ b/gnucash/register/register-gnome/gnucash-header.c
@@ -69,7 +69,6 @@ static void
 gnc_header_draw_offscreen (GncHeader *header)
 {
     SheetBlockStyle *style = header->style;
-    GncItemEdit *item_edit = GNC_ITEM_EDIT(header->sheet->item_editor);
     Table *table = header->sheet->table;
     VirtualLocation virt_loc;
     VirtualCell *vcell;
@@ -88,8 +87,8 @@ gnc_header_draw_offscreen (GncHeader *header)
 
     gtk_style_context_save (stylectxt);
 
-    // Get the color type and apply the css class
-    color_type = gnc_table_get_color (table, virt_loc, NULL);
+    // Get the background color type and apply the css class
+    color_type = gnc_table_get_bg_color (table, virt_loc, NULL);
     gnucash_get_style_classes (header->sheet, stylectxt, color_type);
 
     if (header->surface)
@@ -126,7 +125,7 @@ gnc_header_draw_offscreen (GncHeader *header)
     for (i = 0; i < style->nrows; i++)
     {
         int col_offset = 0;
-        int height = 0, j;
+        int h = 0, j;
         virt_loc.phys_row_offset = i;
 
         /* TODO: This routine is duplicated in several places.
@@ -140,29 +139,26 @@ gnc_header_draw_offscreen (GncHeader *header)
             double text_x, text_y, text_w, text_h;
             BasicCell *cell;
             const char *text;
-            int width;
+            int w;
             PangoLayout *layout;
-            PangoRectangle logical_rect;
-            GdkRectangle rect;
-            int x_offset;
 
             virt_loc.phys_col_offset = j;
 
             cd = gnucash_style_get_cell_dimensions (style, i, j);
-            height = cd->pixel_height;
+            h = cd->pixel_height;
             if (header->in_resize && (j == header->resize_col))
-                width = header->resize_col_width;
+                w = header->resize_col_width;
             else
-                width = cd->pixel_width;
+                w = cd->pixel_width;
 
             cell = gnc_cellblock_get_cell (cb, i, j);
             if (!cell || !cell->cell_name)
             {
-                col_offset += width;
+                col_offset += w;
                 continue;
             }
 
-            cairo_rectangle (cr, col_offset - 0.5, row_offset + 0.5, width, height);
+            cairo_rectangle (cr, col_offset - 0.5, row_offset + 0.5, w, h);
             cairo_set_line_width (cr, 1.0);
             cairo_stroke (cr);
 
@@ -173,28 +169,38 @@ gnc_header_draw_offscreen (GncHeader *header)
                 text = "";
 
             layout = gtk_widget_create_pango_layout (GTK_WIDGET (header->sheet), text);
+            switch (gnc_table_get_align (table, virt_loc))
+            {
+            default:
+            case CELL_ALIGN_LEFT:
+                pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT);
+                break;
+
+            case CELL_ALIGN_RIGHT:
+                pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
+                break;
+
+            case CELL_ALIGN_CENTER:
+                pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
+                break;
+            }
 
-            pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
-
-            gnucash_sheet_set_text_bounds (header->sheet, &rect,
-                                           col_offset, row_offset, width, height);
-
+            text_x = col_offset + CELL_HPADDING;
+            text_y = row_offset + 1;
+            text_w = MAX (0, w - (2 * CELL_HPADDING));
+            text_h = h - 2;
             cairo_save (cr);
-            cairo_rectangle (cr, rect.x, rect.y, rect.width, rect.height);
+            cairo_rectangle (cr, text_x, text_y, text_w, text_h);
             cairo_clip (cr);
 
-            x_offset = gnucash_sheet_get_text_offset (header->sheet, virt_loc,
-                                                      rect.width, logical_rect.width);
-
-            gtk_render_layout (stylectxt, cr, rect.x + x_offset,
-                               rect.y + gnc_item_edit_get_padding_border (item_edit, top), layout);
+            gtk_render_layout (stylectxt, cr, text_x, text_y, layout);
 
             cairo_restore (cr);
             g_object_unref (layout);
 
-            col_offset += width;
+            col_offset += w;
         }
-        row_offset += height;
+        row_offset += h;
     }
     gtk_style_context_restore (stylectxt);
 
diff --git a/gnucash/register/register-gnome/gnucash-item-edit.c b/gnucash/register/register-gnome/gnucash-item-edit.c
index 39641d1..91aa497 100644
--- a/gnucash/register/register-gnome/gnucash-item-edit.c
+++ b/gnucash/register/register-gnome/gnucash-item-edit.c
@@ -58,157 +58,6 @@ enum
 
 static GtkBoxClass *gnc_item_edit_parent_class;
 
-static GtkToggleButtonClass *gnc_item_edit_tb_parent_class;
-
-static void
-gnc_item_edit_tb_init (GncItemEditTb *item_edit_tb)
-{
-    item_edit_tb->sheet = NULL;
-}
-
-static void
-gnc_item_edit_tb_get_property (GObject *object,
-                               guint param_id,
-                               GValue *value,
-                               GParamSpec *pspec)
-{
-    GncItemEditTb *item_edit_tb = GNC_ITEM_EDIT_TB (object);
-
-    switch (param_id)
-    {
-    case PROP_SHEET:
-        g_value_take_object (value, item_edit_tb->sheet);
-        break;
-    default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
-        break;
-    }
-}
-
-static void
-gnc_item_edit_tb_set_property (GObject *object,
-                               guint param_id,
-                               const GValue *value,
-                               GParamSpec *pspec)
-{
-    GncItemEditTb *item_edit_tb = GNC_ITEM_EDIT_TB (object);
-
-    switch (param_id)
-    {
-    case PROP_SHEET:
-        item_edit_tb->sheet = GNUCASH_SHEET (g_value_get_object (value));
-        break;
-    default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
-        break;
-    }
-}
-
-static void
-gnc_item_edit_tb_get_preferred_width (GtkWidget *widget,
-                                   gint *minimal_width,
-                                   gint *natural_width)
-{
-    GncItemEditTb *tb = GNC_ITEM_EDIT_TB (widget);
-    GncItemEdit *item_edit = GNC_ITEM_EDIT(tb->sheet->item_editor);
-    gint x, y, w, h, width = 0;
-    gnc_item_edit_get_pixel_coords (GNC_ITEM_EDIT (item_edit), &x, &y, &w, &h);
-    width = ((h - 2)*2)/3;
-    if (width < 20) // minimum size for a button
-        width = 20;
-    *minimal_width = *natural_width = width;
-}
-
-static void
-gnc_item_edit_tb_get_preferred_height (GtkWidget *widget,
-                                    gint *minimal_width,
-                                    gint *natural_width)
-{
-    GncItemEditTb *tb = GNC_ITEM_EDIT_TB (widget);
-    GncItemEdit *item_edit = GNC_ITEM_EDIT(tb->sheet->item_editor);
-    gint x, y, w, h;
-    gnc_item_edit_get_pixel_coords (GNC_ITEM_EDIT (item_edit), &x, &y, &w, &h);
-    *minimal_width = *natural_width = (h - 2);
-}
-
-static void
-gnc_item_edit_tb_class_init (GncItemEditTbClass *gnc_item_edit_tb_class)
-{
-    GObjectClass  *object_class;
-    GtkWidgetClass *widget_class;
-
-#if GTK_CHECK_VERSION(3,20,0)
-//    gtk_widget_class_set_css_name (GTK_WIDGET_CLASS(gnc_item_edit_tb_class), "button");
-    gtk_widget_class_set_css_name (GTK_WIDGET_CLASS(gnc_item_edit_tb_class), "toggle-button");
-#endif
-
-    gnc_item_edit_tb_parent_class = g_type_class_peek_parent (gnc_item_edit_tb_class);
-
-    object_class = G_OBJECT_CLASS (gnc_item_edit_tb_class);
-    widget_class = GTK_WIDGET_CLASS (gnc_item_edit_tb_class);
-
-    object_class->get_property = gnc_item_edit_tb_get_property;
-    object_class->set_property = gnc_item_edit_tb_set_property;
-
-    g_object_class_install_property (object_class,
-                                     PROP_SHEET,
-                                     g_param_spec_object ("sheet",
-                                             "Sheet Value",
-                                             "Sheet Value",
-                                             GNUCASH_TYPE_SHEET,
-                                             G_PARAM_READWRITE));
-
-    /* GtkWidget method overrides */
-    widget_class->get_preferred_width = gnc_item_edit_tb_get_preferred_width;
-    widget_class->get_preferred_height = gnc_item_edit_tb_get_preferred_height;
-}
-
-GType
-gnc_item_edit_tb_get_type (void)
-{
-    static GType gnc_item_edit_tb_type = 0;
-
-    if (!gnc_item_edit_tb_type)
-    {
-        static const GTypeInfo gnc_item_edit_tb_info =
-        {
-            sizeof (GncItemEditTbClass),
-            NULL,
-            NULL,
-            (GClassInitFunc) gnc_item_edit_tb_class_init,
-            NULL,
-            NULL,
-            sizeof (GncItemEditTb),
-            0, /* n_preallocs */
-            (GInstanceInitFunc) gnc_item_edit_tb_init,
-            NULL,
-        };
-        gnc_item_edit_tb_type =
-            g_type_register_static(GTK_TYPE_TOGGLE_BUTTON,
-                                   "GncItemEditTb",
-                                   &gnc_item_edit_tb_info, 0);
-    }
-    return gnc_item_edit_tb_type;
-}
-
-GtkWidget *
-gnc_item_edit_tb_new (GnucashSheet *sheet)
-{
-    GtkStyleContext *context;
-    GncItemEditTb *item_edit_tb =
-            g_object_new (GNC_TYPE_ITEM_EDIT_TB,
-                          "sheet", sheet,
-                           NULL);
-
-    // This sets a style class for when Gtk+ version is less than 3.20
-//    gnc_widget_set_css_name (GTK_WIDGET(item_edit_tb), "button");
-    gnc_widget_set_css_name (GTK_WIDGET(item_edit_tb), "toggle-button");
-
-    context = gtk_widget_get_style_context (GTK_WIDGET(item_edit_tb));
-    gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
-
-    return GTK_WIDGET(item_edit_tb);
-}
 
 /*
  * Returns the coordinates for the editor bounding box
@@ -245,6 +94,14 @@ gnc_item_edit_get_pixel_coords (GncItemEdit *item_edit,
     *y += yd;
 }
 
+
+int
+gnc_item_edit_get_toggle_offset (int row_height)
+{
+    /* sync with gnc_item_edit_update */
+    return row_height - (2 * (CELL_VPADDING + 1)) + 3;
+}
+
 static gboolean
 gnc_item_edit_update (GncItemEdit *item_edit)
 {
@@ -487,8 +344,11 @@ draw_background_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data)
 
     gtk_style_context_save (stylectxt);
 
-    // Get the color type and apply the css class
-    color_type = gnc_table_get_color (item_edit->sheet->table, item_edit->virt_loc, NULL);
+    // Get the background and foreground color types and apply the css class
+    color_type = gnc_table_get_bg_color (item_edit->sheet->table, item_edit->virt_loc, NULL);
+    gnucash_get_style_classes (item_edit->sheet, stylectxt, color_type);
+
+    color_type = gnc_table_get_fg_color (item_edit->sheet->table, item_edit->virt_loc);
     gnucash_get_style_classes (item_edit->sheet, stylectxt, color_type);
 
     gtk_render_background (stylectxt, cr, 0, 1, width, height - 2);
@@ -501,7 +361,6 @@ draw_background_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data)
 static gboolean
 draw_text_cursor_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data)
 {
-    GncItemEdit *item_edit = GNC_ITEM_EDIT(user_data);
     GtkEditable *editable = GTK_EDITABLE(widget);
     GtkStyleContext *stylectxt = gtk_widget_get_style_context (GTK_WIDGET(widget));
     gint height = gtk_widget_get_allocated_height (widget);
@@ -542,15 +401,8 @@ draw_text_cursor_cb (GtkWidget *widget, cairo_t *cr, gpointer user_data)
     // Now draw a vertical line
     cairo_set_source_rgb (cr, fg_color->red, fg_color->green, fg_color->blue);
     cairo_set_line_width (cr, 1.0);
-#if GTK_CHECK_VERSION(3,20,0)
-    cairo_move_to (cr, cursor_x + 0.5, gnc_item_edit_get_margin (item_edit, top) +
-                                       gnc_item_edit_get_padding_border (item_edit, top));
-    cairo_rel_line_to (cr, 0, height - gnc_item_edit_get_margin (item_edit, top_bottom) -
-                                       gnc_item_edit_get_padding_border (item_edit, top_bottom));
-#else
-    cairo_move_to (cr, cursor_x + 0.5, gnc_item_edit_get_padding_border (item_edit, top));
-    cairo_rel_line_to (cr, 0, height - gnc_item_edit_get_padding_border (item_edit, top_bottom));
-#endif
+    cairo_move_to (cr, cursor_x + 0.5, 2);
+    cairo_rel_line_to (cr, 0, height - 4);
     cairo_stroke (cr);
 
     return FALSE;
@@ -568,9 +420,6 @@ draw_arrow_cb (GtkWidget *widget, cairo_t *cr, gpointer data)
 
     gtk_render_background (context, cr, 0, 0, width, height);
 
-    gtk_style_context_add_class (context, GTK_STYLE_CLASS_FRAME);
-    gtk_render_frame (context, cr, 1, 1, width - 2, height - 2);
-
     gtk_style_context_add_class (context, GTK_STYLE_CLASS_ARROW);
 
     size = MIN(width / 2, height / 2);
@@ -759,60 +608,13 @@ gnc_item_edit_get_type (void)
     return gnc_item_edit_type;
 }
 
-gint
-gnc_item_edit_get_margin (GncItemEdit *item_edit, Sides side)
-{
-    switch (side)
-    {
-    case left:
-        return item_edit->margin.left;
-    case right:
-        return item_edit->margin.right;
-    case top:
-        return item_edit->margin.top;
-    case bottom:
-        return item_edit->margin.bottom;
-    case left_right:
-        return item_edit->margin.left + item_edit->margin.right;
-    case top_bottom:
-        return item_edit->margin.top + item_edit->margin.bottom;
-    default:
-        return 2;
-    }
-}
-
-gint
-gnc_item_edit_get_padding_border (GncItemEdit *item_edit, Sides side)
-{
-    switch (side)
-    {
-    case left:
-        return item_edit->padding.left + item_edit->border.left;
-    case right:
-        return item_edit->padding.right + item_edit->border.right;
-    case top:
-        return item_edit->padding.top + item_edit->border.top;
-    case bottom:
-        return item_edit->padding.bottom + item_edit->border.bottom;
-    case left_right:
-        return item_edit->padding.left + item_edit->border.left +
-               item_edit->padding.right + item_edit->border.right;
-    case top_bottom:
-        return item_edit->padding.top + item_edit->border.top +
-               item_edit->padding.bottom + item_edit->border.bottom;
-    default:
-        return 2;
-    }
-}
 
 GtkWidget *
 gnc_item_edit_new (GnucashSheet *sheet)
 {
-    GtkStyleContext *stylectxt;
-    GtkBorder padding;
-    GtkBorder margin;
-    GtkBorder border;
-    GtkWidget *vb = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+    char *hpad_str, *vpad_str, *entry_css;
+    GtkStyleContext *stylecontext;
+    GtkCssProvider *provider;
     GncItemEdit *item_edit =
             g_object_new (GNC_TYPE_ITEM_EDIT,
                           "sheet", sheet,
@@ -828,54 +630,32 @@ gnc_item_edit_new (GnucashSheet *sheet)
     item_edit->editor = gtk_entry_new();
     sheet->entry = item_edit->editor;
     gtk_entry_set_width_chars (GTK_ENTRY(item_edit->editor), 1);
-    gtk_box_pack_start (GTK_BOX(item_edit), item_edit->editor, TRUE, TRUE, 0);
-
-    // Get the CSS space settings for the entry
-    stylectxt = gtk_widget_get_style_context (GTK_WIDGET(item_edit->editor));
-    gtk_style_context_get_padding (stylectxt, GTK_STATE_FLAG_NORMAL, &padding);
-    gtk_style_context_get_margin (stylectxt, GTK_STATE_FLAG_NORMAL, &margin);
-    gtk_style_context_get_border (stylectxt, GTK_STATE_FLAG_NORMAL, &border);
-
-    item_edit->padding = padding;
-    item_edit->margin = margin;
-    item_edit->border = border;
+    gtk_box_pack_start (GTK_BOX(item_edit), item_edit->editor,  TRUE, TRUE, 0);
 
     // Make sure the Entry can not have focus and no frame
     gtk_widget_set_can_focus (GTK_WIDGET(item_edit->editor), FALSE);
     gtk_entry_set_has_frame (GTK_ENTRY(item_edit->editor), FALSE);
 
-#if !GTK_CHECK_VERSION(3,20,0)
-#if GTK_CHECK_VERSION(3,12,0)
-    gtk_widget_set_margin_start (GTK_WIDGET(item_edit->editor),
-                                 gnc_item_edit_get_margin (item_edit, left));
-    gtk_widget_set_margin_end (GTK_WIDGET(item_edit->editor),
-                               gnc_item_edit_get_margin (item_edit, right));
-#else
-    gtk_widget_set_margin_left (GTK_WIDGET(item_edit->editor),
-                                gnc_item_edit_get_margin (item_edit, left));
-    gtk_widget_set_margin_right (GTK_WIDGET(item_edit->editor),
-                                 gnc_item_edit_get_margin (item_edit, right));
-#endif
-    gtk_widget_set_margin_top (GTK_WIDGET(item_edit->editor),
-                               gnc_item_edit_get_margin (item_edit, top));
-    gtk_widget_set_margin_bottom (GTK_WIDGET(item_edit->editor),
-                                  gnc_item_edit_get_margin (item_edit, bottom));
-#endif
-
     // Connect to the draw signal so we can draw a cursor
     g_signal_connect_after (item_edit->editor, "draw",
-                            G_CALLBACK (draw_text_cursor_cb), item_edit);
+                            G_CALLBACK (draw_text_cursor_cb), NULL);
 
     // Fill in the background so the underlying sheet cell can not be seen
     g_signal_connect (item_edit, "draw",
                             G_CALLBACK (draw_background_cb), item_edit);
 
+    /* Force padding on the entry to align with the rest of the register this
+       is done in the gnucash.css file which should be in line with sheet.h */
+
     /* Create the popup button
        It will only be displayed when the cell being edited provides
        a popup item (like a calendar or account list) */
-    item_edit->popup_toggle.tbutton = gnc_item_edit_tb_new (sheet);
+    item_edit->popup_toggle.tbutton = gtk_toggle_button_new();
     gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (item_edit->popup_toggle.tbutton), FALSE);
 
+    /* Force padding on the button to keep it small and display as much as
+       possible of the arrow which is done in the gnucash.css file */
+
     /* Wrap the popup button in an event box to give it its own gdkwindow.
      * Without one the button would disappear behind the grid object. */
     item_edit->popup_toggle.ebox = gtk_event_box_new();
@@ -883,35 +663,14 @@ gnc_item_edit_new (GnucashSheet *sheet)
     gtk_container_add(GTK_CONTAINER(item_edit->popup_toggle.ebox),
                       item_edit->popup_toggle.tbutton);
 
-    /* The button needs to be packed into a vertical box so that the height and position
-     * can be controlled in ealier than Gtk3.20 versions */
-    gtk_box_pack_start (GTK_BOX(vb), item_edit->popup_toggle.ebox,
-                        FALSE, FALSE, 0);
-
-    gtk_box_pack_start (GTK_BOX(item_edit), vb, FALSE, FALSE, 0);
+    gtk_box_pack_start (GTK_BOX(item_edit),
+                        item_edit->popup_toggle.ebox,
+                        FALSE, TRUE, 0);
     gtk_widget_show_all(GTK_WIDGET(item_edit));
+
     return GTK_WIDGET(item_edit);
 }
 
-static void
-check_popup_height_is_true (GtkWidget    *widget,
-                            GdkRectangle *allocation,
-                            gpointer user_data)
-{
-    GncItemEdit *item_edit = GNC_ITEM_EDIT(user_data);
-    GnucashSheet *sheet = item_edit->sheet;
-
-    // if a larger font is specified in css for the sheet, the popup returned height value
-    // on first pop does not reflect the true height but the minimum height so just to be
-    // sure check this value against the allocated one.
-    if (allocation->height != item_edit->popup_returned_height)
-    {
-        gtk_container_remove (GTK_CONTAINER(item_edit->sheet), item_edit->popup_item);
-
-        g_idle_add_full (G_PRIORITY_HIGH_IDLE,
-                        (GSourceFunc) gnc_item_edit_update, item_edit, NULL);
-    }
-}
 
 void
 gnc_item_edit_show_popup (GncItemEdit *item_edit)
@@ -980,11 +739,6 @@ gnc_item_edit_show_popup (GncItemEdit *item_edit)
     if (!gtk_widget_get_parent (item_edit->popup_item))
         gtk_layout_put (GTK_LAYOUT(sheet), item_edit->popup_item, popup_x, popup_y);
 
-    // Lets check popup height is the true height
-    item_edit->popup_returned_height = popup_h;
-    g_signal_connect_after (item_edit->popup_item, "size-allocate",
-                            G_CALLBACK(check_popup_height_is_true), item_edit);
-
     gtk_widget_set_size_request (item_edit->popup_item, popup_w - 1, popup_h);
 
     toggle = GTK_TOGGLE_BUTTON(item_edit->popup_toggle.tbutton);
diff --git a/gnucash/register/register-gnome/gnucash-item-edit.h b/gnucash/register/register-gnome/gnucash-item-edit.h
index 2be4d24..7b8969a 100644
--- a/gnucash/register/register-gnome/gnucash-item-edit.h
+++ b/gnucash/register/register-gnome/gnucash-item-edit.h
@@ -37,10 +37,6 @@
 #define GNC_ITEM_EDIT_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST ((k), GNC_TYPE_ITEM_EDIT, GncItemEditClass))
 #define GNC_IS_ITEM_EDIT(o)       (G_TYPE_CHECK_INSTANCE_TYPE((o), GNC_TYPE_ITEM_EDIT))
 
-#define GNC_TYPE_ITEM_EDIT_TB        (gnc_item_edit_tb_get_type ())
-#define GNC_ITEM_EDIT_TB(o)          (G_TYPE_CHECK_INSTANCE_CAST((o), GNC_TYPE_ITEM_EDIT_TB, GncItemEditTb))
-#define GNC_ITEM_EDIT_TB_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST ((k), GNC_TYPE_ITEM_EDIT_TB, GncItemEditTbClass))
-#define GNC_IS_ITEM_EDIT_TB(o)       (G_TYPE_CHECK_INSTANCE_TYPE((o), GNC_TYPE_ITEM_EDIT_TB))
 
 typedef int (*PopupGetHeight) (GtkWidget *item,
                                int space_available,
@@ -89,11 +85,6 @@ typedef struct
     PopupPostShow    popup_post_show;
     PopupGetWidth    popup_get_width;
     gpointer         popup_user_data;
-    gint             popup_returned_height;
-
-    GtkBorder        padding;
-    GtkBorder        margin;
-    GtkBorder        border;
 
     /* Where are we */
     VirtualLocation virt_loc;
@@ -106,28 +97,6 @@ typedef struct
     GtkBoxClass parent_class;
 } GncItemEditClass;
 
-typedef struct
-{
-    GtkToggleButton tb;
-    GnucashSheet *sheet;
-} GncItemEditTb;
-
-typedef struct
-{
-    GtkToggleButtonClass parent_class;
-
-    void (* toggled) (GncItemEditTb *item_edit_tb);
-} GncItemEditTbClass;
-
-typedef enum
-{
-    left,
-    right,
-    top,
-    bottom,
-    left_right,
-    top_bottom,
-} Sides;
 
 GType gnc_item_edit_get_type (void);
 
@@ -151,6 +120,8 @@ void gnc_item_edit_set_popup (GncItemEdit    *item_edit,
 void gnc_item_edit_show_popup (GncItemEdit *item_edit);
 void gnc_item_edit_hide_popup (GncItemEdit *item_edit);
 
+int gnc_item_edit_get_toggle_offset (int row_height);
+
 void gnc_item_edit_cut_clipboard (GncItemEdit *item_edit);
 void gnc_item_edit_copy_clipboard (GncItemEdit *item_edit);
 void gnc_item_edit_paste_clipboard (GncItemEdit *item_edit);
@@ -159,11 +130,5 @@ gboolean gnc_item_edit_get_has_selection (GncItemEdit *item_edit);
 void gnc_item_edit_focus_in (GncItemEdit *item_edit);
 void gnc_item_edit_focus_out (GncItemEdit *item_edit);
 
-gint gnc_item_edit_get_margin (GncItemEdit *item_edit, Sides side);
-gint gnc_item_edit_get_padding_border (GncItemEdit *item_edit, Sides side);
-
-GType gnc_item_edit_tb_get_type (void);
-GtkWidget *gnc_item_edit_tb_new (GnucashSheet *sheet);
-
 /** @} */
 #endif /* GNUCASH_ITEM_EDIT_H */
diff --git a/gnucash/register/register-gnome/gnucash-sheet-private.c b/gnucash/register/register-gnome/gnucash-sheet-private.c
index e71db31..955f607 100644
--- a/gnucash/register/register-gnome/gnucash-sheet-private.c
+++ b/gnucash/register/register-gnome/gnucash-sheet-private.c
@@ -381,7 +381,6 @@ draw_cell (GnucashSheet *sheet,
            cairo_t *cr,
            int x, int y, int width, int height)
 {
-    GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
     Table *table = sheet->table;
     PhysicalCellBorders borders;
     const char *text;
@@ -399,8 +398,11 @@ draw_cell (GnucashSheet *sheet,
 
     gtk_style_context_save (stylectxt);
 
-    // Get the color type and apply the css class
-    color_type = gnc_table_get_color (table, virt_loc, &hatching);
+    // Get the background and foreground color types and apply the css class
+    color_type = gnc_table_get_bg_color (table, virt_loc, &hatching);
+    gnucash_get_style_classes (sheet, stylectxt, color_type);
+
+    color_type = gnc_table_get_fg_color (table, virt_loc);
     gnucash_get_style_classes (sheet, stylectxt, color_type);
 
     // Are we in a read-only row? Then make the background color somewhat more grey.
@@ -415,10 +417,7 @@ draw_cell (GnucashSheet *sheet,
     gtk_render_background (stylectxt, cr, x, y, width, height);
 
     gdk_rgba_parse (&color, "black");
-    if (gtk_style_context_get_state (stylectxt) == GTK_STATE_FLAG_INSENSITIVE)
-        gnc_style_context_get_background_color (stylectxt, GTK_STATE_FLAG_INSENSITIVE, &color);
-    else
-        gnc_style_context_get_background_color (stylectxt, GTK_STATE_FLAG_NORMAL, &color);
+    gnc_style_context_get_background_color (stylectxt, GTK_STATE_FLAG_NORMAL, &color);
     bg_color = &color;
 
     get_cell_borders (sheet, virt_loc, &borders);
@@ -525,19 +524,39 @@ draw_cell (GnucashSheet *sheet,
         goto exit;
     }
 
-    pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
+    pango_layout_get_pixel_extents(layout,
+                                   NULL,
+                                   &logical_rect);
 
-    gnucash_sheet_set_text_bounds (sheet, &rect, x, y, width, height);
+    rect.x      = x + CELL_HPADDING;
+    rect.y      = y + CELL_VPADDING;
+    rect.width  = MAX (0, width - (2 * CELL_HPADDING));
+    rect.height = height - 2;
 
     cairo_save (cr);
     cairo_rectangle (cr, rect.x, rect.y, rect.width, rect.height);
     cairo_clip (cr);
 
-    x_offset = gnucash_sheet_get_text_offset (sheet, virt_loc,
-                                              rect.width, logical_rect.width);
-
-    gtk_render_layout (stylectxt, cr, rect.x + x_offset,
-                       rect.y + gnc_item_edit_get_padding_border (item_edit, top), layout);
+    switch (gnc_table_get_align (table, virt_loc))
+    {
+    default:
+    case CELL_ALIGN_LEFT:
+        x_offset = 0;
+        break;
+
+    case CELL_ALIGN_RIGHT:
+        x_offset = width - 2 * CELL_HPADDING - logical_rect.width - 3;
+        break;
+
+    case CELL_ALIGN_CENTER:
+        if (logical_rect.width > width - 2 * CELL_HPADDING)
+            x_offset = 0;
+        else
+            x_offset = (width - 2 * CELL_HPADDING -
+                        logical_rect.width) / 2;
+        break;
+    }
+    gtk_render_layout (stylectxt, cr, rect.x + x_offset + 1, rect.y, layout);
 
     cairo_restore (cr);
 
@@ -682,7 +701,7 @@ gnucash_sheet_draw_cursor (GnucashCursor *cursor, cairo_t *cr)
     cairo_stroke (cr);
 
     // make the bottom line thicker
-    cairo_move_to (cr, cursor->x - x + 0.5, cursor->y - y + cursor->h - 3.5);
+    cairo_move_to (cr, cursor->x - x + 0.5, cursor->y - y + cursor->h - 1.5);
     cairo_rel_line_to (cr, cursor->w, 0);
     cairo_set_line_width (cr, 1.0);
     cairo_stroke (cr);
diff --git a/gnucash/register/register-gnome/gnucash-sheet.c b/gnucash/register/register-gnome/gnucash-sheet.c
index 311ab1b..d8a6cea 100644
--- a/gnucash/register/register-gnome/gnucash-sheet.c
+++ b/gnucash/register/register-gnome/gnucash-sheet.c
@@ -261,47 +261,6 @@ gnucash_sheet_deactivate_cursor_cell (GnucashSheet *sheet)
     gnucash_sheet_redraw_block (sheet, virt_loc.vcell_loc);
 }
 
-void
-gnucash_sheet_set_text_bounds (GnucashSheet *sheet, GdkRectangle *rect,
-                               gint x, gint y, gint width, gint height)
-{
-    GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
-
-    rect->x = x + gnc_item_edit_get_margin (item_edit, left);
-    rect->y = y + gnc_item_edit_get_margin (item_edit, top);
-    rect->width = MAX (0, width - gnc_item_edit_get_margin (item_edit, left_right));
-    rect->height = height - gnc_item_edit_get_margin (item_edit, top_bottom);
-}
-
-gint
-gnucash_sheet_get_text_offset (GnucashSheet *sheet, const VirtualLocation virt_loc,
-                                gint rect_width, gint logical_width)
-{
-    GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
-    Table *table = sheet->table;
-    gint x_offset = 0;
-
-    // Get the alignment of the cell
-    switch (gnc_table_get_align (table, virt_loc))
-    {
-    default:
-    case CELL_ALIGN_LEFT:
-        x_offset = gnc_item_edit_get_padding_border (item_edit, left);
-        break;
-
-    case CELL_ALIGN_RIGHT:
-        x_offset = rect_width - gnc_item_edit_get_padding_border (item_edit, right) - logical_width - 1;
-        break;
-
-    case CELL_ALIGN_CENTER:
-        if (logical_width > rect_width)
-            x_offset = 0;
-        else
-            x_offset = (rect_width - logical_width) / 2;
-        break;
-    }
-    return x_offset;
-}
 
 static gint
 gnucash_sheet_get_text_cursor_position (GnucashSheet *sheet, const VirtualLocation virt_loc)
@@ -312,7 +271,7 @@ gnucash_sheet_get_text_cursor_position (GnucashSheet *sheet, const VirtualLocati
     PangoLayout *layout;
     PangoRectangle logical_rect;
     GdkRectangle rect;
-    gint x, y, width, height;
+    gint x, y, w, h;
     gint index, trailing;
     gboolean result;
     gint x_offset = 0;
@@ -321,7 +280,7 @@ gnucash_sheet_get_text_cursor_position (GnucashSheet *sheet, const VirtualLocati
         return 0;
 
     // Get the item_edit position
-    gnc_item_edit_get_pixel_coords (item_edit, &x, &y, &width, &height);
+    gnc_item_edit_get_pixel_coords (item_edit, &x, &y, &w, &h);
 
     layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), text);
 
@@ -330,14 +289,35 @@ gnucash_sheet_get_text_cursor_position (GnucashSheet *sheet, const VirtualLocati
 
     pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
 
-    gnucash_sheet_set_text_bounds (sheet, &rect, x, y, width, height);
+    rect.x      = x + CELL_HPADDING;
+    rect.y      = y + CELL_VPADDING;
+    rect.width  = MAX (0, w - (2 * CELL_HPADDING));
+    rect.height = h - 2;
+
+    // Get the alignment of the cell
+    switch (gnc_table_get_align (table, virt_loc))
+    {
+    default:
+    case CELL_ALIGN_LEFT:
+        x_offset = 0;
+        break;
+
+    case CELL_ALIGN_RIGHT:
+        x_offset = w - 2 * CELL_HPADDING - logical_rect.width - 3;
+        break;
 
-    x_offset = gnucash_sheet_get_text_offset (sheet, virt_loc,
-                                              rect.width, logical_rect.width);
+    case CELL_ALIGN_CENTER:
+        if (logical_rect.width > w - 2 * CELL_HPADDING)
+            x_offset = 0;
+        else
+            x_offset = (w - 2 * CELL_HPADDING -
+                        logical_rect.width) / 2;
+        break;
+    }
 
     result = pango_layout_xy_to_index (layout,
                  PANGO_SCALE * (sheet->button_x - rect.x - x_offset),
-                 PANGO_SCALE * (height/2), &index, &trailing);
+                 PANGO_SCALE * (h/2), &index, &trailing);
 
     g_object_unref (layout);
 
@@ -2210,7 +2190,6 @@ gnucash_sheet_col_max_width (GnucashSheet *sheet, gint virt_col, gint cell_col)
     SheetBlock *block;
     SheetBlockStyle *style;
     PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), "");
-    GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
 
     g_return_val_if_fail (virt_col >= 0, 0);
     g_return_val_if_fail (virt_col < sheet->num_virt_cols, 0);
@@ -2250,7 +2229,7 @@ gnucash_sheet_col_max_width (GnucashSheet *sheet, gint virt_col, gint cell_col)
                 pango_layout_set_text (layout, text, strlen (text));
                 pango_layout_get_pixel_size (layout, &width, NULL);
 
-                width += gnc_item_edit_get_margin (item_edit, left_right);
+                width += 2 * CELL_HPADDING;
 
                 max = MAX (max, width);
             }
@@ -2428,46 +2407,52 @@ gnucash_sheet_table_load (GnucashSheet *sheet, gboolean do_scroll)
 
 /*************************************************************/
 
-/** Map a cell color type to a css style class. */
+/** Map a cell type to a css style class. */
 void
 gnucash_get_style_classes (GnucashSheet *sheet, GtkStyleContext *stylectxt,
                            RegisterColor field_type)
 {
     gchar *full_class, *style_class = NULL;
 
-    if (field_type >= COLOR_NEGATIVE) // Require a Negative fg color
-    {
-        gtk_style_context_add_class (stylectxt, "negative-numbers");
-        field_type -= COLOR_NEGATIVE;
-    }
-
     switch (field_type)
     {
     default:
-    case COLOR_UNDEFINED:
+    case COLOR_UNKNOWN_BG:
+    case COLOR_UNKNOWN_FG:
         gtk_style_context_add_class (stylectxt, GTK_STYLE_CLASS_BACKGROUND);
         return;
 
-    case COLOR_HEADER:
+    case COLOR_NEGATIVE:
+        gtk_style_context_add_class (stylectxt, "negative-numbers");
+        return;
+
+    case COLOR_HEADER_BG:
+    case COLOR_HEADER_FG:
         style_class = "header";
         break;
 
-    case COLOR_PRIMARY:
+    case COLOR_PRIMARY_BG:
+    case COLOR_PRIMARY_FG:
         style_class = "primary";
         break;
 
-    case COLOR_PRIMARY_ACTIVE:
-    case COLOR_SECONDARY_ACTIVE:
-    case COLOR_SPLIT_ACTIVE:
+    case COLOR_PRIMARY_BG_ACTIVE:
+    case COLOR_PRIMARY_FG_ACTIVE:
+    case COLOR_SECONDARY_BG_ACTIVE:
+    case COLOR_SECONDARY_FG_ACTIVE:
+    case COLOR_SPLIT_BG_ACTIVE:
+    case COLOR_SPLIT_FG_ACTIVE:
         gtk_style_context_set_state (stylectxt, GTK_STATE_FLAG_SELECTED);
         style_class = "cursor";
         break;
 
-    case COLOR_SECONDARY:
+    case COLOR_SECONDARY_BG:
+    case COLOR_SECONDARY_FG:
         style_class = "secondary";
         break;
 
-    case COLOR_SPLIT:
+    case COLOR_SPLIT_BG:
+    case COLOR_SPLIT_FG:
         style_class = "split";
         break;
     }
diff --git a/gnucash/register/register-gnome/gnucash-sheet.h b/gnucash/register/register-gnome/gnucash-sheet.h
index f729e8f..b571d03 100644
--- a/gnucash/register/register-gnome/gnucash-sheet.h
+++ b/gnucash/register/register-gnome/gnucash-sheet.h
@@ -33,6 +33,10 @@
  * @brief Public declarations of GnucashSheet class.
  */
 
+#define CELL_VPADDING 2
+#define CELL_HPADDING 5
+
+
 #define GNUCASH_TYPE_SHEET     (gnucash_sheet_get_type ())
 #define GNUCASH_SHEET(obj)     (G_TYPE_CHECK_INSTANCE_CAST((obj), GNUCASH_TYPE_SHEET, GnucashSheet))
 #define GNUCASH_SHEET_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GNUCASH_TYPE_SHEET))
@@ -104,11 +108,5 @@ void gnucash_sheet_set_window (GnucashSheet *sheet, GtkWidget *window);
 void gnucash_get_style_classes (GnucashSheet *sheet, GtkStyleContext *stylectxt,
                                 RegisterColor field_type);
 
-void gnucash_sheet_set_text_bounds (GnucashSheet *sheet, GdkRectangle *rect,
-                                    gint x, gint y, gint width, gint height);
-
-gint gnucash_sheet_get_text_offset (GnucashSheet *sheet, const VirtualLocation virt_loc,
-                                    gint rect_width, gint logical_width);
-
 /** @} */
 #endif
diff --git a/gnucash/register/register-gnome/gnucash-style.c b/gnucash/register/register-gnome/gnucash-style.c
index e999620..dcadb7c 100644
--- a/gnucash/register/register-gnome/gnucash-style.c
+++ b/gnucash/register/register-gnome/gnucash-style.c
@@ -169,7 +169,6 @@ set_dimensions_pass_one (GnucashSheet *sheet, CellBlock *cursor,
     int row, col;
     gint max_height = -1;
     PangoLayout *layout;
-    GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
 
     /* g_return_if_fail (font != NULL); */
 
@@ -197,17 +196,13 @@ set_dimensions_pass_one (GnucashSheet *sheet, CellBlock *cursor,
                 layout = gtk_widget_create_pango_layout (GTK_WIDGET (sheet), text);
                 pango_layout_get_pixel_size (layout, &width, &cd->pixel_height);
                 g_object_unref (layout);
-                width += gnc_item_edit_get_margin (item_edit, left_right) +
-                         gnc_item_edit_get_padding_border (item_edit, left_right);
-
-                cd->pixel_height += gnc_item_edit_get_margin (item_edit, top_bottom) +
-                                    gnc_item_edit_get_padding_border (item_edit, top_bottom);
+                width += 2 * CELL_HPADDING;
+                cd->pixel_height += 2 * CELL_VPADDING;
             }
             else
             {
                 width = 0;
-                cd->pixel_height = gnc_item_edit_get_margin (item_edit, top_bottom) +
-                                   gnc_item_edit_get_padding_border (item_edit, top_bottom);
+                cd->pixel_height = (2 * CELL_VPADDING);
             }
 
             max_height = MAX(max_height, cd->pixel_height);
@@ -215,10 +210,9 @@ set_dimensions_pass_one (GnucashSheet *sheet, CellBlock *cursor,
             if (cd->pixel_width > 0)
                 continue;
 
-            // This is used on new account popup cells to get the default
-            // width of text plus toggle button.
             if (cell && cell->is_popup)
-                width += cd->pixel_height; // toggle button is square, use cell height
+                width += gnc_item_edit_get_toggle_offset
+                         (cd->pixel_height);
 
             cd->pixel_width = MAX (cd->pixel_width, width);
         }
@@ -245,7 +239,6 @@ static void
 set_dimensions_pass_two (GnucashSheet *sheet, int default_width)
 {
     SheetBlockStyle *style;
-    GncItemEdit *item_edit = GNC_ITEM_EDIT(sheet->item_editor);
     BlockDimensions *dimensions;
     CellDimensions *cd;
     GTable *cd_table;
@@ -322,8 +315,7 @@ set_dimensions_pass_two (GnucashSheet *sheet, int default_width)
                 pango_layout_get_pixel_size (layout, &sample_width, NULL);
                 g_object_unref (layout);
                 /*sample_width = gdk_string_width (font, text);*/
-                sample_width += gnc_item_edit_get_margin (item_edit, left_right) +
-                                gnc_item_edit_get_padding_border (item_edit, left_right);
+                sample_width += 2 * CELL_HPADDING;
             }
             else
                 sample_width = 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                                     |  35 +-
 ChangeLog                                          | 446 ++++++++++++++++++++-
 NEWS                                               |  97 +++++
 bindings/python/Makefile.am                        |  17 +-
 bindings/python/sqlite3test.c                      |   6 +-
 bindings/python/tests/CMakeLists.txt               |   1 +
 borrowed/goffice/CMakeLists.txt                    |   6 +-
 borrowed/gwengui-gtk3/CMakeLists.txt               |   6 +-
 cmake/CMakeLists.txt                               |  22 +-
 common/test-core/CMakeLists.txt                    |   3 +-
 common/test-core/unittest_support.py               | 166 --------
 configure.ac                                       |   2 +-
 data/accounts/CMakeLists.txt                       |   2 +-
 data/checks/CMakeLists.txt                         |   2 +-
 gnucash/CMakeLists.txt                             |  15 +-
 gnucash/environment.in                             |   5 +-
 gnucash/gnome-search/CMakeLists.txt                |  10 +-
 gnucash/gnome-utils/CMakeLists.txt                 |  10 +-
 .../gtkbuilder/dialog-preferences.glade            |  15 +-
 gnucash/gnome/CMakeLists.txt                       |   6 +-
 .../gtkbuilder/gnc-plugin-page-register.glade      |  15 +-
 gnucash/gnucash-310.css                            |   2 +-
 gnucash/gnucash-320.css                            |   2 +-
 gnucash/html/CMakeLists.txt                        |  10 +-
 gnucash/html/gnc-html-webkit1.c                    |  15 +-
 gnucash/import-export/CMakeLists.txt               |  10 +-
 gnucash/import-export/aqb/CMakeLists.txt           |   8 +-
 .../import-export/aqb/assistant-ab-initial.glade   |  28 +-
 gnucash/import-export/aqb/dialog-ab-trans.c        |  22 +-
 gnucash/import-export/bi-import/CMakeLists.txt     |   8 +-
 gnucash/import-export/csv-exp/CMakeLists.txt       |   8 +-
 gnucash/import-export/csv-imp/CMakeLists.txt       |   8 +-
 .../import-export/customer-import/CMakeLists.txt   |   8 +-
 gnucash/import-export/dialog-import.glade          |  20 +-
 gnucash/import-export/log-replay/CMakeLists.txt    |   8 +-
 gnucash/import-export/ofx/CMakeLists.txt           |   8 +-
 gnucash/import-export/qif-imp/CMakeLists.txt       |   8 +-
 gnucash/import-export/qif/CMakeLists.txt           |   8 +-
 gnucash/overrides/CMakeLists.txt                   |   2 +-
 gnucash/python/CMakeLists.txt                      |   6 +-
 gnucash/register/ledger-core/CMakeLists.txt        |   8 +-
 gnucash/register/register-core/CMakeLists.txt      |  10 +-
 gnucash/register/register-gnome/CMakeLists.txt     |   8 +-
 .../register/register-gnome/gnucash-item-edit.c    |   9 +-
 .../register-gnome/gnucash-sheet-private.c         |   6 +-
 gnucash/report/locale-specific/us/CMakeLists.txt   |   8 +-
 gnucash/report/report-gnome/CMakeLists.txt         |  10 +-
 gnucash/report/report-system/CMakeLists.txt        |  10 +-
 gnucash/report/report-system/doc/report-html.txt   |   2 +-
 gnucash/report/standard-reports/price-scatter.scm  |   2 +-
 gnucash/report/stylesheets/CMakeLists.txt          |   8 +-
 gnucash/report/stylesheets/stylesheet-easy.scm     |  16 +-
 gnucash/report/stylesheets/stylesheet-fancy.scm    |  16 +-
 gnucash/report/stylesheets/stylesheet-footer.scm   |  16 +-
 .../report/stylesheets/stylesheet-head-or-tail.scm |  16 +-
 gnucash/report/stylesheets/stylesheet-plain.scm    |   4 +-
 gnucash/report/utility-reports/hello-world.scm     |   4 +-
 libgnucash/app-utils/CMakeLists.txt                |  18 +-
 libgnucash/backend/dbi/CMakeLists.txt              |   8 +-
 libgnucash/backend/dbi/gnc-dbiproviderimpl.hpp     |   2 +-
 libgnucash/backend/dbi/gnc-dbisqlconnection.cpp    |   6 +-
 libgnucash/backend/dbi/gnc-dbisqlresult.cpp        |   2 +-
 libgnucash/backend/sql/CMakeLists.txt              |   6 +-
 libgnucash/backend/sql/gnc-account-sql.cpp         |   2 +-
 libgnucash/backend/sql/gnc-address-sql.cpp         |   2 +-
 libgnucash/backend/sql/gnc-bill-term-sql.cpp       |   4 +-
 libgnucash/backend/sql/gnc-book-sql.cpp            |   2 +-
 libgnucash/backend/sql/gnc-budget-sql.cpp          |   2 +-
 libgnucash/backend/sql/gnc-commodity-sql.cpp       |   2 +-
 libgnucash/backend/sql/gnc-customer-sql.cpp        |   4 +-
 libgnucash/backend/sql/gnc-employee-sql.cpp        |   4 +-
 libgnucash/backend/sql/gnc-entry-sql.cpp           |   5 +-
 libgnucash/backend/sql/gnc-invoice-sql.cpp         |   5 +-
 libgnucash/backend/sql/gnc-job-sql.cpp             |   2 +-
 libgnucash/backend/sql/gnc-lots-sql.cpp            |   4 +-
 libgnucash/backend/sql/gnc-order-sql.cpp           |   2 +-
 libgnucash/backend/sql/gnc-owner-sql.cpp           |   4 +-
 libgnucash/backend/sql/gnc-price-sql.cpp           |  11 +-
 libgnucash/backend/sql/gnc-recurrence-sql.cpp      |   4 +-
 libgnucash/backend/sql/gnc-schedxaction-sql.cpp    |   2 +-
 libgnucash/backend/sql/gnc-slots-sql.cpp           |  11 +-
 libgnucash/backend/sql/gnc-sql-backend.cpp         |   5 +-
 .../backend/sql/gnc-sql-column-table-entry.cpp     |  15 +-
 .../backend/sql/gnc-sql-column-table-entry.hpp     |  22 +
 libgnucash/backend/sql/gnc-sql-object-backend.hpp  |   1 -
 libgnucash/backend/sql/gnc-tax-table-sql.cpp       |   6 +-
 libgnucash/backend/sql/gnc-transaction-sql.cpp     |   7 +-
 libgnucash/backend/sql/gnc-vendor-sql.cpp          |   2 +-
 libgnucash/backend/xml/CMakeLists.txt              |  14 +-
 libgnucash/core-utils/CMakeLists.txt               |  12 +-
 libgnucash/engine/CMakeLists.txt                   |  12 +-
 libgnucash/engine/gnc-date.cpp                     |  18 +-
 libgnucash/engine/gnc-date.h                       |   2 +-
 libgnucash/engine/test/test-gnc-date.c             |  23 +-
 libgnucash/gnc-module/CMakeLists.txt               |   8 +-
 libgnucash/quotes/CMakeLists.txt                   |   2 +-
 libgnucash/scm/CMakeLists.txt                      |   2 +-
 libgnucash/tax/us/CMakeLists.txt                   |   8 +-
 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 +--
 106 files changed, 1190 insertions(+), 815 deletions(-)
 delete mode 100644 common/test-core/unittest_support.py



More information about the gnucash-changes mailing list