mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-29 16:21:29 +00:00
LibJS+LibUnicode: Port retrieving the system time zone to ICU
This commit is contained in:
parent
89aa9a3af0
commit
d3e809bcd4
Notes:
sideshowbarker
2024-07-16 22:18:54 +09:00
Author: https://github.com/trflynn89 Commit: https://github.com/LadybirdBrowser/ladybird/commit/d3e809bcd4 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/281
|
@ -4,6 +4,7 @@ set(TEST_SOURCES
|
|||
TestIDNA.cpp
|
||||
TestLocale.cpp
|
||||
TestSegmenter.cpp
|
||||
TestTimeZone.cpp
|
||||
TestUnicodeCharacterTypes.cpp
|
||||
TestUnicodeNormalization.cpp
|
||||
)
|
||||
|
|
43
Tests/LibUnicode/TestTimeZone.cpp
Normal file
43
Tests/LibUnicode/TestTimeZone.cpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibTest/TestCase.h>
|
||||
|
||||
#include <AK/StringView.h>
|
||||
#include <LibCore/Environment.h>
|
||||
#include <LibUnicode/TimeZone.h>
|
||||
|
||||
class TimeZoneGuard {
|
||||
public:
|
||||
explicit TimeZoneGuard(StringView time_zone)
|
||||
: m_time_zone(Core::Environment::get("TZ"sv))
|
||||
{
|
||||
MUST(Core::Environment::set("TZ"sv, time_zone, Core::Environment::Overwrite::Yes));
|
||||
}
|
||||
|
||||
~TimeZoneGuard()
|
||||
{
|
||||
if (m_time_zone.has_value())
|
||||
MUST(Core::Environment::set("TZ"sv, *m_time_zone, Core::Environment::Overwrite::Yes));
|
||||
else
|
||||
MUST(Core::Environment::unset("TZ"sv));
|
||||
}
|
||||
|
||||
private:
|
||||
Optional<StringView> m_time_zone;
|
||||
};
|
||||
|
||||
TEST_CASE(current_time_zone)
|
||||
{
|
||||
{
|
||||
TimeZoneGuard guard { "America/New_York"sv };
|
||||
EXPECT_EQ(Unicode::current_time_zone(), "America/New_York"sv);
|
||||
}
|
||||
{
|
||||
TimeZoneGuard guard { "ladybird"sv };
|
||||
EXPECT_EQ(Unicode::current_time_zone(), "UTC"sv);
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/Temporal/ISO8601.h>
|
||||
#include <LibTimeZone/TimeZone.h>
|
||||
#include <LibUnicode/TimeZone.h>
|
||||
#include <time.h>
|
||||
|
||||
namespace JS {
|
||||
|
@ -464,9 +465,9 @@ Vector<TimeZoneIdentifier> available_named_time_zone_identifiers()
|
|||
}
|
||||
|
||||
// 21.4.1.24 SystemTimeZoneIdentifier ( ), https://tc39.es/ecma262/#sec-systemtimezoneidentifier
|
||||
StringView system_time_zone_identifier()
|
||||
String system_time_zone_identifier()
|
||||
{
|
||||
return TimeZone::current_time_zone();
|
||||
return Unicode::current_time_zone();
|
||||
}
|
||||
|
||||
// 21.4.1.25 LocalTime ( t ), https://tc39.es/ecma262/#sec-localtime
|
||||
|
|
|
@ -76,7 +76,7 @@ Crypto::SignedBigInteger get_utc_epoch_nanoseconds(i32 year, u8 month, u8 day, u
|
|||
Vector<Crypto::SignedBigInteger> get_named_time_zone_epoch_nanoseconds(StringView time_zone_identifier, i32 year, u8 month, u8 day, u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond);
|
||||
i64 get_named_time_zone_offset_nanoseconds(StringView time_zone_identifier, Crypto::SignedBigInteger const& epoch_nanoseconds);
|
||||
Vector<TimeZoneIdentifier> available_named_time_zone_identifiers();
|
||||
StringView system_time_zone_identifier();
|
||||
String system_time_zone_identifier();
|
||||
double local_time(double time);
|
||||
double utc_time(double time);
|
||||
double make_time(double hour, double min, double sec, double ms);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <LibTimeZone/TimeZone.h>
|
||||
#include <LibUnicode/DisplayNames.h>
|
||||
#include <LibUnicode/Locale.h>
|
||||
#include <LibUnicode/TimeZone.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
|
@ -1159,7 +1160,7 @@ ByteString time_zone_string(double time)
|
|||
if (auto name = Unicode::time_zone_display_name(Unicode::default_locale(), tz_name, maybe_offset->in_dst, time); name.has_value())
|
||||
tz_name = name.release_value();
|
||||
} else {
|
||||
tz_name = MUST(String::from_utf8(TimeZone::current_time_zone()));
|
||||
tz_name = Unicode::current_time_zone();
|
||||
}
|
||||
|
||||
// 10. Return the string-concatenation of offsetSign, offsetHour, offsetMin, and tzName.
|
||||
|
|
|
@ -197,7 +197,7 @@ ThrowCompletionOr<NonnullGCPtr<DateTimeFormat>> create_date_time_format(VM& vm,
|
|||
// 30. If timeZone is undefined, then
|
||||
if (time_zone_value.is_undefined()) {
|
||||
// a. Set timeZone to DefaultTimeZone().
|
||||
time_zone = MUST(String::from_utf8(system_time_zone_identifier()));
|
||||
time_zone = system_time_zone_identifier();
|
||||
}
|
||||
// 31. Else,
|
||||
else {
|
||||
|
|
|
@ -687,7 +687,7 @@ ThrowCompletionOr<RelativeTo> to_relative_temporal_object(VM& vm, Object const&
|
|||
}
|
||||
|
||||
// ii. Let timeZone be ! CreateTemporalTimeZone(timeZoneName).
|
||||
time_zone = MUST_OR_THROW_OOM(create_temporal_time_zone(vm, *time_zone_name));
|
||||
time_zone = MUST_OR_THROW_OOM(create_temporal_time_zone(vm, time_zone_name.release_value()));
|
||||
|
||||
// iii. If result.[[TimeZone]].[[Z]] is true, then
|
||||
if (result.time_zone.z) {
|
||||
|
|
|
@ -279,7 +279,7 @@ ThrowCompletionOr<String> temporal_instant_to_string(VM& vm, Instant& instant, V
|
|||
// 4. If outputTimeZone is undefined, then
|
||||
if (output_time_zone.is_undefined()) {
|
||||
// a. Set outputTimeZone to ! CreateTemporalTimeZone("UTC").
|
||||
output_time_zone = MUST_OR_THROW_OOM(create_temporal_time_zone(vm, "UTC"sv));
|
||||
output_time_zone = MUST_OR_THROW_OOM(create_temporal_time_zone(vm, "UTC"_string));
|
||||
}
|
||||
|
||||
// 5. Let isoCalendar be ! GetISO8601Calendar().
|
||||
|
|
|
@ -158,7 +158,7 @@ TimeZone* system_time_zone(VM& vm)
|
|||
|
||||
// 2. Return ! CreateTemporalTimeZone(identifier).
|
||||
// FIXME: Propagate possible OOM error
|
||||
return MUST(create_temporal_time_zone(vm, identifier));
|
||||
return MUST(create_temporal_time_zone(vm, move(identifier)));
|
||||
}
|
||||
|
||||
// 2.3.2 SystemUTCEpochNanoseconds ( ), https://tc39.es/proposal-temporal/#sec-temporal-systemutcepochnanoseconds
|
||||
|
|
|
@ -61,7 +61,7 @@ ThrowCompletionOr<String> canonicalize_time_zone_name(VM& vm, StringView time_zo
|
|||
}
|
||||
|
||||
// 11.6.1 CreateTemporalTimeZone ( identifier [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporaltimezone
|
||||
ThrowCompletionOr<TimeZone*> create_temporal_time_zone(VM& vm, StringView identifier, FunctionObject const* new_target)
|
||||
ThrowCompletionOr<TimeZone*> create_temporal_time_zone(VM& vm, String identifier, FunctionObject const* new_target)
|
||||
{
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
|
@ -89,7 +89,7 @@ ThrowCompletionOr<TimeZone*> create_temporal_time_zone(VM& vm, StringView identi
|
|||
VERIFY(MUST_OR_THROW_OOM(canonicalize_time_zone_name(vm, identifier)) == identifier);
|
||||
|
||||
// b. Set object.[[Identifier]] to identifier.
|
||||
object->set_identifier(TRY_OR_THROW_OOM(vm, String::from_utf8(identifier)));
|
||||
object->set_identifier(move(identifier));
|
||||
|
||||
// c. Set object.[[OffsetNanoseconds]] to undefined.
|
||||
// NOTE: No-op.
|
||||
|
@ -318,15 +318,15 @@ ThrowCompletionOr<Object*> to_temporal_time_zone(VM& vm, Value temporal_time_zon
|
|||
}
|
||||
|
||||
// c. Return ! CreateTemporalTimeZone(name).
|
||||
return MUST_OR_THROW_OOM(create_temporal_time_zone(vm, name));
|
||||
return MUST_OR_THROW_OOM(create_temporal_time_zone(vm, move(name)));
|
||||
}
|
||||
|
||||
// 5. If parseResult.[[Z]] is true, return ! CreateTemporalTimeZone("UTC").
|
||||
if (parse_result.z)
|
||||
return MUST_OR_THROW_OOM(create_temporal_time_zone(vm, "UTC"sv));
|
||||
return MUST_OR_THROW_OOM(create_temporal_time_zone(vm, "UTC"_string));
|
||||
|
||||
// 6. Return ! CreateTemporalTimeZone(parseResult.[[OffsetString]]).
|
||||
return MUST_OR_THROW_OOM(create_temporal_time_zone(vm, *parse_result.offset_string));
|
||||
return MUST_OR_THROW_OOM(create_temporal_time_zone(vm, parse_result.offset_string.release_value()));
|
||||
}
|
||||
|
||||
// 11.5.19 GetOffsetNanosecondsFor ( timeZoneRec, instant ), https://tc39.es/proposal-temporal/#sec-temporal-getoffsetnanosecondsfor
|
||||
|
|
|
@ -39,7 +39,7 @@ private:
|
|||
|
||||
bool is_available_time_zone_name(StringView time_zone);
|
||||
ThrowCompletionOr<String> canonicalize_time_zone_name(VM&, StringView time_zone);
|
||||
ThrowCompletionOr<TimeZone*> create_temporal_time_zone(VM&, StringView identifier, FunctionObject const* new_target = nullptr);
|
||||
ThrowCompletionOr<TimeZone*> create_temporal_time_zone(VM&, String identifier, FunctionObject const* new_target = nullptr);
|
||||
ISODateTime get_iso_parts_from_epoch(VM&, Crypto::SignedBigInteger const& epoch_nanoseconds);
|
||||
BigInt* get_named_time_zone_next_transition(VM&, StringView time_zone_identifier, BigInt const& epoch_nanoseconds);
|
||||
BigInt* get_named_time_zone_previous_transition(VM&, StringView time_zone_identifier, BigInt const& epoch_nanoseconds);
|
||||
|
|
|
@ -65,7 +65,7 @@ ThrowCompletionOr<NonnullGCPtr<Object>> TimeZoneConstructor::construct(FunctionO
|
|||
}
|
||||
|
||||
// 4. Return ? CreateTemporalTimeZone(identifier, NewTarget).
|
||||
return *TRY(create_temporal_time_zone(vm, identifier, &new_target));
|
||||
return *TRY(create_temporal_time_zone(vm, move(identifier), &new_target));
|
||||
}
|
||||
|
||||
// 11.3.2 Temporal.TimeZone.from ( item ), https://tc39.es/proposal-temporal/#sec-temporal.timezone.from
|
||||
|
|
|
@ -227,7 +227,7 @@ ThrowCompletionOr<ZonedDateTime*> to_temporal_zoned_date_time(VM& vm, Value item
|
|||
}
|
||||
|
||||
// j. Let timeZone be ! CreateTemporalTimeZone(timeZoneName).
|
||||
time_zone = MUST_OR_THROW_OOM(create_temporal_time_zone(vm, *time_zone_name));
|
||||
time_zone = MUST_OR_THROW_OOM(create_temporal_time_zone(vm, time_zone_name.release_value()));
|
||||
|
||||
// k. Let calendar be ? ToTemporalCalendarWithISODefault(result.[[Calendar]]).
|
||||
auto temporal_calendar_like = result.calendar.has_value()
|
||||
|
|
|
@ -17,6 +17,7 @@ set(SOURCES
|
|||
RelativeTimeFormat.cpp
|
||||
Segmenter.cpp
|
||||
String.cpp
|
||||
TimeZone.cpp
|
||||
UnicodeKeywords.cpp
|
||||
${UNICODE_DATA_SOURCES}
|
||||
)
|
||||
|
|
37
Userland/Libraries/LibUnicode/TimeZone.cpp
Normal file
37
Userland/Libraries/LibUnicode/TimeZone.cpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#define AK_DONT_REPLACE_STD
|
||||
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <LibUnicode/ICU.h>
|
||||
#include <LibUnicode/TimeZone.h>
|
||||
|
||||
#include <unicode/timezone.h>
|
||||
|
||||
namespace Unicode {
|
||||
|
||||
String current_time_zone()
|
||||
{
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
auto time_zone = adopt_own_if_nonnull(icu::TimeZone::detectHostTimeZone());
|
||||
if (!time_zone)
|
||||
return "UTC"_string;
|
||||
|
||||
icu::UnicodeString time_zone_id;
|
||||
time_zone->getID(time_zone_id);
|
||||
|
||||
icu::UnicodeString time_zone_name;
|
||||
time_zone->getCanonicalID(time_zone_id, time_zone_name, status);
|
||||
|
||||
if (icu_failure(status))
|
||||
return "UTC"_string;
|
||||
|
||||
return icu_string_to_string(time_zone_name);
|
||||
}
|
||||
|
||||
}
|
15
Userland/Libraries/LibUnicode/TimeZone.h
Normal file
15
Userland/Libraries/LibUnicode/TimeZone.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/String.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Unicode {
|
||||
|
||||
String current_time_zone();
|
||||
|
||||
}
|
Loading…
Reference in a new issue