diff options
author | Timothy Flynn <trflynn89@pm.me> | 2022-01-19 11:17:54 -0500 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-01-19 21:20:41 +0000 |
commit | 42c9c57141b33845e63f8028b18ccc71223c2297 (patch) | |
tree | 8e6de5da804a9810596d6d92ec26c12fbe83750b /Meta/Lagom | |
parent | 9dd4602636074519d2a8df572e977811fad8aadd (diff) | |
download | serenity-42c9c57141b33845e63f8028b18ccc71223c2297.zip |
LibJS+LibTimeZone: Begin handling DST when computing time zone offsets
This also updates some expectations in a Temporal time zone offset test
that is using a time stamp which is in DST for a few time zones.
Diffstat (limited to 'Meta/Lagom')
-rw-r--r-- | Meta/Lagom/Tools/CodeGenerators/LibTimeZone/GenerateTimeZoneData.cpp | 58 |
1 files changed, 56 insertions, 2 deletions
diff --git a/Meta/Lagom/Tools/CodeGenerators/LibTimeZone/GenerateTimeZoneData.cpp b/Meta/Lagom/Tools/CodeGenerators/LibTimeZone/GenerateTimeZoneData.cpp index 46efbe016a..64e05485d3 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibTimeZone/GenerateTimeZoneData.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibTimeZone/GenerateTimeZoneData.cpp @@ -450,9 +450,55 @@ static constexpr Array<@type@, @size@> @name@ { { append_string_conversions("DaylightSavingsRule"sv, "daylight_savings_rule"sv, time_zone_data.dst_offset_names); generator.append(R"~~~( +static i64 get_dst_offset(TimeZoneOffset const& time_zone_offset, AK::Time time) +{ + auto const& dst_rules = s_dst_offsets[time_zone_offset.dst_rule]; + + DaylightSavingsOffset const* standard_offset = nullptr; + DaylightSavingsOffset const* daylight_offset = nullptr; + + auto time_in_effect_for_rule = [&](auto const& dst_rule) { + auto in_effect = dst_rule.in_effect; + in_effect.year = seconds_since_epoch_to_year(time.to_seconds()); + + return in_effect.time_since_epoch(); + }; + + auto preferred_rule = [&](auto* current_offset, auto& new_offset) { + if (!current_offset) + return &new_offset; + + auto new_time_in_effect = time_in_effect_for_rule(new_offset); + return (time >= new_time_in_effect) ? &new_offset : current_offset; + }; + + 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)) + continue; + + if (dst_rule.offset == 0) + standard_offset = preferred_rule(standard_offset, dst_rule); + else + daylight_offset = preferred_rule(daylight_offset, dst_rule); + } + + if (!standard_offset || !daylight_offset) + return 0; + + auto standard_time_in_effect = time_in_effect_for_rule(*standard_offset); + auto daylight_time_in_effect = time_in_effect_for_rule(*daylight_offset); + + if ((time < daylight_time_in_effect) || (time >= standard_time_in_effect)) + return standard_offset->offset; + return daylight_offset->offset; +} + Optional<i64> get_time_zone_offset(TimeZone time_zone, AK::Time time) { - // FIXME: This implementation completely ignores DST. auto const& time_zone_offsets = s_time_zone_offsets[to_underlying(time_zone)]; size_t index = 0; @@ -464,7 +510,15 @@ Optional<i64> get_time_zone_offset(TimeZone time_zone, AK::Time time) } VERIFY(index < time_zone_offsets.size()); - return time_zone_offsets[index].offset; + auto const& time_zone_offset = time_zone_offsets[index]; + + i64 dst_offset = 0; + if (time_zone_offset.dst_rule != -1) + dst_offset = get_dst_offset(time_zone_offset, time); + else + dst_offset = time_zone_offset.dst_offset; + + return time_zone_offset.offset + dst_offset; } } |