gnucash master: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Tue Sep 27 09:19:39 EDT 2016


Updated	 via  https://github.com/Gnucash/gnucash/commit/ba002bbe (commit)
	 via  https://github.com/Gnucash/gnucash/commit/fd370518 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/a7ca2057 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/158b17d5 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/0dd672c6 (commit)
	from  https://github.com/Gnucash/gnucash/commit/081d6ec0 (commit)



commit ba002bbec4c1580502358881dbaeb49a199aac2b
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Sep 27 15:19:08 2016 +0200

    Fix test failure when in Spain.
    
    It turns out that some timezones use local time for pre-1900 dates in
    the 32bit timezone file, too.

diff --git a/src/libqof/qof/test/test-gnc-date.c b/src/libqof/qof/test/test-gnc-date.c
index a3dfc21..dc22b76 100644
--- a/src/libqof/qof/test/test-gnc-date.c
+++ b/src/libqof/qof/test/test-gnc-date.c
@@ -261,10 +261,10 @@ test_gnc_mktime (void)
     {
         time64 secs = gnc_mktime (&time[ind]);
 #if !PLATFORM(WINDOWS)
-	//The 64-bit timezone database uses local time for some
+	//The timezone database uses local time for some
 	//timezones before 1900, which screws up the offset.
-	if (time[ind].tm_year < 0 && sizeof(time_t) == sizeof(int64_t))
-	     continue;
+	if (time[ind].tm_year < 0)
+            continue;
 #endif
         g_assert_cmpint (secs, ==, ans[ind] - offset);
 

commit fd3705186524f2600654cd20d372073906f92d1f
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Sep 27 15:17:39 2016 +0200

    gnc-timezone: Enable POSIX-style timezone strings on Unix systems.
    
    E.g. CEST01CEDT,M4.1.0,M10.1.0.
    
    Also reorder priority of finding TZ information: Passed-in timezone string
    is tried first; if that's empty or fails, try the TZ variable, then
    /etc/localtime, and finally give up and use UTC. Exceptions never leave
    GncTimeZoneProvider and *some* timezone is always returned.
    
    Provide a new test for posix timezones and invert the exception test.

diff --git a/src/libqof/qof/gnc-timezone.cpp b/src/libqof/qof/gnc-timezone.cpp
index bd52498..d6b8c89 100644
--- a/src/libqof/qof/gnc-timezone.cpp
+++ b/src/libqof/qof/gnc-timezone.cpp
@@ -377,15 +377,6 @@ namespace IANAParser
 	    }
 	}
 
-        if (!ifs.is_open())
-        {
-            if (!tzname.empty())
-                std::cerr << "Failed to open time zone " << tzname <<
-                    "; No such file. Falling back on system default timezone.\n";
-            ifs.open("/etc/localtime",
-                     std::ios::in|std::ios::binary|std::ios::ate);
-        }
-
 	if (! ifs.is_open())
 	    throw std::invalid_argument("The timezone string failed to resolve to a valid filename");
 	std::streampos filesize = ifs.tellg();
@@ -609,7 +600,8 @@ zone_from_rule(int year, DSTRule::DSTRule rule)
     return std::make_pair(year, tz);
 }
 
-TimeZoneProvider::TimeZoneProvider(const std::string& tzname) :  zone_vector {}
+void
+TimeZoneProvider::parse_file(const std::string& tzname)
 {
     IANAParser::IANAParser parser(tzname);
     auto last_info = std::find_if(parser.tzinfo.begin(), parser.tzinfo.end(),
@@ -675,6 +667,34 @@ TimeZoneProvider::TimeZoneProvider(const std::string& tzname) :  zone_vector {}
         zone_vector.push_back(zone_from_rule(max_year, last_rule));
 }
 
+TimeZoneProvider::TimeZoneProvider(const std::string& tzname) :  zone_vector {}
+{
+    try
+    {
+        parse_file(tzname);
+    }
+    catch(const std::invalid_argument& err)
+    {
+        try
+        {
+            TZ_Ptr zone(new PTZ(tzname));
+            zone_vector.push_back(std::make_pair(max_year, zone));
+        }
+        catch(const std::exception& err)
+        {
+            std::cerr << "Unable to use either provided tzname or TZ environment variable. Resorting to /etc/localtime.\n";
+            try
+            {
+                parse_file("/etc/localtime");
+            }
+            catch(const std::invalid_argument& env)
+            {
+                std::cerr << "/etc/localtime invalid, resorting to GMT.";
+                TZ_Ptr zone(new PTZ("UTC0"));
+                zone_vector.push_back(std::make_pair(max_year, zone));
+            }
+        }
+    }
 }
 #endif
 
diff --git a/src/libqof/qof/gnc-timezone.hpp b/src/libqof/qof/gnc-timezone.hpp
index efbfc65..546bbf3 100644
--- a/src/libqof/qof/gnc-timezone.hpp
+++ b/src/libqof/qof/gnc-timezone.hpp
@@ -58,6 +58,7 @@ public:
     static const unsigned int min_year; //1400
     static const unsigned int max_year; //9999
 private:
+    void parse_file(const std::string& tzname);
     TZ_Vector zone_vector;
 #if PLATFORM(WINDOWS)
     void load_windows_dynamic_tz(HKEY, time_zone_names);
diff --git a/src/libqof/qof/test/gtest-gnc-timezone.cpp b/src/libqof/qof/test/gtest-gnc-timezone.cpp
index b20f11a..b7e4f51 100644
--- a/src/libqof/qof/test/gtest-gnc-timezone.cpp
+++ b/src/libqof/qof/test/gtest-gnc-timezone.cpp
@@ -57,8 +57,23 @@ TEST(gnc_timezone_constructors, test_pacific_time_constructor)
     EXPECT_TRUE(tz->base_utc_offset().hours() == -8);
 }
 
+#if !PLATFORM(WINDOWS)
+TEST(gnc_timezone_constructors, test_posix_timezone)
+{
+    std::string timezone("FST08FDT07,M4.1.0,M10.31.0");
+    TimeZoneProvider tzp(timezone);
+    TZ_Ptr tz = tzp.get(2006);
+    EXPECT_TRUE(tz->std_zone_abbrev() == "FST");
+    EXPECT_TRUE(tz->dst_zone_abbrev() == "FDT");
+    EXPECT_TRUE(tz->base_utc_offset().hours() == 8L);
+    EXPECT_TRUE(tz->dst_offset().hours() == 7L);
+}
+#endif
+
 TEST(gnc_timezone_constructors, test_bogus_time_constructor)
 {
-    EXPECT_THROW (TimeZoneProvider tzp ("New York Standard Time"),
-		  std::invalid_argument);
+    TimeZoneProvider tzp ("New York Standard Time");
+    TimeZoneProvider machine ("");
+    EXPECT_TRUE(machine.get(2006)->std_zone_abbrev() ==
+                tzp.get(2006)->std_zone_abbrev());
 }

commit a7ca20572d6e42573d47536b40ca40c62bcec6a6
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Sep 27 15:11:06 2016 +0200

    Fix whitespace in function about to be extracted.

diff --git a/src/libqof/qof/gnc-timezone.cpp b/src/libqof/qof/gnc-timezone.cpp
index 710eebd..bd52498 100644
--- a/src/libqof/qof/gnc-timezone.cpp
+++ b/src/libqof/qof/gnc-timezone.cpp
@@ -613,66 +613,68 @@ TimeZoneProvider::TimeZoneProvider(const std::string& tzname) :  zone_vector {}
 {
     IANAParser::IANAParser parser(tzname);
     auto last_info = std::find_if(parser.tzinfo.begin(), parser.tzinfo.end(),
-				  [](IANAParser::TZInfo tz)
-				  {return !tz.info.isdst;});
+                                  [](IANAParser::TZInfo tz)
+                                  {return !tz.info.isdst;});
     auto last_time = ptime();
     DSTRule::DSTRule last_rule;
     using boost::gregorian::date;
     using boost::posix_time::ptime;
     using boost::posix_time::time_duration;
     for (auto txi = parser.transitions.begin();
-	 txi != parser.transitions.end(); ++txi)
+         txi != parser.transitions.end(); ++txi)
     {
-	auto this_info = parser.tzinfo.begin() + txi->index;
+        auto this_info = parser.tzinfo.begin() + txi->index;
 //Can't use boost::posix_date::from_time_t() constructor because it
 //silently casts the time_t to an int32_t.
-	auto this_time = ptime(date(1970, 1, 1),
-			       time_duration(txi->timestamp / 3600, 0,
-					     txi->timestamp % 3600));
-	try
-	{
-	    auto this_year = this_time.date().year();
-	    //Initial case
-	    if (last_time.is_not_a_date_time())
-		zone_vector.push_back(zone_no_dst(this_year - 1, last_info));
-	    //gap in transitions > 1 year, non-dst zone
-	    //change. In the last case the exact date of the change will be
-	    //wrong because boost::local_date::timezone isn't able to
-	    //represent it. For GnuCash's purposes this isn't likely to be
-	    //important as the last time this sort of transition happened
-	    //was 1946, but we have to handle the case in order to parse
-	    //the tz file.
-	    else if (this_year - last_time.date().year() > 1 ||
-		     last_info->info.isdst == this_info->info.isdst)
-	    {
-		zone_vector.push_back(zone_no_dst(this_year, last_info));
-	    }
-
-	    else
-	    {
-		DSTRule::DSTRule new_rule(last_info, this_info,
-					  last_time, this_time);
-		if (new_rule != last_rule)
-		{
-		    last_rule = new_rule;
-		    zone_vector.push_back(zone_from_rule (this_time.date().year(),
-							  new_rule));
-		}
-	    }
-	}
-	catch(boost::gregorian::bad_year err)
-	{
-	    continue;
-	}
-	last_time = this_time;
-	last_info = this_info;
+        auto this_time = ptime(date(1970, 1, 1),
+                               time_duration(txi->timestamp / 3600, 0,
+                                             txi->timestamp % 3600));
+        try
+        {
+            auto this_year = this_time.date().year();
+            //Initial case
+            if (last_time.is_not_a_date_time())
+                zone_vector.push_back(zone_no_dst(this_year - 1, last_info));
+            //gap in transitions > 1 year, non-dst zone
+            //change. In the last case the exact date of the change will be
+            //wrong because boost::local_date::timezone isn't able to
+            //represent it. For GnuCash's purposes this isn't likely to be
+            //important as the last time this sort of transition happened
+            //was 1946, but we have to handle the case in order to parse
+            //the tz file.
+            else if (this_year - last_time.date().year() > 1 ||
+                     last_info->info.isdst == this_info->info.isdst)
+            {
+                zone_vector.push_back(zone_no_dst(this_year, last_info));
+            }
+
+            else
+            {
+                DSTRule::DSTRule new_rule(last_info, this_info,
+                                          last_time, this_time);
+                if (new_rule != last_rule)
+                {
+                    last_rule = new_rule;
+                    zone_vector.push_back(zone_from_rule (this_time.date().year(),
+                                                          new_rule));
+                }
+            }
+        }
+        catch(const boost::gregorian::bad_year& err)
+        {
+            continue;
+        }
+        last_time = this_time;
+        last_info = this_info;
     }
 
     if (last_time.is_not_a_date_time() ||
-	last_time.date().year() < parser.last_year)
-	zone_vector.push_back(zone_no_dst(max_year, last_info));
+        last_time.date().year() < parser.last_year)
+        zone_vector.push_back(zone_no_dst(max_year, last_info));
     else //Last DST rule forever after.
-	zone_vector.push_back(zone_from_rule(max_year, last_rule));
+        zone_vector.push_back(zone_from_rule(max_year, last_rule));
+}
+
 }
 #endif
 

commit 158b17d582e4a3667d448a2dc8caa8a5926544ae
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Sep 27 15:06:56 2016 +0200

    gnu-timezone: Alias boost::local_time::posix_time_zone.

diff --git a/src/libqof/qof/gnc-timezone.cpp b/src/libqof/qof/gnc-timezone.cpp
index 1f745cc..710eebd 100644
--- a/src/libqof/qof/gnc-timezone.cpp
+++ b/src/libqof/qof/gnc-timezone.cpp
@@ -44,6 +44,7 @@ using duration = boost::posix_time::time_duration;
 using time_zone = boost::local_time::custom_time_zone;
 using dst_offsets = boost::local_time::dst_adjustment_offsets;
 using calc_rule_ptr = boost::local_time::dst_calc_rule_ptr;
+using PTZ = boost::local_time::posix_time_zone;
 
 const unsigned int TimeZoneProvider::min_year = 1400;
 const unsigned int TimeZoneProvider::max_year = 9999;
@@ -688,7 +689,7 @@ TimeZoneProvider::get(int year) const noexcept
              year);
         if (!zone_vector.empty())
             return zone_vector.back().second;
-        return TZ_Ptr(new boost::local_time::posix_time_zone("UTC0"));
+        return TZ_Ptr(new PTZ("UTC0"));
     }
     return iter->second;
 }

commit 0dd672c622938b9d9ec9299f0e5d45af13e02042
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Sep 26 18:29:19 2016 +0200

    Handle TZ that's not a file name by opening /etc/localtime.

diff --git a/src/libqof/qof/gnc-timezone.cpp b/src/libqof/qof/gnc-timezone.cpp
index 46a7ca9..1f745cc 100644
--- a/src/libqof/qof/gnc-timezone.cpp
+++ b/src/libqof/qof/gnc-timezone.cpp
@@ -356,13 +356,8 @@ namespace IANAParser
             if (auto tzenv = getenv("TZ"))
                 tzname = std::string(std::getenv("TZ"));
         //std::cout << "Testing tzname " << tzname << "\n";
-	if (tzname.empty())
-	{
-	    ifs.open("/etc/localtime",
-		     std::ios::in|std::ios::binary|std::ios::ate);
-	}
-	else
-	{
+        if (!tzname.empty())
+        {
 //POSIX specifies that that identifier should begin with ':', but we
 //should be liberal. If it's there, it's not part of the filename.
 	    if (tzname[0] == ':')
@@ -380,6 +375,16 @@ namespace IANAParser
 			 std::ios::in|std::ios::binary|std::ios::ate);
 	    }
 	}
+
+        if (!ifs.is_open())
+        {
+            if (!tzname.empty())
+                std::cerr << "Failed to open time zone " << tzname <<
+                    "; No such file. Falling back on system default timezone.\n";
+            ifs.open("/etc/localtime",
+                     std::ios::in|std::ios::binary|std::ios::ate);
+        }
+
 	if (! ifs.is_open())
 	    throw std::invalid_argument("The timezone string failed to resolve to a valid filename");
 	std::streampos filesize = ifs.tellg();



Summary of changes:
 src/libqof/qof/gnc-timezone.cpp            | 140 +++++++++++++++++------------
 src/libqof/qof/gnc-timezone.hpp            |   1 +
 src/libqof/qof/test/gtest-gnc-timezone.cpp |  19 +++-
 src/libqof/qof/test/test-gnc-date.c        |   6 +-
 4 files changed, 105 insertions(+), 61 deletions(-)



More information about the gnucash-changes mailing list