gnucash unstable: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Tue Jan 9 20:34:07 EST 2018


Updated	 via  https://github.com/Gnucash/gnucash/commit/ebbcd30f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/fcf88262 (commit)
	from  https://github.com/Gnucash/gnucash/commit/e798df07 (commit)



commit ebbcd30f398e589abbaf1efbeb99d74cb04ba951
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Jan 9 14:58:43 2018 -0800

    Save Changes Bug 792106 - Wrong dates displayed
    
    The first attempt to fix this, a17bc85a, doesn't work because the
    boost::date_time constructor gets enough information in most cases to
    generate a date, just not the one we expect. This change looks for '-' in
    the fourth position and if it's there assumes iso-extended format, otherwise
    it assumes delimiter-less ISO without the 'T', i.e. %Y%m%d%H%M%S.

diff --git a/libgnucash/engine/gnc-datetime.cpp b/libgnucash/engine/gnc-datetime.cpp
index 795ae5c..2ddc9dd 100644
--- a/libgnucash/engine/gnc-datetime.cpp
+++ b/libgnucash/engine/gnc-datetime.cpp
@@ -294,16 +294,12 @@ GncDateTimeImpl::GncDateTimeImpl(const std::string str) :
         auto input_facet(new Facet());
         std::istringstream ss(str.substr(0, tzpos));
         ss.imbue(std::locale(std::locale(), input_facet));
-        input_facet->set_iso_extended_format();
+        if (str.find("-") == 4)
+            input_facet->set_iso_extended_format();
+        else /* Not in iso format, try squashed format. */
+            input_facet->format("%Y%m%d%H%M%S");
         PTime pdt(not_a_date_time);
         ss >> pdt;
-        if (pdt.is_special())
-        {
-            input_facet->format("%Y%m%d%H%M%S");
-            ss.clear(); //Reset to the beginning.
-            ss.seekg(0);
-            ss >> pdt;
-        }
         m_time = LDT(pdt.date(), pdt.time_of_day(), tzptr,
                          LDTBase::NOT_DATE_TIME_ON_ERROR);
     }
@@ -450,7 +446,7 @@ GncDateTime::GncDateTime(const time64 time) :
     m_impl(new GncDateTimeImpl(time)) {}
 GncDateTime::GncDateTime(const struct tm tm) :
     m_impl(new GncDateTimeImpl(tm)) {}
-GncDateTime::GncDateTime(const std::string str, std::string fmt) :
+GncDateTime::GncDateTime(const std::string str) :
     m_impl(new GncDateTimeImpl(str)) {}
 GncDateTime::~GncDateTime() = default;
 
diff --git a/libgnucash/engine/test/gtest-gnc-datetime.cpp b/libgnucash/engine/test/gtest-gnc-datetime.cpp
index 245562b..65989bf 100644
--- a/libgnucash/engine/test/gtest-gnc-datetime.cpp
+++ b/libgnucash/engine/test/gtest-gnc-datetime.cpp
@@ -293,6 +293,16 @@ TEST(gnc_datetime_constructors, test_string_constructor)
     EXPECT_EQ(tm.tm_hour, 15);
     EXPECT_EQ(tm.tm_min, 8);
     EXPECT_EQ(tm.tm_sec, 19);
+/* Squashed format from SQLite3 databases */
+    timestr = "20151205115703";
+    GncDateTime time4(timestr);
+    tm = time4.utc_tm();
+    EXPECT_EQ(tm.tm_year, 115);
+    EXPECT_EQ(tm.tm_mon, 11);
+    EXPECT_EQ(tm.tm_mday, 5);
+    EXPECT_EQ(tm.tm_hour,11);
+    EXPECT_EQ(tm.tm_min, 57);
+    EXPECT_EQ(tm.tm_sec, 3);
 }
 
 TEST(gnc_datetime_constructors, test_struct_tm_constructor)

commit fcf88262ca036439c711d91d2a8e7bf892f49b21
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Jan 9 13:58:25 2018 -0800

    Extract function tz_from_string.
    
    Also changes from calculating the Bug 767824 offset to using
    boost::date_time::local_time_in() and provides unit tests.

diff --git a/libgnucash/engine/gnc-datetime.cpp b/libgnucash/engine/gnc-datetime.cpp
index 2bec648..795ae5c 100644
--- a/libgnucash/engine/gnc-datetime.cpp
+++ b/libgnucash/engine/gnc-datetime.cpp
@@ -262,48 +262,31 @@ GncDateTimeImpl::GncDateTimeImpl(const GncDateImpl& date, DayPart part) :
     }
 }
 
+using PTZ = boost::local_time::posix_time_zone;
+
+static TZ_Ptr
+tz_from_string(std::string str)
+{
+    if (str.empty()) return utc_zone;
+    std::string tzstr = "XXX" + str;
+    if (tzstr.length() > 6 && tzstr[6] != ':') //6 for XXXsHH, s is + or -
+        tzstr.insert(6, ":");
+    if (tzstr.length() > 9 && tzstr[9] != ':') //9 for XXXsHH:MM
+    {
+        tzstr.insert(9, ":");
+    }
+    return TZ_Ptr(new PTZ(tzstr));
+}
+
 GncDateTimeImpl::GncDateTimeImpl(const std::string str) :
     m_time(unix_epoch, utc_zone)
 {
     if (str.empty()) return;
 
-    using std::string;
-    using PTZ = boost::local_time::posix_time_zone;
-    TZ_Ptr tzptr;
     auto tzpos = str.find_first_of("+-", str.find(":"));
-    int offset = 0L;
-    if (tzpos != str.npos)
-    {
-        string tzstr = "XXX" + str.substr(tzpos);
-        if (tzstr.length() > 6 && tzstr[6] != ':') //6 for XXXsHH, s is + or -
-            tzstr.insert(6, ":");
-        if (tzstr.length() > 9 && tzstr[9] != ':') //9 for XXXsHH:MM
-        {
-            tzstr.insert(9, ":");
-        /* Bug 767824: A GLib bug in parsing the UTC timezone on
-         * Windows may have created a bogus timezone of a random
-         * number of minutes. Since there are no fractional-hour
-         * timezones around the prime meridian we can safely check for
-         * this in files by looking for minutes-only offsets and
-         * making the appropriate correction.
-         */
-            if (tzstr.compare(7,8, "00") &&
-                (tzstr.length() > 10 ? tzstr[10] != '0' :
-                 !tzstr.compare(10, 11, "00")))
-            {
-                offset = atoi(tzstr.substr(10,11).c_str());
-                if (offset && tzpos == '-')
-                    offset = -offset;
-                tzstr.replace(10, 11, "00");
-            }
-        }
-        tzptr.reset(new PTZ(tzstr));
-        if (str[tzpos - 1] == ' ') --tzpos;
-    }
-    else
-    {
-        tzptr = utc_zone;
-    }
+    auto tzptr = tz_from_string(tzpos != str.npos ? str.substr(tzpos) : "");
+    if (tzpos != str.npos && str[tzpos - 1] == ' ') --tzpos;
+
     try
     {
         using Facet = boost::posix_time::time_input_facet;
@@ -328,8 +311,15 @@ GncDateTimeImpl::GncDateTimeImpl(const std::string str) :
     {
         throw(std::invalid_argument("The date string was outside of the supported year range."));
     }
-    if (offset)
-        m_time -= boost::posix_time::minutes(offset);
+    /* Bug 767824: A GLib bug in parsing the UTC timezone on Windows may have
+     * created a bogus timezone of a random number of minutes. Since there are
+     * no fractional-hour timezones around the prime meridian we can safely
+     * check for this in files by resetting to UTC if there's a
+     * less-than-an-hour offset.
+     */
+    auto offset = tzptr->base_utc_offset().seconds();
+    if (offset != 0 && std::abs(offset) < 3600)
+        m_time = m_time.local_time_in(utc_zone);
 }
 
 GncDateTimeImpl::operator time64() const
@@ -460,7 +450,7 @@ GncDateTime::GncDateTime(const time64 time) :
     m_impl(new GncDateTimeImpl(time)) {}
 GncDateTime::GncDateTime(const struct tm tm) :
     m_impl(new GncDateTimeImpl(tm)) {}
-GncDateTime::GncDateTime(const std::string str) :
+GncDateTime::GncDateTime(const std::string str, std::string fmt) :
     m_impl(new GncDateTimeImpl(str)) {}
 GncDateTime::~GncDateTime() = default;
 
diff --git a/libgnucash/engine/test/gtest-gnc-datetime.cpp b/libgnucash/engine/test/gtest-gnc-datetime.cpp
index 350d22a..245562b 100644
--- a/libgnucash/engine/test/gtest-gnc-datetime.cpp
+++ b/libgnucash/engine/test/gtest-gnc-datetime.cpp
@@ -261,15 +261,38 @@ TEST(gnc_datetime_constructors, test_time64_constructor)
 
 TEST(gnc_datetime_constructors, test_string_constructor)
 {
-    std::string timestr("2015-12-05 00:01:00");
-    GncDateTime time(timestr);
-    auto tm = time.utc_tm();
+/* Plain UTC date-time */
+    std::string timestr("2015-12-05 11:57:03");
+    GncDateTime time1(timestr);
+    auto tm = time1.utc_tm();
     EXPECT_EQ(tm.tm_year, 115);
     EXPECT_EQ(tm.tm_mon, 11);
     EXPECT_EQ(tm.tm_mday, 5);
-    EXPECT_EQ(tm.tm_hour, 0);
-    EXPECT_EQ(tm.tm_min, 1);
-    EXPECT_EQ(tm.tm_sec, 0);
+    EXPECT_EQ(tm.tm_hour,11);
+    EXPECT_EQ(tm.tm_min, 57);
+    EXPECT_EQ(tm.tm_sec, 3);
+
+/* Datetime with an offset */
+    timestr = "1993-07-22 15:21:19 +0300";
+    GncDateTime time2(timestr);
+    tm = time2.utc_tm();
+    EXPECT_EQ(tm.tm_year, 93);
+    EXPECT_EQ(tm.tm_mon, 6);
+    EXPECT_EQ(tm.tm_mday, 22);
+    EXPECT_EQ(tm.tm_hour, 12);
+    EXPECT_EQ(tm.tm_min, 21);
+    EXPECT_EQ(tm.tm_sec, 19);
+
+/* Bug 767824 date-time */
+    timestr = "1993-07-22 15:21:19 +0013";
+    GncDateTime time3(timestr);
+    tm = time3.utc_tm();
+    EXPECT_EQ(tm.tm_year, 93);
+    EXPECT_EQ(tm.tm_mon, 6);
+    EXPECT_EQ(tm.tm_mday, 22);
+    EXPECT_EQ(tm.tm_hour, 15);
+    EXPECT_EQ(tm.tm_min, 8);
+    EXPECT_EQ(tm.tm_sec, 19);
 }
 
 TEST(gnc_datetime_constructors, test_struct_tm_constructor)



Summary of changes:
 libgnucash/engine/gnc-datetime.cpp            | 78 +++++++++++----------------
 libgnucash/engine/test/gtest-gnc-datetime.cpp | 45 +++++++++++++---
 2 files changed, 71 insertions(+), 52 deletions(-)



More information about the gnucash-changes mailing list