Speedup DateLUT initialization

This commit is contained in:
Alexander Gololobov 2023-06-23 23:33:45 +02:00
parent b7ef782335
commit 8243b624e9

View File

@ -33,8 +33,24 @@ UInt8 getDayOfWeek(const cctz::civil_day & date)
UNREACHABLE();
}
inline cctz::time_point<cctz::seconds> lookupTz(const cctz::time_zone & cctz_time_zone, const cctz::civil_day & date)
{
cctz::time_zone::civil_lookup lookup = cctz_time_zone.lookup(date);
/// Ambiguity is possible if time was changed backwards at the midnight
/// or after midnight time has been changed back to midnight, for example one hour backwards at 01:00
/// or after midnight time has been changed to the previous day, for example two hours backwards at 01:00
/// Then midnight appears twice. Usually time change happens exactly at 00:00 or 01:00.
/// If transition did not involve previous day, we should use the first midnight as the start of the day,
/// otherwise it's better to use the second midnight.
return lookup.trans < lookup.post
? lookup.post /* Second midnight appears after transition, so there was a piece of previous day after transition */
: lookup.pre;
}
}
__attribute__((__weak__)) extern bool inside_main;
@ -63,54 +79,21 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
offset_is_whole_number_of_minutes_during_epoch = true;
cctz::civil_day date = lut_start;
cctz::time_point<cctz::seconds> start_of_day_time_point = lookupTz(cctz_time_zone, date);
auto next_transition_date = date;
UInt32 i = 0;
do
{
cctz::time_zone::civil_lookup lookup = cctz_time_zone.lookup(date);
/// Ambiguity is possible if time was changed backwards at the midnight
/// or after midnight time has been changed back to midnight, for example one hour backwards at 01:00
/// or after midnight time has been changed to the previous day, for example two hours backwards at 01:00
/// Then midnight appears twice. Usually time change happens exactly at 00:00 or 01:00.
/// If transition did not involve previous day, we should use the first midnight as the start of the day,
/// otherwise it's better to use the second midnight.
std::chrono::time_point start_of_day_time_point = lookup.trans < lookup.post
? lookup.post /* Second midnight appears after transition, so there was a piece of previous day after transition */
: lookup.pre;
start_of_day = std::chrono::system_clock::to_time_t(start_of_day_time_point);
Values & values = lut[i];
values.year = date.year();
values.month = date.month();
values.day_of_month = date.day();
values.day_of_week = getDayOfWeek(date);
values.date = start_of_day;
assert(values.year >= DATE_LUT_MIN_YEAR && values.year <= DATE_LUT_MAX_YEAR + 1);
assert(values.month >= 1 && values.month <= 12);
assert(values.day_of_month >= 1 && values.day_of_month <= 31);
assert(values.day_of_week >= 1 && values.day_of_week <= 7);
if (values.day_of_month == 1)
{
cctz::civil_month month(date);
values.days_in_month = cctz::civil_day(month + 1) - cctz::civil_day(month);
}
else
values.days_in_month = i != 0 ? lut[i - 1].days_in_month : 31;
values.time_at_offset_change_value = 0;
values.amount_of_offset_change_value = 0;
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 (offset_is_whole_number_of_minutes_during_epoch && start_of_day > 0 && start_of_day % 60)
offset_is_whole_number_of_minutes_during_epoch = false;
if (date >= next_transition_date)
{
start_of_day_time_point = lookupTz(cctz_time_zone, date);
/// 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
@ -134,7 +117,38 @@ DateLUTImpl::DateLUTImpl(const std::string & time_zone_)
values.time_at_offset_change_value = -values.amount_of_offset_change_value;
}
next_transition_date = std::min(cctz::civil_day(transition.to), cctz::civil_day(transition.from));
}
start_of_day = std::chrono::system_clock::to_time_t(start_of_day_time_point);
values.year = date.year();
values.month = date.month();
values.day_of_month = date.day();
values.day_of_week = getDayOfWeek(date);
values.date = start_of_day;
assert(values.year >= DATE_LUT_MIN_YEAR && values.year <= DATE_LUT_MAX_YEAR + 1);
assert(values.month >= 1 && values.month <= 12);
assert(values.day_of_month >= 1 && values.day_of_month <= 31);
assert(values.day_of_week >= 1 && values.day_of_week <= 7);
if (values.day_of_month == 1)
{
cctz::civil_month month(date);
values.days_in_month = cctz::civil_day(month + 1) - cctz::civil_day(month);
}
else
values.days_in_month = i != 0 ? lut[i - 1].days_in_month : 31;
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 (offset_is_whole_number_of_minutes_during_epoch && start_of_day > 0 && start_of_day % 60)
offset_is_whole_number_of_minutes_during_epoch = false;
/// Going to next day.
start_of_day_time_point += std::chrono::hours(24);
++date;
++i;
}