By default, the offset option is set to "prefer", which means we use the original offset (or that provided in info) if it's valid, and recalculate otherwise. This means if you set to another date that has a different offset due to a DST transition, the offset will be recalculated:
const zdt = Temporal.ZonedDateTime.from(
"2021-07-01T12:00:00-04:00[America/New_York]",
);
const newZDT = zdt.with({ month: 12 });
// The offset is recalculated to -05:00
console.log(newZDT.toString()); // "2021-12-01T12:00:00-05:00[America/New_York]"
And if you set the time to within the DST transition, the offset is used to resolve the ambiguity:
const zdt = Temporal.ZonedDateTime.from(
"2024-11-02T01:05:00-04:00[America/New_York]",
);
const newZDT = zdt.with({ day: 3 });
console.log(newZDT.toString()); // "2024-11-03T01:05:00-04:00[America/New_York]"
const zdt2 = Temporal.ZonedDateTime.from(
"2024-11-04T01:05:00-05:00[America/New_York]",
);
const newZDT2 = zdt2.with({ day: 3 });
console.log(newZDT2.toString()); // "2024-11-03T01:05:00-05:00[America/New_York]"
If you use offset: "use", then the offset will be used as-is to obtain the exact time first, and then recalculate the offset:
const zdt = Temporal.ZonedDateTime.from(
"2021-07-01T12:00:00-04:00[America/New_York]",
);
const newZDT = zdt.with({ month: 12 }, { offset: "use" });
// The offset is recalculated to -05:00, but the wall-clock time changes
console.log(newZDT.toString()); // "2021-12-01T11:00:00-05:00[America/New_York]"
You can also set offset: "reject" to throw an error if the original offset is invalid, forcing an explicit new offset to be specified:
const zdt = Temporal.ZonedDateTime.from(
"2021-07-01T12:00:00-04:00[America/New_York]",
);
zdt.with({ month: 12 }, { offset: "reject" });
// RangeError: date-time can't be represented in the given time zone
zdt.with({ month: 12, offset: "-05:00" }, { offset: "reject" }).toString();
// "2021-12-01T12:00:00-05:00[America/New_York]"