Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
71046d0
Add InternalDuration class for Temporal support
catamorphism Apr 11, 2025
656e2e3
Define InternalDuration::sign()
catamorphism Apr 14, 2025
aed29bd
Comments
catamorphism Apr 14, 2025
77ba1d9
Temporal: Implement ExactTime::round() according to the spec
catamorphism Apr 11, 2025
9fc4bec
Part 3: Refactor implementation of TemporalPlainDate/prototype/add
catamorphism Apr 12, 2025
c1f1267
Part 4: Make ExactTime::difference() return an InternalDuration
catamorphism Apr 12, 2025
a851754
Part 5: Move make{Date, Time, Day} into header file
catamorphism Apr 14, 2025
567ed8f
Part 6: Implement TemporalDuration::compare() according to the spec
catamorphism Apr 14, 2025
0610ede
Part 7: Reimplement TemporalPlainTime::since() and TemporalPlainTime:…
catamorphism Apr 14, 2025
7d35839
Part 8: Reimplement TemporalDuration::total() according to the spec
catamorphism Apr 14, 2025
da3f892
Part 9: Implement TemporalDuration::subtract() according to spec
catamorphism Apr 14, 2025
d1dd8c0
Part 10: Add roundRelativeDuration()
catamorphism Apr 15, 2025
cc8fa9c
Part 11: Implement TemporalCalendar/p/add and TemporalDuration/p/add …
catamorphism Apr 17, 2025
e593a06
Part 12: Remove isoDateDifference() and use calendarDateUntil() instead
catamorphism Apr 17, 2025
60c2c74
Part 13: Implement TemporalDuration::round() according to the spec
catamorphism Apr 17, 2025
331c0e9
Part 14: Unskip some RegExp test262 tests
catamorphism Apr 14, 2025
bbad910
Temporal: Part 1: Add {PlainDate, PlainDateTime}::calendarId
catamorphism Apr 25, 2025
0586065
Temporal: Part 2: Add PlainMonthDay
catamorphism Apr 24, 2025
9bcac19
Temporal: Part 3: Add PlainMonthDay::{toString, toJSON, toLocaleString}
catamorphism Apr 23, 2025
d3792df
Temporal: Part 4: Add PlainMonthDay::with()
catamorphism Apr 23, 2025
e9f94b9
Temporal: Part 5: Add PlainMonthDay::equals()
catamorphism Apr 23, 2025
eb69e6b
Temporal: Part 6: Add PlainMonthDay::toPlainDate()
catamorphism Apr 23, 2025
be9ed43
Temporal: Part 7: Add PlainMonthDay:valueOf()
catamorphism Apr 24, 2025
4723058
Temporal: Part 8: Add PlainYearMonth
catamorphism Apr 24, 2025
78954f0
Temporal: Part 9: Add PlainYearMonth::{toString, toJSON, toLocaleString}
catamorphism Apr 24, 2025
d62366a
Temporal: Part 10: Add PlainYearMonth::from()
catamorphism Apr 24, 2025
b6eb8e4
Temporal: Part 11: Add PlainYearMonth::{compare(), equals(), valueOf()}
catamorphism Apr 25, 2025
cc351a9
Temporal: Part 12: Add PlainYearMonth::with()
catamorphism Apr 24, 2025
f6c2f0e
Temporal: Part 13: Add PlainYearMonth::toPlainDate()
catamorphism Apr 24, 2025
aaefb88
Temporal: Part 14: Add PlainYearMonth::{add, subtract}
catamorphism Apr 24, 2025
4ae1348
Temporal: Part 15: Add PlainYearMonth::{since, until}
catamorphism Apr 24, 2025
6ce62ed
Temporal: Part 16: Add PlainDate::{toPlainMonthDay,toPlainYearMonth}
catamorphism Apr 25, 2025
b87ab47
Temporal: Part 17: Fix order of operations in TemporalPlainTime::from()
catamorphism Apr 24, 2025
cf94c76
Part 19: Can this be dropped?
catamorphism Apr 24, 2025
fbc1fb8
Fix rebasing issues
catamorphism Mar 5, 2025
7a10316
Fix style error
catamorphism Mar 5, 2025
d5f8ffa
Cherry-pick 93c325b5cb99. https://bugs.webkit.org/show_bug.cgi?id=223166
catamorphism Nov 20, 2024
145c8a0
Fix style errors
catamorphism Nov 29, 2024
03c3ec0
Cleanup
catamorphism Nov 29, 2024
146e57a
Fix rebasing issues
catamorphism Mar 5, 2025
5f2b332
Cherry-pick 93c325b5cb99. https://bugs.webkit.org/show_bug.cgi?id=223166
catamorphism Nov 20, 2024
0d92dde
Fix style errors
catamorphism Nov 29, 2024
c55fa94
WIP
catamorphism Nov 30, 2024
d73adab
WIP
catamorphism Dec 3, 2024
5b9213f
WIP
catamorphism Dec 4, 2024
6116572
WIP
catamorphism Dec 4, 2024
32a9823
WIP - code compiles, not tested
catamorphism Dec 5, 2024
0097eb9
Add exception checks
catamorphism Dec 5, 2024
49b5f2a
Fix TemporalTimeZone::from()
catamorphism Dec 5, 2024
af5e3b7
WIP - stress tests pass. Fixed balanceTime bug
catamorphism Dec 6, 2024
d470f03
WIP
catamorphism Dec 11, 2024
cc08908
WIP
catamorphism Dec 11, 2024
46a1176
WIP
catamorphism Dec 12, 2024
814185a
WIP
catamorphism Dec 12, 2024
894d642
WIP
catamorphism Dec 13, 2024
f4455fb
WIP
catamorphism Dec 14, 2024
37038e4
WIP
catamorphism Dec 17, 2024
6d5ce5e
WIP
catamorphism Dec 20, 2024
9487157
WIP
catamorphism Dec 31, 2024
3d65e49
WIP
catamorphism Jan 3, 2025
95f7e38
WIP - all test262 tests now pass except for intl402 tests
catamorphism Jan 3, 2025
0f68f18
Fix formatOffsetTimeZoneIdentifier
catamorphism Jan 4, 2025
e01eb08
Change TimeZone methods; comments
catamorphism Jan 4, 2025
ce68294
Update expectations.yaml
catamorphism Jan 4, 2025
4d51d57
Fix TemporalPlainTime order-of-operations code; refactor, moving some…
catamorphism Jan 7, 2025
d93c208
Update expectations
catamorphism Jan 7, 2025
4ebcfad
Update config.yaml; add cases to TemporalCalendar::from, add ZonedDat…
catamorphism Jan 7, 2025
c055a2d
Refactor TimeZoneRecord
catamorphism Jan 7, 2025
73ae734
Fix up Int128 literals
catamorphism Jan 7, 2025
c280f0a
Formatting
catamorphism Jan 7, 2025
5a4b16d
Define ISO8601::PlainDateTime and use it instead of tuples
catamorphism Jan 8, 2025
f0ad1f8
Refactor
catamorphism Jan 9, 2025
df7efc3
Move some functions to different files
catamorphism Jan 9, 2025
e809d42
Move more functions to different files
catamorphism Jan 9, 2025
b91de5e
Move combineISODateAndTimeRecord()
catamorphism Jan 9, 2025
d48470d
Fix style errors
catamorphism Jan 9, 2025
f388c90
Reorganize more methods
catamorphism Jan 10, 2025
4e124b8
Fix rebasing issues
catamorphism Mar 7, 2025
d7e7818
Fix style errors
catamorphism Mar 7, 2025
c08188d
Fix MacOS build
Mar 7, 2025
ed15e49
Fix style error
catamorphism Mar 7, 2025
1ae17a4
Fix arm build errors
catamorphism Mar 10, 2025
7968204
Fix loss of precision in totalTimeDuration()
catamorphism Mar 10, 2025
c2ddd3d
Fix ambiguous overloading in totalTimeDuration()
catamorphism Mar 10, 2025
c40fa50
Implement TemporalInstant::toZonedDateTimeISO()
catamorphism Mar 11, 2025
6ce64cd
Implement Temporal::Now::plain{Date,DateTime,Time}ISO()
catamorphism Mar 11, 2025
8d296e6
Implement Temporal::Now::zonedDateTimeISO()
catamorphism Mar 11, 2025
a26c550
Implement TemporalPlainDate::toZonedDateTime()
catamorphism Mar 11, 2025
3677c33
Un-ignore PlainDateTime/prototype/toZonedDateTime tests
catamorphism Mar 11, 2025
7295d70
Implement PlainDateTime/prototype/{since, until}
catamorphism Mar 11, 2025
2f9063e
Fix Temporal.Instant.toString
catamorphism Mar 13, 2025
752bd4f
Fix rebasing issues
catamorphism May 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions JSTests/stress/temporal-duration.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ shouldBe(Temporal.Duration.compare(posAbsolute, posAbsolute), 0);
shouldBe(Temporal.Duration.compare(posAbsolute, zero), 1);
shouldBe(Temporal.Duration.compare(zero, posAbsolute), -1);
shouldBe(Temporal.Duration.compare('PT86400S', 'P1D'), 0);
shouldBe(Temporal.Duration.compare({ days: 200 }, { days: 200, nanoseconds: 1 }), -1);

shouldBe(Temporal.Duration.prototype.with.length, 1);
shouldThrow(() => Temporal.Duration.prototype.with.call({}, { years: 1 }), TypeError);
Expand Down Expand Up @@ -188,6 +189,11 @@ for (const method of ['add', 'subtract']) {
}
shouldBe(Temporal.Duration.from('P1DT13H31M31S').add('P1DT13H31M31S').toString(), 'P3DT3H3M2S');
shouldBe(Temporal.Duration.from('-PT1M59S').subtract('PT1M59S').toString(), '-PT3M58S');
const duration1 = Temporal.Duration.from({microseconds: Number.MAX_SAFE_INTEGER + 1, nanoseconds: 0});
const duration2 = Temporal.Duration.from({microseconds: -1, nanoseconds: -1000});
shouldBe(duration1.subtract(duration2).toString(), 'PT9007199254.740994S');
// Addition exceeds max duration
shouldThrow(() => (new Temporal.Duration(0, 0, 0, 2, 0, 0, 0, 0, 0, 0)).add({ days: 104249991373 }), RangeError);

shouldBe(Temporal.Duration.prototype.round.length, 1);
shouldThrow(() => Temporal.Duration.prototype.round.call({}), TypeError);
Expand Down Expand Up @@ -220,6 +226,19 @@ shouldBe(Temporal.Duration.from('-PT31S').round({ smallestUnit: 'second', roundi
shouldBe(Temporal.Duration.from('-PT31S').round({ smallestUnit: 'second', roundingIncrement: 30, roundingMode: 'floor' }).toString(), '-PT60S');
shouldBe(Temporal.Duration.from('-PT45S').round({ smallestUnit: 'second', roundingIncrement: 30 }).toString(), '-PT60S');
shouldBe(Temporal.Duration.from('-PT45S').round({ smallestUnit: 'second', roundingIncrement: 30, roundingMode: 'trunc' }).toString(), '-PT30S');
// Rounding would exceed maxTimeDuration
shouldThrow(() => Temporal.Duration.from({ seconds: Number.MAX_SAFE_INTEGER }).round({ smallestUnit: 'seconds', roundingMode: 'ceil', roundingIncrement: 30 }), RangeError);

const seconds = 8692288669465520;
const nanoseconds = 321_414_345;
const d = new Temporal.Duration(0, 0, 0, 0, 0, 0, seconds, 0, 0, nanoseconds);
const result = d.round({ largestUnit: "nanoseconds" });
const expectedNanoseconds = Number(BigInt(seconds) * 1_000_000_000n + BigInt(nanoseconds));
shouldBe(expectedNanoseconds, 8692288669465520_321_414_345);
shouldBe(result.nanoseconds, expectedNanoseconds);

// Rounding would exceed maxTimeDuration
shouldThrow(() => Temporal.Duration.from({ seconds: Number.MAX_SAFE_INTEGER }).round({ smallestUnit: 'seconds', roundingMode: 'ceil', roundingIncrement: 30 }), RangeError);

shouldBe(Temporal.Duration.prototype.total.length, 1);
shouldThrow(() => Temporal.Duration.prototype.total.call({}), TypeError);
Expand All @@ -239,6 +258,10 @@ shouldBe(posAbsolute.total({ unit: 'milliseconds' }), 93784005.006007);
shouldBe(posAbsolute.total({ unit: 'microseconds' }), 93784005006.007);
shouldBe(posAbsolute.total({ unit: 'nanoseconds' }), 93784005006007);
shouldBe(Temporal.Duration.from('-PT123456789S').total({ unit: 'day' }), -1428.8980208333332);
const posSubseconds = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 999, 999999, 999999999);
const negSubseconds = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, -999, -999999, -999999999);
shouldBe(posSubseconds.total("seconds"), 2.998998999);
shouldBe(negSubseconds.total("seconds"), -2.998998999);

// At present, toLocaleString has the same behavior as toJSON or argumentless toString.
for (const method of ['toString', 'toJSON', 'toLocaleString']) {
Expand Down Expand Up @@ -291,5 +314,8 @@ shouldBe(pos.toString({ fractionalSecondDigits: 7, roundingMode: 'ceil' }), 'P1Y
shouldBe(pos.toString({ fractionalSecondDigits: 2, roundingMode: 'floor' }), 'P1Y2M3W4DT5H6M7.00S');
shouldBe(pos.toString({ fractionalSecondDigits: 2, roundingMode: 'halfExpand' }), 'P1Y2M3W4DT5H6M7.01S');

const maxSeconds = Temporal.Duration.from({ seconds: Number.MAX_SAFE_INTEGER, milliseconds: 999 });
shouldThrow(() => maxSeconds.toString({ smallestUnit: "seconds", roundingMode: "ceil" }), RangeError);

shouldBe(Temporal.Duration.prototype.valueOf.length, 0);
shouldThrow(() => new Temporal.Duration().valueOf(), TypeError);
22 changes: 22 additions & 0 deletions JSTests/stress/temporal-instant.js
Original file line number Diff line number Diff line change
Expand Up @@ -408,3 +408,25 @@ const maxValue = new Temporal.Instant(86400_0000_0000_000_000_000n);
shouldThrow(() => epoch.subtract({ [unit]: -Number.MAX_VALUE }), RangeError);
});
}

// since() and until()
{
const earlier = Temporal.Instant.from("1976-11-18T15:23:30.123456789Z");
const later = Temporal.Instant.from("2019-10-29T10:46:38.271986102Z");
const diff = later.since(earlier);
shouldBe(diff.nanoseconds, 313);
shouldBe(diff.microseconds, 529);
shouldBe(diff.milliseconds, 148);
shouldBe(diff.seconds, 1355167388);
const diff1 = earlier.until(later);
shouldBe(diff1.nanoseconds, diff.nanoseconds);
shouldBe(diff1.microseconds, diff.microseconds);
shouldBe(diff1.milliseconds, diff.milliseconds);
shouldBe(diff1.seconds, diff.seconds);
}

// round()
{
const pos = new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 999, 999999, 999999999);
shouldBe(pos.round({ largestUnit: "seconds" }).seconds, 2);
}
18 changes: 18 additions & 0 deletions JSTests/stress/temporal-plaindate.js
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,25 @@ shouldBe(Temporal.PlainDate.prototype.until.length, 1);
shouldBe(date.since('2020-02-12', { largestUnit: 'week' }).toString(), 'P2W2D');
shouldBe(date.until('2020-02-12', { largestUnit: 'week' }).toString(), '-P2W2D');

const earlier = Temporal.PlainDate.from("2019-01-08");
const later = Temporal.PlainDate.from("2021-09-07");
shouldBe(later.since(earlier, { smallestUnit: "years", roundingIncrement: 4, roundingMode: "halfExpand" }).toString(), "P4Y");
shouldBe(earlier.until(later, { smallestUnit: "years", roundingIncrement: 4, roundingMode: "halfExpand" }).toString(), "P4Y");

shouldThrow(() => { date.until('2019-02-28', { smallestUnit: 'hour' }); }, RangeError);
shouldThrow(() => { date.until('2019-02-28', { largestUnit: 'hour' }); }, RangeError);
shouldThrow(() => { date.until('2019-02-28', { largestUnit: 'day', smallestUnit: 'month' }); }, RangeError);
}

{
shouldBe(new Temporal.PlainDate(2000, 5, 2, "iso8601").calendarId, "iso8601");
}

shouldBe(Temporal.PlainDate.prototype.toPlainMonthDay.length, 0);
shouldBe(Temporal.PlainDate.prototype.toPlainYearMonth.length, 0);
{
const date = Temporal.PlainDate.from('2020-02-28');

shouldBe(date.toPlainMonthDay().toString(), '02-28');
shouldBe(date.toPlainYearMonth().toString(), '2020-02');
}
116 changes: 116 additions & 0 deletions JSTests/stress/temporal-plainmonthday.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//@ requireOptions("--useTemporal=1")

function shouldBe(actual, expected) {
if (actual !== expected)
throw new Error(`expected ${expected} but got ${actual}`);
}

function shouldThrow(func, errorType, message) {
let error;
try {
func();
} catch (e) {
error = e;
}

if (!(error instanceof errorType))
throw new Error(`Expected ${errorType.name}!`);
if (message !== undefined)
shouldBe(String(error), message);
}

shouldBe(Temporal.PlainMonthDay instanceof Function, true);
shouldBe(Temporal.PlainMonthDay.length, 2);
shouldBe(Object.getOwnPropertyDescriptor(Temporal.PlainMonthDay, 'prototype').writable, false);
shouldBe(Object.getOwnPropertyDescriptor(Temporal.PlainMonthDay, 'prototype').enumerable, false);
shouldBe(Object.getOwnPropertyDescriptor(Temporal.PlainMonthDay, 'prototype').configurable, false);
shouldBe(Temporal.PlainMonthDay.prototype.constructor, Temporal.PlainMonthDay);

const monthDay = new Temporal.PlainMonthDay(4, 29);

{
shouldBe(monthDay.monthCode, "M04");
shouldBe(monthDay.day, 29);
shouldBe(monthDay.year, undefined);
shouldBe(monthDay.calendarId, "iso8601");

shouldThrow(() => new Temporal.PlainMonthDay(20, 1), RangeError);
shouldThrow(() => new Temporal.PlainMonthDay(1, 40), RangeError);
}

{
shouldBe(monthDay.toString(), '04-29');
shouldBe(monthDay.toJSON(), monthDay.toString());
shouldBe(monthDay.toLocaleString(), monthDay.toString());
}

shouldBe(Temporal.PlainMonthDay.prototype.with.length, 1);
{
shouldBe(monthDay.with({ year: 2021, month: 3, day: 5 }).toString(), '03-05');
shouldBe(monthDay.with({ month: 3, day: 5 }).toString(), '03-05');
shouldBe(monthDay.with({ month: 3 }).toString(), '03-29');
shouldBe(monthDay.with({ day: 5 }).toString(), '04-05');

shouldBe(monthDay.with({ day: 31 }).toString(), '04-30');
shouldThrow(() => { monthDay.with({ day: 31 }, { overflow: 'reject' }); }, RangeError);
}

{
shouldBe(String(Temporal.PlainMonthDay.from('2007-01-09')), `01-09`);
shouldBe(String(Temporal.PlainMonthDay.from('2007-01-09T03:24:30')), `01-09`);
shouldBe(String(Temporal.PlainMonthDay.from('2007-01-09t03:24:30')), `01-09`);
shouldBe(String(Temporal.PlainMonthDay.from('2007-01-09 03:24:30')), `01-09`);
shouldBe(String(Temporal.PlainMonthDay.from('2007-01-09T03:24:30+20:20:59')), `01-09`);
shouldBe(String(Temporal.PlainMonthDay.from('2007-01-09T03:24:30-20:20:59')), `01-09`);
shouldBe(String(Temporal.PlainMonthDay.from('2007-01-09T03:24:30+10')), `01-09`);
shouldBe(String(Temporal.PlainMonthDay.from('2007-01-09T03:24:30+1020')), `01-09`);
shouldBe(String(Temporal.PlainMonthDay.from('2007-01-09T03:24:30+102030')), `01-09`);
shouldBe(String(Temporal.PlainMonthDay.from('2007-01-09T03:24:30+10:20:30.05')), `01-09`);
shouldBe(String(Temporal.PlainMonthDay.from('2007-01-09T03:24:30+10:20:30.123456789')), `01-09`);
shouldBe(String(Temporal.PlainMonthDay.from('2007-01-09T03:24:30+01:00[Europe/Brussels]')), `01-09`);
shouldBe(String(Temporal.PlainMonthDay.from('2007-01-09 03:24:30+01:00[Europe/Brussels]')), `01-09`);

let monthDay1 = Temporal.PlainMonthDay.from('2007-04-29T03:24:30+01:00[Europe/Brussels]');
shouldBe(monthDay1 === Temporal.PlainMonthDay.from(monthDay1), false);
shouldBe(monthDay1.toString(), Temporal.PlainMonthDay.from(monthDay1).toString());

shouldBe(Temporal.PlainMonthDay.from({ year: 2007, month: 4, day: 29 }).toString(), monthDay.toString());
shouldBe(Temporal.PlainMonthDay.from({ year: 2007, monthCode: 'M04', day: 29 }).toString(), monthDay.toString());

shouldBe(Temporal.PlainMonthDay.from({ year: 2007, month: 20, day: 40 }).toString(), '12-31');
shouldThrow(() => Temporal.PlainMonthDay.from({ year: 2007, month: 20, day: 40 }, { overflow: 'reject' }), RangeError);

shouldBe(Temporal.PlainMonthDay.from({ month: 4, day: 29 }).toString(), monthDay.toString());
shouldBe(Temporal.PlainMonthDay.from({ monthCode: 'M04', day: 29 }).toString(), monthDay.toString());

shouldThrow(() => { Temporal.PlainMonthDay.from({ year: 2007, day: 9 }); }, TypeError);
shouldThrow(() => { Temporal.PlainMonthDay.from({ year: 2007, month: 1 }); }, TypeError);
shouldThrow(() => { Temporal.PlainMonthDay.from({ month: Infinity, day: 9 }); }, RangeError);
shouldThrow(() => { Temporal.PlainMonthDay.from({ month: 0, day: 9 }); }, RangeError);
shouldThrow(() => { Temporal.PlainMonthDay.from({ monthCode: 'M00', day: 9 }); }, RangeError);
shouldThrow(() => { Temporal.PlainMonthDay.from({ month: 1, day: 0 }); }, RangeError);
shouldThrow(() => { Temporal.PlainMonthDay.from({ month: 1, monthCode: 'M02', day: 9 }); }, RangeError);
}

shouldBe(Temporal.PlainMonthDay.prototype.equals.length, 1);
{
const ones = new Temporal.PlainMonthDay(1,1);
shouldBe(ones.equals(new Temporal.PlainMonthDay(1,1)), true);
shouldBe(ones.equals(new Temporal.PlainMonthDay(2,1)), false);
shouldBe(ones.equals(new Temporal.PlainMonthDay(1,2)), false);
}

shouldBe(Temporal.PlainMonthDay.prototype.toPlainDate.length, 1);
{
shouldBe(monthDay.toPlainDate({ year: 2025 }).toString(), "2025-04-29");
shouldThrow(() => monthDay.toPlainDate({ notYear: 'whatever' }), TypeError);
const leapDay = new Temporal.PlainMonthDay(2, 29);
shouldBe(leapDay.toPlainDate({ year: 2020 }).toString(), "2020-02-29");
shouldBe(leapDay.toPlainDate({ year: 2025 }).toString(), "2025-02-28");

}

shouldBe(Temporal.PlainMonthDay.prototype.valueOf.length, 0);
{
shouldThrow(() => monthDay.valueOf(), TypeError);
}
Loading