A common date/time use-case is to change some units in a Date but not others. For example:
How would you do these cases with Temporal?
Doing this with Date today has a few problems:
Date if you only want to change one field because you have to call 7 different Date methods to change one unit value.Date.setMonth(3, 31) then I'll end up with May 1 not April 30 as expected.Date is the instant that DST ends, then you'll end up with a one-hour-earlier local time in the new Date, because of this behavior (from https://tc39.es/ecma262/#sec-local-time-zone-adjustment): When
tlocalrepresents local time repeating multiple times at a negative time zone transition (e.g. when the daylight saving time ends or the time zone offset is decreased due to a time zone rule change) or skipped local time at a positive time zone transitions (e.g. when the daylight saving time starts or the time zone offset is increased due to a time zone rule change),tlocalmust be interpreted using the time zone offset before the transition.
IMHO the ideal API (on DateTime, Absolute, Time, etc) would be similar to constructing a Duration: you'd pass a parameter containing units e.g. {day: 20, month: 7} or {minutes: 0, seconds: 0}) and optionally indicate how you'd want to handle day-of-month overflow.
Does such an API exist already? I didn't see one in the docs but I know docs might be out of date.
Here's another possible zero-work API. Is object spread supposed to work?
const dt = new Temporal.Date(2020, 3, 14)
const dt2 = new Temporal.Date({...someDateTime, day: 1});
Spread doesn't work, no, but have you seen with()?
const dt = new Temporal.Date(2020, 3, 14)
const dt2 = dt1.with({ day: 1 }); // 2020-03-01
@justingrant @Ms2ger also, getFields should work with object spread and any similar operations.
const dt = new Temporal.Date(2020, 3, 14)
const dt2 = Temporal.Date.from({...dt.getFields(), day: 1});
I think we should add these use cases to the cookbook but I'll take an initial stab at them here:
time.with({minute: 0, second: 0, millisecond: 0, microsecond: 0, nanosecond: 0})
// or
Temporal.Time.from({ hour: time.hour })
date.withTime(Temporal.Time.from({ hour: 12 })
// or
date.withTime(Temporal.Time.from('12:00'))
const date = Temporal.now.date();
date.with({ month: date.month + 1, day: 3 }, { disambiguation: 'balance' })
// or
date.plus({ months: 1 }).with({ day: 3 })
const birthday = Temporal.MonthDay.from('12-15');
birthday.withYear(2030)
dateTime.with({ month: 2 })
// could add { disambiguation: 'constrain' } for clarity, but it's the default
dateTime.with({ month: 4 }, { disambiguation: 'reject' })
// I did have to double-check this one because I wasn't sure if it'd work! but it does
Temporal.now.date().with({ day: 31 })
// here again { disambiguation: 'constrain' } is implied
Temporal.now.date().with({ day: 18 }).withTime(Temporal.Time.from('20:00'))
Ahhh, with was what I was looking for. That API looks great-- nice DX.
I'll get these examples added to the cookbook, then.
Most helpful comment
Spread doesn't work, no, but have you seen
with()?