From 302b6e966f9b42ed68b6753a0d353d5d224a666e Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Sat, 17 Sep 2022 15:57:26 -0400 Subject: [PATCH] LibTimeZone: Generate DST rule timestamps at compile time Rather than invoking AK::Time::from_timestamp at runtime, we can do so at compile time. This reduces invoking TimeZone::get_time_zone_offset 100,000 times in a loop from about 7 seconds to 30 milliseconds. --- .../LibTimeZone/GenerateTimeZoneData.cpp | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/Meta/Lagom/Tools/CodeGenerators/LibTimeZone/GenerateTimeZoneData.cpp b/Meta/Lagom/Tools/CodeGenerators/LibTimeZone/GenerateTimeZoneData.cpp index 750b1ef9836b30..4762c63a05f3b3 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibTimeZone/GenerateTimeZoneData.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibTimeZone/GenerateTimeZoneData.cpp @@ -50,7 +50,7 @@ struct TimeZoneOffset { struct DaylightSavingsOffset { i64 offset { 0 }; u16 year_from { 0 }; - u16 year_to { 0 }; + Optional year_to; DateTime in_effect; StringIndexType format { 0 }; @@ -112,11 +112,19 @@ template<> struct AK::Formatter : Formatter { ErrorOr format(FormatBuilder& builder, DaylightSavingsOffset const& dst_offset) { + auto format_time = [&](auto year) { + return String::formatted("AK::Time::from_timestamp({}, 1, 1, 0, 0, 0, 0)", year); + }; + + static String max_year_as_time("max_year_as_time"sv); + return Formatter::format(builder, "{{ {}, {}, {}, {}, {} }}"sv, dst_offset.offset, - dst_offset.year_from, - dst_offset.year_to, + format_time(dst_offset.year_from), + dst_offset.year_to.has_value() + ? format_time(*dst_offset.year_to + 1) + : max_year_as_time, dst_offset.in_effect, dst_offset.format); } @@ -292,9 +300,7 @@ static void parse_rule(StringView rule_line, TimeZoneData& time_zone_data) if (segments[3] == "only") dst_offset.year_to = dst_offset.year_from; - else if (segments[3] == "max"sv) - dst_offset.year_to = NumericLimits::max(); - else + else if (segments[3] != "max"sv) dst_offset.year_to = segments[3].to_uint().value(); auto in_effect = Array { "0"sv, segments[5], segments[6], segments[7] }; @@ -482,6 +488,7 @@ static ErrorOr generate_time_zone_data_implementation(Core::Stream::Buffer #include #include #include +#include #include #include #include @@ -489,6 +496,8 @@ static ErrorOr generate_time_zone_data_implementation(Core::Stream::Buffer namespace TimeZone { +static constexpr auto max_year_as_time = AK::Time::from_timestamp(NumericLimits::max(), 1, 1, 0, 0, 0, 0); + struct DateTime { AK::Time time_since_epoch() const { @@ -532,8 +541,8 @@ struct DaylightSavingsOffset { } i64 offset { 0 }; - u16 year_from { 0 }; - u16 year_to { 0 }; + AK::Time year_from {}; + AK::Time year_to {}; DateTime in_effect {}; @string_index_type@ format { 0 }; @@ -643,10 +652,7 @@ static Array find_dst_offsets(TimeZoneOffset co for (size_t index = 0; (index < dst_rules.size()) && (!standard_offset || !daylight_offset); ++index) { auto const& dst_rule = dst_rules[index]; - - auto year_from = AK::Time::from_timestamp(dst_rule.year_from, 1, 1, 0, 0, 0, 0); - auto year_to = AK::Time::from_timestamp(dst_rule.year_to + 1, 1, 1, 0, 0, 0, 0); - if ((time < year_from) || (time >= year_to)) + if ((time < dst_rule.year_from) || (time >= dst_rule.year_to)) continue; if (dst_rule.offset == 0)