1
0
Fork 0
mirror of https://github.com/LadybirdBrowser/ladybird.git synced 2025-06-08 05:27:14 +09:00

LibJS: Require strict matching with a precise ZonedDateTime offset

This is a normative change in the Temporal proposal. See:
1117eaf
This commit is contained in:
Timothy Flynn 2025-06-02 10:13:05 -04:00 committed by Shannon Booth
parent f091047159
commit c8b4dc4847
Notes: github-actions[bot] 2025-06-02 21:10:33 +00:00
3 changed files with 70 additions and 6 deletions

View file

@ -630,6 +630,19 @@ ThrowCompletionOr<RelativeTo> get_temporal_relative_to_option(VM& vm, Object con
// iv. Set matchBehaviour to MATCH-MINUTES.
match_behavior = MatchBehavior::MatchMinutes;
// v. If offsetString is not EMPTY, then
if (offset_string.has_value()) {
// 1. Let offsetParseResult be ParseText(StringToCodePoints(offsetString), UTCOffset[+SubMinutePrecision]).
auto offset_parse_result = parse_utc_offset(*offset_string, SubMinutePrecision::Yes);
// 2. Assert: offsetParseResult is a Parse Node.
VERIFY(offset_parse_result.has_value());
// 3. If offsetParseResult contains more than one MinuteSecond Parse Node, set matchBehaviour to MATCH-EXACTLY.
if (offset_parse_result->seconds.has_value())
match_behavior = MatchBehavior::MatchExactly;
}
}
// g. Let calendar be result.[[Calendar]].

View file

@ -262,22 +262,35 @@ ThrowCompletionOr<GC::Ref<ZonedDateTime>> to_temporal_zoned_date_time(VM& vm, Va
// l. Set matchBehaviour to MATCH-MINUTES.
match_behavior = MatchBehavior::MatchMinutes;
// m. Let resolvedOptions be ? GetOptionsObject(options).
// m. If offsetString is not EMPTY, then
if (offset_string.has_value()) {
// i. Let offsetParseResult be ParseText(StringToCodePoints(offsetString), UTCOffset[+SubMinutePrecision]).
auto offset_parse_result = parse_utc_offset(*offset_string, SubMinutePrecision::Yes);
// ii. Assert: offsetParseResult is a Parse Node.
VERIFY(offset_parse_result.has_value());
// iii. If offsetParseResult contains more than one MinuteSecond Parse Node, set matchBehaviour to MATCH-EXACTLY.
if (offset_parse_result->seconds.has_value())
match_behavior = MatchBehavior::MatchExactly;
}
// n. Let resolvedOptions be ? GetOptionsObject(options).
auto resolved_options = TRY(get_options_object(vm, options));
// n. Let disambiguation be ? GetTemporalDisambiguationOption(resolvedOptions).
// o. Let disambiguation be ? GetTemporalDisambiguationOption(resolvedOptions).
disambiguation = TRY(get_temporal_disambiguation_option(vm, resolved_options));
// o. Let offsetOption be ? GetTemporalOffsetOption(resolvedOptions, REJECT).
// p. Let offsetOption be ? GetTemporalOffsetOption(resolvedOptions, REJECT).
offset_option = TRY(get_temporal_offset_option(vm, resolved_options, OffsetOption::Reject));
// p. Perform ? GetTemporalOverflowOption(resolvedOptions).
// q. Perform ? GetTemporalOverflowOption(resolvedOptions).
TRY(get_temporal_overflow_option(vm, resolved_options));
// q. Let isoDate be CreateISODateRecord(result.[[Year]], result.[[Month]], result.[[Day]]).
// r. Let isoDate be CreateISODateRecord(result.[[Year]], result.[[Month]], result.[[Day]]).
iso_date = create_iso_date_record(*result.year, result.month, result.day);
// r. Let time be result.[[Time]].
// s. Let time be result.[[Time]].
time = result.time;
}

View file

@ -67,6 +67,21 @@ describe("correct behavior", () => {
});
expect(result).toBe(-1);
});
test("sub-minute time zone offset", () => {
const duration1 = new Temporal.Duration(0, 0, 0, 31);
const duration2 = new Temporal.Duration(0, 1);
let result = Temporal.Duration.compare(duration1, duration2, {
relativeTo: "1970-01-01T00:00:00-00:45[Africa/Monrovia]",
});
expect(result).toBe(0);
result = Temporal.Duration.compare(duration1, duration2, {
relativeTo: "1970-01-01T00:00:00-00:44:30[Africa/Monrovia]",
});
expect(result).toBe(0);
});
});
describe("errors", () => {
@ -132,4 +147,27 @@ describe("errors", () => {
"A starting point is required for comparing calendar units"
);
});
test("sub-minute time zone offset mismatch", () => {
const duration1 = new Temporal.Duration(0, 0, 0, 31);
const duration2 = new Temporal.Duration(0, 1);
expect(() => {
Temporal.Duration.compare(duration1, duration2, {
relativeTo: "1970-01-01T00:00:00-00:44:40[Africa/Monrovia]",
});
}).toThrowWithMessage(
RangeError,
"Invalid offset for the provided date and time in the current time zone"
);
expect(() => {
Temporal.Duration.compare(duration1, duration2, {
relativeTo: "1970-01-01T00:00:00-00:45:00[Africa/Monrovia]",
});
}).toThrowWithMessage(
RangeError,
"Invalid offset for the provided date and time in the current time zone"
);
});
});