mirror of
https://github.com/Gnucash/gnucash.git
synced 2024-11-26 02:40:43 -06:00
Fix offset handling in GncDateTime struct tm ctor, gnc_mktime, & gnc_timegm.
Tests now pass in all TZa from Honolulu to New Zealand.
This commit is contained in:
parent
de4d1e9859
commit
6db0820771
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user