gnucash unstable: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Wed Dec 13 00:02:22 EST 2017


Updated	 via  https://github.com/Gnucash/gnucash/commit/a5134f91 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/aeb2e65f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/1c8c53a8 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/6db08207 (commit)
	from  https://github.com/Gnucash/gnucash/commit/de4d1e98 (commit)



commit a5134f91e1bbb27d38c10dc3bc0db1a3c828bc61
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Dec 12 21:01:58 2017 -0800

    Fix neutral time for consistent dates in mid-pacific time zones.
    
    Echoes a change made some time ago in 2.6 where the time is adjusted from 10:59Z in time zones where that won't be the same date.

diff --git a/libgnucash/engine/gnc-datetime.cpp b/libgnucash/engine/gnc-datetime.cpp
index e40b898..bad5c9b 100644
--- a/libgnucash/engine/gnc-datetime.cpp
+++ b/libgnucash/engine/gnc-datetime.cpp
@@ -183,6 +183,8 @@ LDT_from_struct_tm(const struct tm tm)
     }
 }
 
+using TD = boost::posix_time::time_duration;
+
 class GncDateTimeImpl
 {
 public:
@@ -204,8 +206,10 @@ public:
     std::string format_zulu(const char* format) const;
 private:
     LDT m_time;
+    static const TD time_of_day[3];
 };
 
+const TD GncDateTimeImpl::time_of_day[3] = {TD(0, 0, 0), TD(10, 59, 0), TD(23, 59, 59)};
 /** Private implementation of GncDate. See the documentation for that class.
  */
 class GncDateImpl
@@ -235,33 +239,24 @@ private:
 
 /* Member function definitions for GncDateTimeImpl.
  */
+
 GncDateTimeImpl::GncDateTimeImpl(const GncDateImpl& date, DayPart part) :
-    m_time(unix_epoch, utc_zone)
+    m_time(date.m_greg, time_of_day[part], tzp.get(date.m_greg.year()),
+                     LDT::NOT_DATE_TIME_ON_ERROR)
 {
-    using TD = boost::posix_time::time_duration;
-    static const TD start(0, 0, 0);
-    static const TD neutral(10, 59, 0);
-    static const TD end(23,59, 59);
-    TD time_of_day;
-    switch (part)
-    {
-        case DayPart::start:
-            time_of_day = start;
-            break;
-        case DayPart::neutral:
-            time_of_day = neutral;
-            break;
-        case DayPart::end:
-            time_of_day = end;
-            break;
-    }
-
+    using boost::posix_time::hours;
     try
     {
-        auto tz = utc_zone;
-        if (part != DayPart::neutral)
-            tz = tzp.get(date.m_greg.year());
-        m_time = LDT(date.m_greg, time_of_day, tz, LDT::EXCEPTION_ON_ERROR);
+        if (part == DayPart::neutral)
+        {
+            auto offset = m_time.local_time() - m_time.utc_time();
+            m_time = LDT(date.m_greg, time_of_day[part], utc_zone,
+                         LDT::EXCEPTION_ON_ERROR);
+            if (offset < hours(-10))
+                m_time -= hours(offset.hours() + 10);
+            if (offset > hours(13))
+                m_time -= hours(offset.hours() - 10);
+        }
     }
     catch(boost::gregorian::bad_year)
     {
diff --git a/libgnucash/engine/gnc-datetime.hpp b/libgnucash/engine/gnc-datetime.hpp
index 104220d..d8cd724 100644
--- a/libgnucash/engine/gnc-datetime.hpp
+++ b/libgnucash/engine/gnc-datetime.hpp
@@ -37,7 +37,7 @@ typedef struct
     int day; //1-31
 } ymd;
 
-enum class DayPart {
+enum DayPart : int {
     start,  // 00:00
     neutral,  // 10:59
     end,  // 23:59

commit aeb2e65ff163f72f1cfb12422378628de58bed89
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Dec 12 11:50:24 2017 -0800

    Fix posted-date scrub incrementing the day in central pacific timezones.

diff --git a/libgnucash/engine/Transaction.c b/libgnucash/engine/Transaction.c
index b6c9264..811100d 100644
--- a/libgnucash/engine/Transaction.c
+++ b/libgnucash/engine/Transaction.c
@@ -2424,7 +2424,20 @@ xaccTransGetDatePostedGDate (const Transaction *trans)
         if (G_VALUE_HOLDS_BOXED (&v))
              result = *(GDate*)g_value_get_boxed (&v);
 	if (! g_date_valid (&result))
-            result = timespec_to_gdate(xaccTransRetDatePostedTS(trans));
+        {
+             /* Well, this txn doesn't have a GDate saved in a
+              * slot. Avoid getting the date in the local TZ by
+              * converting to UTC before generating the
+              * date. (timespec_to_gdate doesn't do this so don't use
+              * it.
+              */
+             time64 time = xaccTransGetDate(trans);
+             struct tm *stm = gnc_gmtime(&time);
+             g_date_set_dmy(&result, stm->tm_mday,
+                            (GDateMonth)(stm->tm_mon + 1),
+                            stm->tm_year + 1900);
+             free(stm);
+        }
     }
     return result;
 }

commit 1c8c53a8616c9073d129e5a236ceef7c4d5be663
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Dec 12 11:48:11 2017 -0800

    Remove (unused because of an error) parse-to-tm string timespec construction.

diff --git a/libgnucash/backend/sql/gnc-sql-column-table-entry.cpp b/libgnucash/backend/sql/gnc-sql-column-table-entry.cpp
index 3c23a89..a2f7c1a 100644
--- a/libgnucash/backend/sql/gnc-sql-column-table-entry.cpp
+++ b/libgnucash/backend/sql/gnc-sql-column-table-entry.cpp
@@ -395,33 +395,9 @@ GncSqlColumnTableEntryImpl<CT_TIMESPEC>::load (const GncSqlBackend* sql_be,
     {
         try
         {
-            constexpr size_t datelen = 14;
             auto val = row.get_string_at_col(m_col_name);
-            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);
-            }
+            GncDateTime time(val);
+            ts.tv_sec = static_cast<time64>(time);
         }
         catch (std::invalid_argument)
         {

commit 6db08207718304af6bff832f4a607d61d52e514b
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Dec 12 08:42:32 2017 -0800

    Fix offset handling in GncDateTime struct tm ctor, gnc_mktime, & gnc_timegm.
    
    Tests now pass in all TZa from Honolulu to New Zealand.

diff --git a/libgnucash/engine/gnc-date.cpp b/libgnucash/engine/gnc-date.cpp
index e124135..0c7b774 100644
--- a/libgnucash/engine/gnc-date.cpp
+++ b/libgnucash/engine/gnc-date.cpp
@@ -208,7 +208,8 @@ gnc_mktime (struct tm* time)
     {
         normalize_struct_tm (time);
         GncDateTime gncdt(*time);
-        return static_cast<time64>(gncdt) - gncdt.offset();
+        *time = static_cast<struct tm>(gncdt);
+        return static_cast<time64>(gncdt);
     }
     catch(std::invalid_argument)
     {
@@ -222,7 +223,14 @@ gnc_timegm (struct tm* time)
     try
     {
         normalize_struct_tm(time);
-        return static_cast<time64>(GncDateTime(*time));
+        GncDateTime gncdt(*time);
+        *time = static_cast<struct tm>(gncdt);
+        time->tm_sec -= gncdt.offset();
+        normalize_struct_tm(time);
+#ifdef HAVE_STRUcT_TM_GMTOFF
+        time->tm_gmtoff = 0;
+#endif
+        return static_cast<time64>(gncdt) - gncdt.offset();
     }
     catch(std::invalid_argument)
     {
diff --git a/libgnucash/engine/gnc-date.h b/libgnucash/engine/gnc-date.h
index 46ca0c4..7d15b31 100644
--- a/libgnucash/engine/gnc-date.h
+++ b/libgnucash/engine/gnc-date.h
@@ -594,7 +594,6 @@ void gnc_tm_set_day_start (struct tm *tm)
     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
@@ -609,7 +608,6 @@ void gnc_tm_set_day_middle (struct tm *tm)
     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
@@ -624,7 +622,6 @@ void gnc_tm_set_day_end (struct tm *tm)
     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
diff --git a/libgnucash/engine/gnc-datetime.cpp b/libgnucash/engine/gnc-datetime.cpp
index 7a0b98c..e40b898 100644
--- a/libgnucash/engine/gnc-datetime.cpp
+++ b/libgnucash/engine/gnc-datetime.cpp
@@ -29,6 +29,7 @@ extern "C"
 }
 #include <boost/date_time/gregorian/gregorian.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/date_time/local_time/local_time.hpp>
 #include <boost/regex.hpp>
 #include <libintl.h>
 #include <map>
@@ -163,12 +164,23 @@ LDT_from_struct_tm(const struct tm tm)
         auto tdur = boost::posix_time::time_duration(tm.tm_hour, tm.tm_min,
                                                      tm.tm_sec, 0);
         auto tz = tzp.get(tdate.year());
-        return LDT(PTime(tdate, tdur), tz);
+        LDT ldt(tdate, tdur, tz, LDTBase::EXCEPTION_ON_ERROR);
+        if (tm.tm_isdst == -1 && ldt.is_dst())
+            ldt += tz->dst_offset();
+        return ldt;
     }
     catch(boost::gregorian::bad_year)
     {
         throw(std::invalid_argument("Time value is outside the supported year range."));
     }
+    catch(boost::local_time::time_label_invalid)
+    {
+        throw(std::invalid_argument("Struct tm does not resolve to a valid time."));
+    }
+    catch(boost::local_time::ambiguous_result)
+    {
+        throw(std::invalid_argument("Struct tm can resolve to more than one time."));
+    }
 }
 
 class GncDateTimeImpl
diff --git a/libgnucash/engine/test/gtest-gnc-datetime.cpp b/libgnucash/engine/test/gtest-gnc-datetime.cpp
index 936e8be..b77b303 100644
--- a/libgnucash/engine/test/gtest-gnc-datetime.cpp
+++ b/libgnucash/engine/test/gtest-gnc-datetime.cpp
@@ -282,13 +282,15 @@ TEST(gnc_datetime_constructors, test_struct_tm_constructor)
 
     const time64 time = 2394187200; //2045-11-13 12:00:00 Z
     GncDateTime atime(tm);
-    EXPECT_EQ(static_cast<time64>(atime), time);
+    EXPECT_EQ(static_cast<time64>(atime) + atime.offset(), time);
     const struct tm tm1 = static_cast<struct tm>(atime);
     EXPECT_EQ(tm1.tm_year, tm.tm_year);
     EXPECT_EQ(tm1.tm_mon, tm.tm_mon);
+// We have to contort these a bit to handle offsets > 12, e.g. New Zealand during DST.
+//    EXPECT_EQ(tm1.tm_mday - (11 + atime.offset() / 3600) / 24 , tm.tm_mday);
+//    EXPECT_EQ((24 + tm1.tm_hour - atime.offset() / 3600) % 24, tm.tm_hour);
     EXPECT_EQ(tm1.tm_mday, tm.tm_mday);
-// We have to contort this a bit to handle offsets > 12, e.g. New Zealand during DST.
-    EXPECT_EQ((24 + tm1.tm_hour - atime.offset() / 3600) % 24, tm.tm_hour);
+    EXPECT_EQ(tm1.tm_hour, tm.tm_hour);
     EXPECT_EQ(tm1.tm_min, tm.tm_min);
 }
 
@@ -324,8 +326,10 @@ TEST(gnc_datetime_constructors, test_gncdate_neutral_constructor)
 TEST(gnc_datetime_functions, test_format)
 {
     GncDateTime atime(2394187200); //2045-11-13 12:00:00 Z
-    //Date only to finesse timezone issues. It will still fail in +12 DST.
-    EXPECT_EQ(atime.format("%d-%m-%Y"), "13-11-2045");
+    if ((atime.offset() / 3600) > 12)
+        EXPECT_EQ(atime.format("%d-%m-%Y"), "14-11-2045");
+    else
+        EXPECT_EQ(atime.format("%d-%m-%Y"), "13-11-2045");
 }
 
 TEST(gnc_datetime_functions, test_format_zulu)
@@ -343,9 +347,10 @@ TEST(gnc_datetime_functions, test_date)
     auto ymd = gncd.year_month_day();
     EXPECT_EQ(ymd.year, 2045);
     EXPECT_EQ(ymd.month, 11);
-    EXPECT_EQ(ymd.day, 13);
+    EXPECT_EQ(ymd.day - (12 + atime.offset() / 3600) / 24, 13);
 }
-
+/* This test works only in the America/LosAngeles time zone and
+ * there's no way at present to make it more flexible.
 TEST(gnc_datetime_functions, test_timezone_offset)
 {
 
@@ -356,3 +361,4 @@ TEST(gnc_datetime_functions, test_timezone_offset)
     GncDateTime gncdt3(1490525940);  //26 Mar 2017
     EXPECT_EQ(-25200, gncdt3.offset());
 }
+*/
diff --git a/libgnucash/engine/test/test-gnc-date.c b/libgnucash/engine/test/test-gnc-date.c
index 616909f..4b765c8 100644
--- a/libgnucash/engine/test/test-gnc-date.c
+++ b/libgnucash/engine/test/test-gnc-date.c
@@ -268,10 +268,10 @@ test_gnc_mktime (void)
 #endif
     };
     guint ind;
-    int offset = timegm(&time[4]) - mktime(&time[4]);
 
     for (ind = 0; ind < G_N_ELEMENTS (time); ind++)
     {
+        int offset = timegm(&time[ind]) - mktime(&time[ind]);
         time64 secs = gnc_mktime (&time[ind]);
 #if !PLATFORM(WINDOWS)
 	//The timezone database uses local time for some
@@ -319,7 +319,8 @@ test_gnc_mktime_normalization (void)
 #endif
     };
     guint ind;
-    int offset = timegm(&normal_time) - mktime(&normal_time);
+    time_t calc_timegm = timegm(&normal_time);
+    time_t calc_time = mktime(&normal_time);
     for (ind = 0; ind < G_N_ELEMENTS (time); ind++)
     {
         time64 secs = gnc_mktime (&time[ind]);
@@ -330,7 +331,7 @@ test_gnc_mktime_normalization (void)
         g_assert_cmpint (time[ind].tm_mday, ==, normal_time.tm_mday);
         g_assert_cmpint (time[ind].tm_mon, ==, normal_time.tm_mon);
         g_assert_cmpint (time[ind].tm_year, ==, normal_time.tm_year);
-        g_assert_cmpint (secs, ==, ans - offset);
+        g_assert_cmpint (secs, ==, ans - (calc_timegm - calc_time));
     }
 }
 
@@ -705,9 +706,11 @@ 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;
+    const time64 secs = 8 * 3600 + 43 * 60 + 11; /* 1970-01-01 08:43:11 Z */
+    const time64 secs1 = 23 * sec_per_yr + 5 * sec_per_mo +
+        11 * sec_per_day + 8 * 3600 + 43 * 60 + 11; /* 1993-05-11 08:43:60 Z */
+    const time64 secs2 = 21 * sec_per_yr + 11 * sec_per_mo +
+        19 * sec_per_day + 21 * 3600 + 9 * 60 + 48; /* 1991-11-19 21:09:48 Z */
 
     Timespec t0 = { secs, 0 };
     Timespec ta = { secs1, 0 };
@@ -998,9 +1001,9 @@ 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
+    time64 time1 = 154436399; //1974-11-23 10:59:59
+    time64 time2 = -281192401; //1961-02-02 10:59:59
+    time64 time3 = 2381223599LL; //2045-06-16 10:59:59
     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};
@@ -1280,9 +1283,9 @@ 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
+    time64 time1 = 154436399; //1974-11-23 10:59:59
+    time64 time2 = -281192401; //1961-02-02 10:59:59
+    time64 time3 = 2381223599LL; //2045-06-16 10:59:59
     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};
@@ -1812,7 +1815,7 @@ 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;
+    gint loglevel = G_LOG_LEVEL_WARNING | 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);
@@ -1828,13 +1831,14 @@ test_gnc_dmy2timespec (FixtureB *f, gconstpointer pData)
 #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);
+        struct tm time1 = tm, time2 = tm;
+        int offset = gnc_mktime(&time1) - gnc_timegm(&time2);
         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_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs - offset);
     }
     g_log_set_default_handler (hdlr, 0);
 }
@@ -1868,7 +1872,7 @@ test_gnc_dmy2timespec_end (FixtureB *f, gconstpointer pData)
              * 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_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs - offset);
     }
     g_log_set_default_handler (hdlr, 0);
 }



Summary of changes:
 .../backend/sql/gnc-sql-column-table-entry.cpp     | 28 +----------
 libgnucash/engine/Transaction.c                    | 15 +++++-
 libgnucash/engine/gnc-date.cpp                     | 12 ++++-
 libgnucash/engine/gnc-date.h                       |  3 --
 libgnucash/engine/gnc-datetime.cpp                 | 55 ++++++++++++----------
 libgnucash/engine/gnc-datetime.hpp                 |  2 +-
 libgnucash/engine/test/gtest-gnc-datetime.cpp      | 20 +++++---
 libgnucash/engine/test/test-gnc-date.c             | 36 +++++++-------
 8 files changed, 91 insertions(+), 80 deletions(-)



More information about the gnucash-changes mailing list