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