LibTimeZone: Parse and generate a list of time zones used by region

The zone1970.tab file in the TZDB contains regional time zone data, some
of which we already parse for the system time zone settings map.

This parses the region names from that file and generates a list of time
zones which are used in each of those regions.
This commit is contained in:
Timothy Flynn 2022-07-05 15:56:23 -04:00 committed by Linus Groh
parent f6aa6a480c
commit fa005bd276
Notes: sideshowbarker 2024-07-17 23:00:03 +09:00
4 changed files with 65 additions and 2 deletions

View file

@ -18,8 +18,8 @@
namespace {
using StringIndexType = u8;
constexpr auto s_string_index_type = "u8"sv;
using StringIndexType = u16;
constexpr auto s_string_index_type = "u16"sv;
struct DateTime {
u16 year { 0 };
@ -67,6 +67,9 @@ struct TimeZoneData {
Vector<String> dst_offset_names;
HashMap<String, TimeZone::Location> time_zone_coordinates;
HashMap<String, Vector<StringIndexType>> time_zone_regions;
Vector<String> time_zone_region_names;
};
}
@ -379,6 +382,7 @@ static ErrorOr<void> parse_time_zone_coordinates(Core::Stream::BufferedFile& fil
continue;
auto segments = line.split_view('\t');
auto regions = segments[0];
auto coordinates = segments[1];
auto zone = segments[2];
@ -389,6 +393,14 @@ static ErrorOr<void> parse_time_zone_coordinates(Core::Stream::BufferedFile& fil
auto longitude = parse_coordinate(coordinates.substring_view(index));
time_zone_data.time_zone_coordinates.set(zone, { latitude, longitude });
regions.for_each_split_view(',', false, [&](auto region) {
auto index = time_zone_data.unique_strings.ensure(zone);
time_zone_data.time_zone_regions.ensure(region).append(index);
if (!time_zone_data.time_zone_region_names.contains_slow(region))
time_zone_data.time_zone_region_names.append(region);
});
}
return {};
@ -447,6 +459,7 @@ namespace TimeZone {
generate_enum(generator, format_identifier, "TimeZone"sv, {}, time_zone_data.time_zone_names, time_zone_data.time_zone_aliases);
generate_enum(generator, format_identifier, "DaylightSavingsRule"sv, {}, time_zone_data.dst_offset_names);
generate_enum(generator, format_identifier, "Region"sv, {}, time_zone_data.time_zone_region_names);
generator.append(R"~~~(
}
@ -556,6 +569,26 @@ static constexpr Array<@type@, @size@> @name@ { {
append_offsets(name, "DaylightSavingsOffset"sv, dst_offsets);
});
generate_mapping(generator, time_zone_data.time_zone_region_names, s_string_index_type, "s_regional_time_zones"sv, "s_regional_time_zones_{}", format_identifier,
[&](auto const& name, auto const& value) {
auto const& time_zones = time_zone_data.time_zone_regions.find(value)->value;
generator.set("name", name);
generator.set("size", String::number(time_zones.size()));
generator.append(R"~~~(
static constexpr Array<@string_index_type@, @size@> @name@ { {)~~~");
bool first = true;
for (auto const& time_zone : time_zones) {
generator.append(first ? " " : ", ");
generator.append(String::number(time_zone));
first = false;
}
generator.append(" } };");
});
generator.set("size", String::number(time_zone_data.time_zone_names.size()));
generator.append(R"~~~(
static constexpr Array<Location, @size@> s_time_zone_locations { {
@ -590,6 +623,7 @@ static constexpr Array<Location, @size@> s_time_zone_locations { {
append_string_conversions("TimeZone"sv, "time_zone"sv, time_zone_data.time_zone_names, time_zone_data.time_zone_aliases);
append_string_conversions("DaylightSavingsRule"sv, "daylight_savings_rule"sv, time_zone_data.dst_offset_names);
append_string_conversions("Region"sv, "region"sv, time_zone_data.time_zone_region_names);
generator.append(R"~~~(
static Array<DaylightSavingsOffset const*, 2> find_dst_offsets(TimeZoneOffset const& time_zone_offset, AK::Time time)
@ -727,6 +761,25 @@ Optional<Location> get_time_zone_location(TimeZone time_zone)
return location;
return {};
}
Vector<StringView> time_zones_in_region(StringView region)
{
auto region_value = region_from_string(region);
if (!region_value.has_value())
return {};
auto region_index = to_underlying(*region_value);
auto const& regional_time_zones = s_regional_time_zones[region_index];
Vector<StringView> time_zones;
time_zones.ensure_capacity(regional_time_zones.size());
for (auto time_zone : regional_time_zones)
time_zones.unchecked_append(s_string_list[time_zone]);
return time_zones;
}
)~~~");
generate_available_values(generator, "all_time_zones"sv, time_zone_data.time_zone_names);

View file

@ -11,6 +11,7 @@
namespace TimeZone {
enum class DaylightSavingsRule : u8;
enum class Region : u8;
enum class TimeZone : u16;
}

View file

@ -192,4 +192,8 @@ Optional<Location> get_time_zone_location(StringView time_zone)
return {};
}
Optional<Region> __attribute__((weak)) region_from_string(StringView) { return {}; }
StringView __attribute__((weak)) region_to_string(Region) { return {}; }
Vector<StringView> __attribute__((weak)) time_zones_in_region(StringView) { return {}; }
}

View file

@ -13,6 +13,7 @@
#include <AK/StringView.h>
#include <AK/Time.h>
#include <AK/Types.h>
#include <AK/Vector.h>
#include <LibTimeZone/Forward.h>
namespace TimeZone {
@ -68,4 +69,8 @@ Optional<Array<NamedOffset, 2>> get_named_time_zone_offsets(StringView time_zone
Optional<Location> get_time_zone_location(TimeZone time_zone);
Optional<Location> get_time_zone_location(StringView time_zone);
Optional<Region> region_from_string(StringView region);
StringView region_to_string(Region region);
Vector<StringView> time_zones_in_region(StringView region);
}