LibJS+LibUnicode: Port retrieving available regional time zones to ICU

This commit is contained in:
Timothy Flynn 2024-06-25 11:33:26 -04:00 committed by Andreas Kling
parent 4fc0fba646
commit 1b2d47e6bb
4 changed files with 41 additions and 20 deletions

View File

@ -49,6 +49,18 @@ TEST_CASE(available_time_zones)
EXPECT(!time_zones.contains_slow("EAT"sv));
}
TEST_CASE(available_time_zones_in_region)
{
{
auto time_zones = Unicode::available_time_zones_in_region("AD"sv);
EXPECT_EQ(time_zones, to_array({ "Europe/Andorra"_string }));
}
{
auto time_zones = Unicode::available_time_zones_in_region("ES"sv);
EXPECT_EQ(time_zones, to_array({ "Africa/Ceuta"_string, "Atlantic/Canary"_string, "Europe/Madrid"_string }));
}
}
TEST_CASE(resolve_primary_time_zone)
{
EXPECT_EQ(Unicode::resolve_primary_time_zone("UTC"sv), "Etc/UTC"sv);

View File

@ -8,9 +8,9 @@
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Intl/Locale.h>
#include <LibTimeZone/TimeZone.h>
#include <LibUnicode/DateTimeFormat.h>
#include <LibUnicode/Locale.h>
#include <LibUnicode/TimeZone.h>
#include <LibUnicode/UnicodeKeywords.h>
namespace JS::Intl {
@ -142,12 +142,11 @@ NonnullGCPtr<Array> time_zones_of_locale(VM& vm, StringView region)
// 3. Let region be the substring of locale corresponding to the unicode_region_subtag production of the unicode_language_id.
// 4. Let list be a List of unique canonical time zone identifiers, which must be String values indicating a canonical Zone name of the IANA Time Zone Database, ordered as if an Array of the same values had been sorted using %Array.prototype.sort% using undefined as comparefn, of those in common use in region. If no time zones are commonly used in region, let list be a new empty List.
auto list = TimeZone::time_zones_in_region(region);
quick_sort(list);
auto list = Unicode::available_time_zones_in_region(region);
// 5. Return ! CreateArrayFromList( list ).
return Array::create_from<StringView>(realm, list, [&vm](auto value) {
return PrimitiveString::create(vm, String::from_utf8(value).release_value());
return Array::create_from<String>(realm, list, [&vm](auto value) {
return PrimitiveString::create(vm, value);
});
}

View File

@ -76,26 +76,35 @@ static constexpr bool is_legacy_non_iana_time_zone(StringView time_zone)
return legacy_zones.contains_slow(time_zone);
}
static Vector<String> icu_available_time_zones(Optional<ByteString> const& region)
{
UErrorCode status = U_ZERO_ERROR;
char const* icu_region = region.has_value() ? region->characters() : nullptr;
auto time_zone_enumerator = adopt_own_if_nonnull(icu::TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_ANY, icu_region, nullptr, status));
if (icu_failure(status))
return { "UTC"_string };
auto time_zones = icu_string_enumeration_to_list(move(time_zone_enumerator), [](char const* zone) {
return !is_legacy_non_iana_time_zone({ zone, strlen(zone) });
});
quick_sort(time_zones);
return time_zones;
}
Vector<String> const& available_time_zones()
{
static auto time_zones = []() -> Vector<String> {
UErrorCode status = U_ZERO_ERROR;
auto time_zone_enumerator = adopt_own_if_nonnull(icu::TimeZone::createEnumeration(status));
if (icu_failure(status))
return { "UTC"_string };
auto time_zones = icu_string_enumeration_to_list(move(time_zone_enumerator), [](char const* zone) {
return !is_legacy_non_iana_time_zone({ zone, strlen(zone) });
});
quick_sort(time_zones);
return time_zones;
}();
static auto time_zones = icu_available_time_zones({});
return time_zones;
}
Vector<String> available_time_zones_in_region(StringView region)
{
return icu_available_time_zones(region);
}
Optional<String> resolve_primary_time_zone(StringView time_zone)
{
UErrorCode status = U_ZERO_ERROR;

View File

@ -14,6 +14,7 @@ namespace Unicode {
String current_time_zone();
Vector<String> const& available_time_zones();
Vector<String> available_time_zones_in_region(StringView region);
Optional<String> resolve_primary_time_zone(StringView time_zone);
}