mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Fix timezone transition times.
This is responsible for test failures on DST transition days. See the comments in gnc-timezone.cpp for an explanation of why this is correct. The rubric was tested on macOS, Arch Linux, Debian Unstable, Fedora 33, and Ubuntu 18.04 to confirm universal applicability.
This commit is contained in:
parent
b6c0a62bbd
commit
3bcf57e7f2
@ -549,10 +549,34 @@ namespace DSTRule
|
||||
std::swap(to_std_time, to_dst_time);
|
||||
std::swap(std_info, dst_info);
|
||||
}
|
||||
if (dst_info->isgmt)
|
||||
to_dst_time += boost::posix_time::seconds(dst_info->info.gmtoff);
|
||||
if (std_info->isgmt)
|
||||
to_std_time += boost::posix_time::seconds(std_info->info.gmtoff);
|
||||
|
||||
/* Documentation notwithstanding, the date-time rules are
|
||||
* looking for local time (wall clock to use the RFC 8538
|
||||
* definition) values.
|
||||
*
|
||||
* The TZ Info contains two fields, isstd and isgmt (renamed
|
||||
* to isut in newer versions of tzinfo). In theory if both are
|
||||
* 0 the transition times represent wall-clock times,
|
||||
* i.e. time stamps in the respective time zone's local time
|
||||
* at the moment of the transition. If isstd is 1 then the
|
||||
* representation is always in standard time instead of
|
||||
* daylight time; this is significant for dst->std
|
||||
* transitions. If isgmt/isut is one then isstd must also be
|
||||
* set and the transition time is in UTC.
|
||||
*
|
||||
* In practice it seems that the timestamps are always in UTC
|
||||
* so the isgmt/isut flag isn't meaningful. The times always
|
||||
* need to have the utc offset added to them to make the
|
||||
* transition occur at the right time; the isstd flag
|
||||
* determines whether that should be the standard offset or
|
||||
* the daylight offset for the daylight->standard transition.
|
||||
*/
|
||||
|
||||
to_dst_time += boost::posix_time::seconds(std_info->info.gmtoff);
|
||||
if (std_info->isstd) //if isstd always use standard time
|
||||
to_std_time += boost::posix_time::seconds(std_info->info.gmtoff);
|
||||
else
|
||||
to_std_time += boost::posix_time::seconds(dst_info->info.gmtoff);
|
||||
|
||||
}
|
||||
|
||||
|
@ -381,6 +381,57 @@ TEST(gnc_datetime_constructors, test_gncdate_end_constructor)
|
||||
EXPECT_EQ(atime.format("%d-%m-%Y %H:%M:%S"), "06-11-2046 23:59:59");
|
||||
}
|
||||
|
||||
static ::testing::AssertionResult
|
||||
test_offset(time64 start_time, int hour, int offset1, int offset2,
|
||||
const char* zone)
|
||||
{
|
||||
GncDateTime gdt{start_time + hour * 3600};
|
||||
if ((hour < 2 && gdt.offset() == offset1) ||
|
||||
(hour >= 2 && gdt.offset() == offset2))
|
||||
return ::testing::AssertionSuccess();
|
||||
else
|
||||
return ::testing::AssertionFailure() << zone << ": " << gdt.format("%D %T %z %q") << " hour " << hour;
|
||||
}
|
||||
|
||||
TEST(gnc_datetime_constructors, test_DST_start_transition_time)
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
TimeZoneProvider tzp_can{"A.U.S Eastern Standard Time"};
|
||||
TimeZoneProvider tzp_la{"Pacific Standard Time"};
|
||||
#else
|
||||
TimeZoneProvider tzp_can("Australia/Canberra");
|
||||
TimeZoneProvider tzp_la("America/Los_Angeles");
|
||||
#endif
|
||||
_set_tzp(tzp_la);
|
||||
for (auto hours = 0; hours < 23; ++hours)
|
||||
EXPECT_TRUE(test_offset(1583657940, hours, -28800, -25200, "Los Angeles"));
|
||||
|
||||
_reset_tzp();
|
||||
_set_tzp(tzp_can);
|
||||
for (auto hours = 0; hours < 23; ++hours)
|
||||
EXPECT_TRUE(test_offset(1601737140, hours, 36000, 39600, "Canberra"));
|
||||
_reset_tzp();
|
||||
}
|
||||
|
||||
TEST(gnc_datetime_constructors, test_DST_end_transition_time)
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
TimeZoneProvider tzp_can{"A.U.S Eastern Standard Time"};
|
||||
TimeZoneProvider tzp_la{"Pacific Standard Time"};
|
||||
#else
|
||||
TimeZoneProvider tzp_can("Australia/Canberra");
|
||||
TimeZoneProvider tzp_la("America/Los_Angeles");
|
||||
#endif
|
||||
_set_tzp(tzp_la);
|
||||
for (auto hours = 0; hours < 23; ++hours)
|
||||
EXPECT_TRUE(test_offset(1604217540, hours, -25200, -28800, "Los Angeles"));
|
||||
_reset_tzp();
|
||||
_set_tzp(tzp_can);
|
||||
for (auto hours = 0; hours < 23; ++hours)
|
||||
EXPECT_TRUE(test_offset(1586008740, hours, 39600, 36000, "Canberra"));
|
||||
_reset_tzp();
|
||||
}
|
||||
|
||||
TEST(gnc_datetime_constructors, test_gncdate_neutral_constructor)
|
||||
{
|
||||
const ymd aymd = { 2017, 04, 20 };
|
||||
|
Loading…
Reference in New Issue
Block a user