1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 15:07:45 +00:00

LibJS: Don't parse/re-format offset in parse_temporal_time_zone_string()

This is an editorial change in the Temporal spec.

See: 6abe146
This commit is contained in:
Linus Groh 2022-01-22 21:52:55 +00:00
parent 31283b5e64
commit 0e3def1d0b
3 changed files with 29 additions and 70 deletions

View file

@ -1626,89 +1626,46 @@ ThrowCompletionOr<TemporalTimeZone> parse_temporal_time_zone_string(GlobalObject
{
auto& vm = global_object.vm();
auto optional_string_view_to_optional_string = [](Optional<StringView> const& s) {
return s.has_value() ? String { *s } : Optional<String> {};
};
// 1. Assert: Type(isoString) is String.
// 2. If isoString does not satisfy the syntax of a TemporalTimeZoneString (see 13.33), then
// 2. Let parseResult be ParseText(! StringToCodePoints(isoString), TemporalTimeZoneString).
auto parse_result = parse_iso8601(Production::TemporalTimeZoneString, iso_string);
// 3. If parseResult is a List of errors, then
if (!parse_result.has_value()) {
// a. Throw a RangeError exception.
return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidTimeZoneString, iso_string);
}
// 3. Let z, sign, hours, minutes, seconds, fraction and name be the parts of isoString produced respectively by the UTCDesignator, TimeZoneUTCOffsetSign, TimeZoneUTCOffsetHour, TimeZoneUTCOffsetMinute, TimeZoneUTCOffsetSecond, TimeZoneUTCOffsetFractionalPart, and TimeZoneIANAName productions, or undefined if not present.
auto z_part = parse_result->utc_designator;
auto sign_part = parse_result->time_zone_utc_offset_sign;
auto hours_part = parse_result->time_zone_utc_offset_hour;
auto minutes_part = parse_result->time_zone_utc_offset_minute;
auto seconds_part = parse_result->time_zone_utc_offset_second;
auto fraction_part = parse_result->time_zone_utc_offset_fractional_part;
auto name_part = parse_result->time_zone_iana_name;
// 4. Let each of z, offsetString, and name be the source text matched by the respective UTCDesignator, TimeZoneNumericUTCOffset, and TimeZoneIANAName Parse Node enclosed by parseResult, or an empty sequence of code points if not present.
auto z = parse_result->utc_designator;
auto offset_string = parse_result->time_zone_numeric_utc_offset;
auto name = parse_result->time_zone_iana_name;
// 4. If z is not undefined, then
if (z_part.has_value()) {
// a. Return the Record { [[Z]]: true, [[OffsetString]]: undefined, [[Name]]: name }.
return TemporalTimeZone { .z = true, .offset_string = {}, .name = name_part.has_value() ? String { *name_part } : Optional<String> {} };
}
Optional<String> offset_string;
// 5. If hours is undefined, then
if (!hours_part.has_value()) {
// a. Let offsetString be undefined.
// NOTE: No-op.
}
// 5. If name is empty, then
// a. Set name to undefined.
// 6. Else,
else {
// a. Assert: sign is not undefined.
VERIFY(sign_part.has_value());
// a. Set name to ! CodePointsToString(name).
// NOTE: No-op.
// b. Set hours to ! ToIntegerOrInfinity(hours).
u8 hours = *hours_part->to_uint<u8>();
i8 sign;
// c. If sign is the code unit 0x002D (HYPHEN-MINUS) or the code unit 0x2212 (MINUS SIGN), then
if (sign_part->is_one_of("-", "\u2212")) {
// i. Set sign to 1.
sign = -1;
}
// d. Else,
else {
// i. Set sign to 1.
sign = 1;
}
// e. Set minutes to ! ToIntegerOrInfinity(minutes).
u8 minutes = *minutes_part.value_or("0"sv).to_uint<u8>();
// f. Set seconds to ! ToIntegerOrInfinity(seconds).
u8 seconds = *seconds_part.value_or("0"sv).to_uint<u8>();
i32 nanoseconds;
// g. If fraction is not undefined, then
if (fraction_part.has_value()) {
// i. Set fraction to the string-concatenation of the previous value of fraction and the string "000000000".
auto fraction = String::formatted("{}000000000", *fraction_part);
// ii. Let nanoseconds be the String value equal to the substring of fraction from 1 to 10.
// iii. Set nanoseconds to ! ToIntegerOrInfinity(nanoseconds).
// FIXME: 1-10 is wrong and should be 0-9; the decimal separator is no longer present in the parsed string.
// See: https://github.com/tc39/proposal-temporal/pull/1999
nanoseconds = *fraction.substring(0, 9).to_int<i32>();
}
// h. Else,
else {
// i. Let nanoseconds be 0.
nanoseconds = 0;
}
// i. Let offsetNanoseconds be sign × (((hours × 60 + minutes) × 60 + seconds) × 10^9 + nanoseconds).
// NOTE: Decimal point in 10^9 is important, otherwise it's all integers and the result overflows!
auto offset_nanoseconds = sign * (((hours * 60 + minutes) * 60 + seconds) * 1000000000.0 + nanoseconds);
// j. Let offsetString be ! FormatTimeZoneOffsetString(offsetNanoseconds).
offset_string = format_time_zone_offset_string(offset_nanoseconds);
// 7. If z is not empty, then
if (z.has_value()) {
// a. Return the Record { [[Z]]: true, [[OffsetString]]: undefined, [[Name]]: name }.
return TemporalTimeZone { .z = true, .offset_string = {}, .name = optional_string_view_to_optional_string(name) };
}
// 7. Return the Record { [[Z]]: false, [[OffsetString]]: offsetString, [[Name]]: name }.
return TemporalTimeZone { .z = false, .offset_string = offset_string, .name = name_part.has_value() ? String { *name_part } : Optional<String> {} };
// 8. If offsetString is empty, then
// a. Set offsetString to undefined.
// 9. Else,
// a. Set offsetString to ! CodePointsToString(offsetString).
// NOTE: No-op.
// 10. Return the Record { [[Z]]: false, [[OffsetString]]: offsetString, [[Name]]: name }.
return TemporalTimeZone { .z = false, .offset_string = optional_string_view_to_optional_string(offset_string), .name = optional_string_view_to_optional_string(name) };
}
// 13.44 ParseTemporalYearMonthString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporalyearmonthstring