Unit tests passing

This commit is contained in:
Alexey Milovidov 2021-03-07 04:10:38 +03:00
parent 8271cec093
commit 1bb62f578b
3 changed files with 42 additions and 45 deletions

View File

@ -59,7 +59,7 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
offset_at_start_of_epoch = cctz_time_zone.lookup(cctz_time_zone.lookup(epoch).pre).offset;
offset_at_start_of_lut = cctz_time_zone.lookup(cctz_time_zone.lookup(lut_start).pre).offset;
offset_is_whole_number_of_hours_everytime = true;
offset_is_whole_number_of_hours_during_epoch = true;
cctz::civil_day date = lut_start;
@ -105,8 +105,8 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
values.time_at_offset_change_value = 0;
values.amount_of_offset_change_value = 0;
if (offset_is_whole_number_of_hours_everytime && start_of_day > 0 && start_of_day % 3600)
offset_is_whole_number_of_hours_everytime = false;
if (offset_is_whole_number_of_hours_during_epoch && start_of_day > 0 && start_of_day % 3600)
offset_is_whole_number_of_hours_during_epoch = false;
/// If UTC offset was changed this day.
/// Change in time zone without transition is possible, e.g. Moscow 1991 Sun, 31 Mar, 02:00 MSK to EEST

View File

@ -185,7 +185,7 @@ private:
time_t offset_at_start_of_epoch;
/// UTC offset at the beginning of the first supported year.
time_t offset_at_start_of_lut;
bool offset_is_whole_number_of_hours_everytime;
bool offset_is_whole_number_of_hours_during_epoch;
/// Time zone name.
std::string time_zone;
@ -193,15 +193,19 @@ private:
inline LUTIndex findIndex(time_t t) const
{
/// First guess.
const UInt32 guess = ((t / 86400) + daynum_offset_epoch) & date_lut_mask;
UInt32 guess = ((t / 86400) + daynum_offset_epoch) & date_lut_mask;
/// For negative time_t the integer division was rounded up, so the guess is offset by one.
if (unlikely(t < 0))
--guess;
/// UTC offset is from -12 to +14 in all known time zones. This requires checking only three indices.
if (t >= lut[guess].date && t < lut[UInt32(guess + 1)].date)
if (t >= lut[guess].date && t < lut[guess + 1].date)
return LUTIndex(guess);
/// Time zones that have offset 0 from UTC do daylight saving time change (if any)
/// towards increasing UTC offset (example: British Standard Time).
if (t >= lut[UInt32(guess + 1)].date)
if (t >= lut[guess + 1].date)
return LUTIndex(guess + 1);
return LUTIndex(guess - 1);
@ -253,7 +257,6 @@ public:
// Methods only for unit-testing, it makes very little sense to use it from user code.
auto getOffsetAtStartOfEpoch() const { return offset_at_start_of_epoch; }
auto getOffsetIsWholNumberOfHoursEveryWhere() const { return offset_is_whole_number_of_hours_everytime; }
auto getTimeOffsetAtStartOfLUT() const { return offset_at_start_of_lut; }
/// All functions below are thread-safe; arguments are not checked.
@ -456,8 +459,8 @@ public:
inline unsigned toMinute(time_t t) const
{
if (offset_is_whole_number_of_hours_everytime)
return ((t + DATE_LUT_ADD) / 60) % 60;
if (t >= 0 && offset_is_whole_number_of_hours_during_epoch)
return (t / 60) % 60;
/// To consider the DST changing situation within this day
/// also make the special timezones with no whole hour offset such as 'Australia/Lord_Howe' been taken into account.
@ -478,8 +481,8 @@ public:
inline time_t toStartOfTenMinutes(time_t t) const
{
if (offset_is_whole_number_of_hours_everytime)
return roundDown(t, 600);
if (t >= 0 && offset_is_whole_number_of_hours_during_epoch)
return t / 600 * 600;
/// More complex logic is for Nepal - it has offset 05:45. Australia/Eucla is also unfortunate.
Int64 date = find(t).date;
@ -489,8 +492,8 @@ public:
/// NOTE: Assuming timezone transitions are multiple of hours. Lord Howe Island in Australia is a notable exception.
inline time_t toStartOfHour(time_t t) const
{
if (offset_is_whole_number_of_hours_everytime)
return roundDown(t, 3600);
if (t >= 0 && offset_is_whole_number_of_hours_during_epoch)
return t / 3600 * 3600;
Int64 date = find(t).date;
return date + (t - date) / 3600 * 3600;
@ -773,8 +776,8 @@ public:
/// We count all hour-length intervals, unrelated to offset changes.
inline time_t toRelativeHourNum(time_t t) const
{
if (offset_is_whole_number_of_hours_everytime)
return (t + DATE_LUT_ADD) / 3600 - (DATE_LUT_ADD / 3600);
if (t >= 0 && offset_is_whole_number_of_hours_during_epoch)
return t / 3600;
/// Assume that if offset was fractional, then the fraction is the same as at the beginning of epoch.
/// NOTE This assumption is false for "Pacific/Pitcairn" and "Pacific/Kiritimati" time zones.
@ -848,7 +851,7 @@ public:
t = roundDown(t, seconds);
if (offset_is_whole_number_of_hours_everytime)
if (t >= 0 && offset_is_whole_number_of_hours_during_epoch)
return t;
/// TODO check if it's correct.

View File

@ -297,7 +297,6 @@ TEST_P(DateLUTWithTimeZone, VaidateTimeComponentsAroundEpoch)
<< "\n\tTimezone: " << timezone_name
<< "\n\ttimestamp: " << i
<< "\n\t offset at start of epoch : " << lut.getOffsetAtStartOfEpoch()
<< "\n\t offset_is_whole_number_of_hours_everytime : " << lut.getOffsetIsWholNumberOfHoursEveryWhere()
<< "\n\t offset_at_start_of_lut : " << lut.getTimeOffsetAtStartOfLUT());
EXPECT_GE(24, lut.toHour(i));
@ -336,7 +335,7 @@ INSTANTIATE_TEST_SUITE_P(ExoticTimezones,
})
);
INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimeZones,
INSTANTIATE_TEST_SUITE_P(AllTimeZones,
DateLUTWithTimeZone,
::testing::ValuesIn(allTimezones())
);
@ -391,11 +390,15 @@ TEST_P(DateLUTWithTimeZoneAndTimeRange, InRange)
{
SCOPED_TRACE(expected_time_t);
const auto tz_time = cctz::convert(std::chrono::system_clock::from_time_t(expected_time_t), tz);
const cctz::civil_second tz_time = cctz::convert(std::chrono::system_clock::from_time_t(expected_time_t), tz);
/// Weird offset, not supported.
/// Example: Africa/Monrovia has offset UTC-0:44:30 in year 1970.
if (tz.lookup(std::chrono::system_clock::from_time_t(expected_time_t)).offset % 900)
auto timestamp_current_day_pre = std::chrono::system_clock::to_time_t(tz.lookup(cctz::civil_day(tz_time)).pre);
auto timestamp_current_day_post = std::chrono::system_clock::to_time_t(tz.lookup(cctz::civil_day(tz_time) + 1).post);
if (timestamp_current_day_pre % 900 || timestamp_current_day_post % 900)
continue;
/// Unsupported timezone transitions - not in 15-minute time point or to different day.
@ -410,7 +413,7 @@ TEST_P(DateLUTWithTimeZoneAndTimeRange, InRange)
bool has_transition = false;
cctz::time_zone::civil_transition transition{};
if (tz.next_transition(std::chrono::system_clock::from_time_t(expected_time_t), &transition)
if (tz.next_transition(std::chrono::system_clock::from_time_t(expected_time_t - 1), &transition)
&& (transition.from.day() == tz_time.day() || transition.to.day() == tz_time.day()))
{
has_transition = true;
@ -418,9 +421,9 @@ TEST_P(DateLUTWithTimeZoneAndTimeRange, InRange)
if (has_transition && (transition.from.second() != 0 || transition.from.minute() % 15 != 0))
{
std::cerr << "Skipping " << timezone_name << " " << tz_time
/*std::cerr << "Skipping " << timezone_name << " " << tz_time
<< " because of unsupported timezone transition from " << transition.from << " to " << transition.to
<< " (not divisible by 15 minutes)\n";
<< " (not divisible by 15 minutes)\n";*/
continue;
}
@ -428,9 +431,9 @@ TEST_P(DateLUTWithTimeZoneAndTimeRange, InRange)
if (has_transition && cctz::civil_day(transition.from) == cctz::civil_day(transition.to) + 1
&& transition.from != cctz::civil_day(transition.from))
{
std::cerr << "Skipping " << timezone_name << " " << tz_time
/*std::cerr << "Skipping " << timezone_name << " " << tz_time
<< " because of unsupported timezone transition from " << transition.from << " to " << transition.to
<< " (to previous day but not at midnight)\n";
<< " (to previous day but not at midnight)\n";*/
continue;
}
@ -438,9 +441,9 @@ TEST_P(DateLUTWithTimeZoneAndTimeRange, InRange)
if (has_transition
&& std::abs(transition.from - transition.to) > 3600 * 3)
{
std::cerr << "Skipping " << timezone_name << " " << tz_time
/*std::cerr << "Skipping " << timezone_name << " " << tz_time
<< " because of unsupported timezone transition from " << transition.from << " to " << transition.to
<< " (it is too large)\n";
<< " (it is too large)\n";*/
continue;
}
@ -457,23 +460,14 @@ TEST_P(DateLUTWithTimeZoneAndTimeRange, InRange)
const auto time_string = cctz::format("%E4Y-%m-%d %H:%M:%S", std::chrono::system_clock::from_time_t(expected_time_t), tz);
EXPECT_EQ(time_string, lut.timeToString(expected_time_t));
// it makes sense to let test execute all checks above to simplify debugging,
// but once we've found a bad apple, no need to dig deeper.
/// It makes sense to let test execute all checks above to simplify debugging,
/// but once we've found a bad apple, no need to dig deeper.
if (countFailures(*test_info->result()).total >= max_failures_per_case)
break;
}
}
/** Next tests are disabled due to following reasons:
* 1. They are huge and take enormous amount of time to run
* 2. Current implementation of DateLUTImpl is inprecise and some cases fail and it seems impractical to try to fix those.
* 3. Many failures (~300) were fixed while refactoring, about ~40 remain the same and 3 new introduced:
* "Asia/Gaza"
* "Pacific/Enderbury"
* "Pacific/Kiritimati"
* So it would be tricky to skip knonw failures to allow all unit tests to pass.
*/
INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimezones_Year2010,
INSTANTIATE_TEST_SUITE_P(AllTimezones_Year2010,
DateLUTWithTimeZoneAndTimeRange,
::testing::Combine(
::testing::ValuesIn(allTimezones()),
@ -484,7 +478,7 @@ INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimezones_Year2010,
}))
);
INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimezones_Year1970_WHOLE,
INSTANTIATE_TEST_SUITE_P(AllTimezones_Year1970_WHOLE,
DateLUTWithTimeZoneAndTimeRange,
::testing::Combine(
::testing::ValuesIn(allTimezones(false)),
@ -494,7 +488,7 @@ INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimezones_Year1970_WHOLE,
}))
);
INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimezones_Year2010_WHOLE,
INSTANTIATE_TEST_SUITE_P(AllTimezones_Year2010_WHOLE,
DateLUTWithTimeZoneAndTimeRange,
::testing::Combine(
::testing::ValuesIn(allTimezones(false)),
@ -504,7 +498,7 @@ INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimezones_Year2010_WHOLE,
}))
);
INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimezones_Year2020_WHOLE,
INSTANTIATE_TEST_SUITE_P(AllTimezones_Year2020_WHOLE,
DateLUTWithTimeZoneAndTimeRange,
::testing::Combine(
::testing::ValuesIn(allTimezones()),
@ -514,7 +508,7 @@ INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimezones_Year2020_WHOLE,
}))
);
INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimezones_PreEpoch,
INSTANTIATE_TEST_SUITE_P(AllTimezones_PreEpoch,
DateLUTWithTimeZoneAndTimeRange,
::testing::Combine(
::testing::ValuesIn(allTimezones(false)),
@ -524,7 +518,7 @@ INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimezones_PreEpoch,
}))
);
INSTANTIATE_TEST_SUITE_P(DISABLED_AllTimezones_Year1970,
INSTANTIATE_TEST_SUITE_P(AllTimezones_Year1970,
DateLUTWithTimeZoneAndTimeRange,
::testing::Combine(
::testing::ValuesIn(allTimezones(false)),