fix: 袋支 calendar 未提供时不再误读 era/eraYear

This commit is contained in:
2026-09-28 16:43:35 +00:00
parent 6c7d7f3ffc
commit 597f11e802
2 changed files with 48 additions and 1 deletions
@@ -410,7 +410,8 @@ fn duration_relative_to_date<H: VmHost>(vm: &mut H, relative_raw: JsValue) -> Re
// calendar 经宽松版接受:白名单/ISO 串(非法 RangeError)、Temporal 实例读日历槽、其余 TypeError。
let calendar_raw = temporal_option_value(vm, obj, relative_raw, "calendar")?;
let calendar = temporal_calendar_id(vm, calendar_raw)?;
let non_iso_calendar = calendar.as_deref() != Some("iso8601");
// calendar 未提供(undefined)时默认 iso8601,era/eraYear 不读;仅具体非 iso8601 日历才读。
let non_iso_calendar = calendar.as_deref().map(|c| c != "iso8601").unwrap_or(false);
let day_raw = temporal_option_value(vm, obj, relative_raw, "day")?;
let day = bag_number_field(vm, day_raw)?;
@@ -4004,6 +4004,52 @@ fn relativeto_bag_era_merge() {
assert_eq!(str_val(&vm, r), "ok|ok|ok|ok|RangeError|RangeError|TypeError|TypeError");
}
#[test]
fn relativeto_bag_era_gate_calendar_default() {
let mut vm = Vm::new();
// era/eraYear 读取门:calendar 未提供(默认 iso8601)时 era/eraYear 不读不合并,
// 缺 year 按 iso8601 语义抛 TypeError「year is required」;同袋带 year 时 era/eraYear
// 被忽略取 year;calendar 为具体非 iso8601(gregory)时读取并合并。
let r = eval(
&mut vm,
"(() => {
const kind = (fn) => { try { fn(); return 'ok'; } catch (e) { return e.constructor.name + ':' + e.message; } };
const d = new Temporal.Duration(1, 0, 0, 0, 24);
const round = (rel) => d.round({ largestUnit: 'years', relativeTo: rel });
return [
kind(() => round({ month: 5, day: 2, era: 'ad', eraYear: 2020 })),
kind(() => round({ year: 2020, month: 5, day: 2, era: 'ad', eraYear: 2021 })),
kind(() => round({ month: 5, day: 2, calendar: 'gregory', era: 'ad', eraYear: 2020 })),
kind(() => round({ year: 2020, month: 5, day: 2, calendar: 'gregory', era: 'ad', eraYear: 2020 })),
].join('|');
})()",
)
.unwrap();
assert_eq!(str_val(&vm, r), "TypeError:year is required|ok|ok|ok");
}
#[test]
fn relativeto_bag_read_order_no_calendar_skips_era() {
let mut vm = Vm::new();
// 读序门:calendar 未提供(默认 iso8601)时 era/eraYear 不进读序,
// 与 iso8601 袋读序一致;若误读 era/eraYear,序中会出现 era,eraYear。
let r = eval(
&mut vm,
"(() => {
const order = [];
const values = { day: 2, era: 'ad', eraYear: 2020, month: 5, year: 2020 };
const rel = {};
for (const k of Object.keys(values)) {
Object.defineProperty(rel, k, { get() { order.push(k); return values[k]; }, configurable: true });
}
Temporal.Duration.compare(new Temporal.Duration(1), new Temporal.Duration(0), { relativeTo: rel });
return order.join(',');
})()",
)
.unwrap();
assert_eq!(str_val(&vm, r), "day,month,year");
}
#[test]
fn relativeto_bag_read_order_calendar_first_dictionary() {
let mut vm = Vm::new();