MonthDay.prootype.toDate. This issue is an attempt to roll up these issues into a concise list and to propose a solution those challenges. It also made sense to roll #592 into this proposal. TL;DR - this issue contains the parts of #747 and #592 that are unrelated to method names.year and era.absolute.toLocalDateTime(timeZone, calendar), monthDay.toDate(year, era), date.toLocalDateTime(timeZone, time)date.toDateTime('10:00'). See #592.toDate methods but also probably applies to toDateTime and toLocalDateTime to a lesser extent.Did I miss any?
Here's a proposal to address (a)-(f) above while not interfering with any solution we choose for (g).
from works. The property bag syntax supports (b).from method of the type that's being added. This supports (d). It also prevents the confusion in (a) because numeric scalars aren't passable to from of any Temporal type.with of the target type. This avoids (c). Date.prototype.toLocalDateTime), then a string is accepted and will be used for the required parameter only. If multiple parameters are required (e.g. Absolute.prototype.toLocalDateTime), then only the property-bag syntax is allowed. from. with would accept the exact same property bags that conversion methods do, which would make it easier to refactor property-bag-using code.'Europe/Paris' or 'iso8601' directly as parameters. This might be a net benefit to avoid typos, but I'm not sure users will see it that way. Examples:
// self-describing
monthDay.toDate({year: 2020});
// destructuring FTW
const {year, era} = jpnDate;
monthDay.toDate({year, era});
// can use whatever style is most convenient
date.toDateTime(time);
date.toDateTime('10:00');
date.toDateTime({hour: 10});
// 2 required parameters, so object bag required
absolute.toLocalDateTime({timeZone: 'America/Los_Angeles', calendar: 'iso8601'});
// various ways to re-use existing data
const {timeZone, calendar} = someTemplateObject;
absolute.toLocalDateTime({timeZone, calendar});
const reusable = {timeZone, calendar};
abs1.toLocalDateTime(reusable);
abs2.toLocalDateTime(reusable);
abs3.toLocalDateTime(reusable);
date.toLocalDateTime('America/Los_Angeles');
const template = date.toLocalDateTime({time: '10:00', timeZone: 'America/Los_Angeles'}); // not ergonomic!
const time = Temporal.now.time();
date.toLocalDateTime({time, timeZone: template.timeZone});
The biggest downside I see with this pattern is that it makes absolute.toLocalDateTime less ergonomic in the case where it's only being called once and literals are being used for the timezone or calendar. On the other hand, if it will be called multiple times with the same time zone and calendar, then the proposed pattern may be _more_ ergonomic because the same property bag can be re-used without the weird code of spreading a 2-element array. Also, if variables are used and named timeZone and calendar then it's about as ergonomic as the current multi-argument form.
I haven't though through this proposal fully and there may be fatal flaws. Fire away!
I'm +1 to this proposal in its entirely if we go with separate methods for additive conversion, barring consideration of #891.
I like this except for the invented time field, which a) feels out of place, and b) runs the risk of collision and/or confusion if supplied with actual time element fields like hour/minute/etc. Just like date.toDateTime({hour: 10}) is valid, so too should date.toLocalDateTime({hour: 10, timeZone}) be鈥攁nd therefore _not_ date.toLocalDateTime({time, timeZone}). Temporal.Date.prototype.toLocalDateTime is definitely the odd one out anyway, and I would also support dropping it in favor of only the two-step date.toDateTime(time).toLocalDateTime(timeZone) and inverted Temporal.LocalDateTime.from({...date, ...time, timeZone}), but I think @justingrant made a compelling argument about the conversion being sufficiently common (i.e., for intervals representing a full calendar date) to include supporting conveniences (just hopefully without breaking the other Temporal patterns).
P.S. For the same reason, absolute.toLocalDateTime({timeZone: 'America/Los_Angeles', calendar: 'iso8601'}) should also be equivalent to the more concise absolute.toLocalDateTime('America/Los_Angeles'). I think that implies Option 2 in #292.
One suggestion. What do you think about allowing the options to be functions, in addition to primitives and strings? For example:
date.toDateTime({
time: (date) => { /* logic to compute a time based on the date */ },
});
The main reason I'm asking is that it would make the following call site very ergonomic.
absolute.toLocalDateTime(Temporal.now);
Both timeZone and calendar would be pulled from Temporal.now.
Meeting, Sept. 18: We will do this (with the exception of allowing the options to be functions). Rationale: The concerns about the time and date fields conflicting with other properties don't apply here, they only apply to the with() method. Some months ago, we had previously said that we should accept strings in fewer places, and encourage people to use strongly typed Temporal objects instead of passing strings around. That is still our advice, but due to the overwhelming feedback we've received asking for more brevity, we now believe the ease of using string literals at call sites such as these, weighs stronger than that concern.
Decision 2020-09-18: We will do this (where "this" means the proposal in the OP), regardless of any decisions around spreadability. We won't do Shane's suggestion of passing a function.
I'm trying to figure out what this would involve, exactly.
{ day }? Seems pretty pointlessAnything I'm missing?
AFAIU we'd rename both toDateInYear() and toDateOnDay() to toDate(), remove the single number argument, and require the argument to be of the form { year: 2020 } or { day: 1 } respectively.
In the OP, what happens when you do
date.toDateTime({hour: 10});
My assumption is that this is shorthand for
date.toDateTime({ time: Temporal.Time.from({ hour: 10 }) });
which I believe will fill in the missing fields (minute, second, subsecond) with zeros. Is that correct?
In the OP, what happens when you do
date.toDateTime({hour: 10});My assumption is that this is shorthand fordate.toDateTime({ time: Temporal.Time.from({ hour: 10 }) });which I believe will fill in the missing fields (minute, second, subsecond) with zeros. Is that correct?
According to my understanding, that's correct. (and also how it currently works)
Now that the YearMonth and MonthDay changes have landed, I believe what's left to do is the changes in
Now that the YearMonth and MonthDay changes have landed, I believe what's left to do is the changes in
- Instant.toZonedDateTime
- [Plain]Date.toZonedDateTime
- [Plain]Time.toZonedDateTime
What about Instant.toZonedDateTimeISO? This only takes one parameter but I assume that {timeZone: 'Asia/Tokyo'} would also work.
You're right, updated
I also forgot to remove the options argument from MonthDay.toDate.
The remaining things to do are, as far as I know:
is that correct?
More:
Another change that should be rolled in: add plain prefix to date and time params of Date/Time toZonedDateTime params #1143
I updated the ambiguity page code examples with the syntax from this issue and verified that all the samples work. But I ran out of time to update the docs for Instant.toZonedDateTime, PlainDate.toZonedDateTime, and PlainTime.toZonedDateTime.
@ryzokuken, @Ms2ger - if you guys have time to PR those docs changes before tomorrow's workshop, that'd be great, but if you can't that's OK too. We can always help people 1:1 in the workshop if they get confused.
BTW, the shape of the updated APIs in TS format is here in case that's useful for docs: https://github.com/tc39/proposal-temporal/pull/1144/files
I think we're done here. Let's file followups if we missed anything.