feat: implement precise Temporal Instant arithmetic

This commit is contained in:
爱特每羊队
2026-08-11 15:55:05 +08:00
parent 4c42112c51
commit 756d6b8e1b
3 changed files with 120 additions and 23 deletions
@@ -86,7 +86,9 @@ pub fn bind_temporal(core: &Arc<KernelCore>, session: &KernelSession, global: &m
instant_proto,
core,
&[
("add", oxide_builtins::temporal::instant_add::<crate::vm::Vm> as *const (), 1),
("equals", oxide_builtins::temporal::instant_equals::<crate::vm::Vm> as *const (), 1),
("subtract", oxide_builtins::temporal::instant_subtract::<crate::vm::Vm> as *const (), 1),
("toString", oxide_builtins::temporal::instant_to_string::<crate::vm::Vm> as *const (), 0),
("valueOf", oxide_builtins::temporal::instant_value_of::<crate::vm::Vm> as *const (), 0),
],
@@ -141,6 +141,45 @@ fn instant_compare_accepts_instances_strings_and_annotations() {
assert!(r.as_bool());
}
#[test]
fn instant_add_and_subtract_are_exact() {
let mut vm = Vm::new();
let r = eval(
&mut vm,
"let i = Temporal.Instant.fromEpochNanoseconds(1582966647747612578n);
i.add({hours: 1, microseconds: 9007199254740991}).epochNanoseconds === 10590169502488603578n
&& i.subtract('PT1.03125H').epochNanoseconds === 1582962935247612578n",
)
.unwrap();
assert!(r.as_bool());
}
#[test]
fn instant_add_ignores_receiver_subclass_for_result() {
let mut vm = Vm::new();
let r = eval(
&mut vm,
"class Sub extends Temporal.Instant { constructor(value) { super(value); } }
let result = new Sub(10n).add({nanoseconds: 5});
result instanceof Temporal.Instant && !(result instanceof Sub) && result.epochNanoseconds === 15n",
)
.unwrap();
assert!(r.as_bool());
}
#[test]
fn instant_arithmetic_rejects_date_units_and_out_of_range_results() {
let mut vm = Vm::new();
let r = eval(
&mut vm,
"let max = Temporal.Instant.fromEpochNanoseconds(8640000000000000000000n);
(() => { try { max.add({nanoseconds: 1}); return false } catch (e) { return e instanceof RangeError } })()
&& (() => { try { max.subtract({days: 1}); return false } catch (e) { return e instanceof RangeError } })()",
)
.unwrap();
assert!(r.as_bool());
}
#[test]
fn instant_epoch_factories_validate_input_and_range() {
let mut vm = Vm::new();