Proposal-temporal: Support weeks in Temporal.Duration?

Created on 28 Apr 2020  Â·  23Comments  Â·  Source: tc39/proposal-temporal

@younies made a compelling case about use cases involving weeks in durations and duration formatting. We should consider adding it to Temporal.Duration.

Questions:

  1. Do we assume weeks are 7 days? That might not always be the case in every calendar.
has-consensus

Most helpful comment

Well, in that case, I could open up a PR and see if someone objects to it.

All 23 comments

Yes, the length of a "week" is inherently dependent on the calendar system, but the same is true for "month". That said, the addition of "week" doesn't seem to align with the data models (year, month, day) and therefore I don't think it's too important to include weeks in durations. Perhaps we could make it a DurationFormat-only unit? I doubt weeks would be very useful while doing arithmetic, but I might be wrong.

This is a great point. Do we need to support the operation to add a week to a date? (I think this is somewhat common in calendar applications.) Wouldn't this support require adding weeks to Duration objects?

It should be safe to do arithmetic with weeks, because the calendar system can interpret the weeks field however it needs to interpret it.

How about the largestUnit setting in .difference()? Should it support "weeks"?

Wouldn't this support require adding weeks to Duration objects?

Yes, hence why I opened the issue.

Well, in that case, I could open up a PR and see if someone objects to it.

To me it depends on how many bells and whistles we do or don't want to add before considering the proposal ready for the next stage. I think weeks could safely be postponed to a later addition, but I'm also not against adding them now.

To me the most compelling reason to do it is to allow the calendar to set the length of a week as pointed out above.

However, there are a couple of complications. For serialization, we would have to pull in the ISO 8601 week duration notation (Temporal.Duration.from({ weeks: 3 }).toString() === 'P3W'). However, in ISO 8601 the weeks notation is mutually exclusive with any other units (P3W1D is not valid) so there would be a problem with serialization. Not an impossible problem, because we already have { microseconds: 2000 } ⇒ 'PT0.002S' ⇒ { milliseconds: 2 }', but a somewhat more difficult one, since you'd have to balance the weeks into days and thereby bypass the whole point of adding weeks to Duration.

It would also seem strange to me to support durations in weeks but not support constructing dates from ISO year-week notation ('2020-W19-1' ⇒ '2020-05-04') so I'd advocate for adding that if we add this.

To me it depends on how many bells and whistles we do or don't want to add before considering the proposal ready for the next stage. I think weeks could safely be postponed to a later addition, but I'm also not against adding them now.

I think weeks in durations have pretty clear use cases that warrant inclusion in V1. @younies, can you list out some of the use cases?

However, there are a couple of complications. For serialization...

Good observation. Worth discussing in the champions call.

It would also seem strange to me to support durations in weeks but not support constructing dates from ISO year-week notation ('2020-W19-1' ⇒ '2020-05-04') so I'd advocate for adding that if we add this.

I don't know if I agree with that. Weeks in durations and weeks in dates are two fundamentally different things with different use cases. We have acknowledged weeks being useful in arithmetic: "reschedule this event in 1 week". However, "the 19th week of 2020" doesn't have as clear of use cases. If those use cases exist, we should list them out and consider that as a separate feature request.

  1. Do we assume weeks are 7 days? That might not always be the case in every calendar.

https://en.wikipedia.org/wiki/Week#%22Weeks%22_in_other_calendars
There's quite a few examples where they are not, but most of these are not "modern" calendars.
Seems like the most recent example was a 5 day week in the Soviet Calendar up until 1940.

It would also seem strange to me to support durations in weeks but not support constructing dates from ISO year-week notation ('2020-W19-1' ⇒ '2020-05-04') so I'd advocate for adding that if we add this.

I second this

To me it depends on how many bells and whistles we do or don't want to add before considering the proposal ready for the next stage. I think weeks could safely be postponed to a later addition, but I'm also not against adding them now.

I think weeks in durations have pretty clear use cases that warrant inclusion in V1. @younies, can you list out some of the use cases?

The most important cases are as the following:

  • For trip agency, the length of the stay or when the trip will start

    • For example, the trip is in two weeks, or the trip is for two weeks

  • For events

    • For example, the conference will held in San Jose in two weeks from now. Or, Zurich festival will be extended for another week ... etc

  • For sales

    • For example, home24.ch, most of the product has a waiting time in weeks

Also, I think we should assume that week => 7 days. Because as a duration (week is 7 days). we do not need to mix specific fields understanding with the general duration concept. For example, most of the companies looks to a working day as a 8-hours period, despite that the day is 24 hours.

  • For trip agency, the length of the stay or when the trip will start

    • For example, the trip is in two weeks, or the trip is for two weeks
  • For sales

    • For example, home24.ch, most of the product has a waiting time in weeks

For these two use cases, it seems to me that it's enough to support weeks in Intl.DurationFormat, and not necessarily in the Duration objects themselves.

  • For events

    • For example, the conference will held in San Jose in two weeks from now. Or, Zurich festival will be extended for another week ... etc

If the use case is extending or postponing some event by a number of weeks then I think there's very little difference between event.plus({ weeks: 2 }) and event.plus({ days: 14 }). If that's the only advantage, then I'd lean towards not adding it, because of the problems I mentioned above. It's only if you have to support calendars where a week is not 7 days that I think it becomes worth adding it.

For these two use cases, it seems to me that it's enough to support weeks in Intl.DurationFormat, and not necessarily in the Duration objects themselves.

How do you propose supporting different fields in Intl.DurationFormat than in Temporal.Duration?

We can add weeks to the options bag, and let Intl.DurationFormat accept it. But then we lose the ability for balancing between fields that comes with the Temporal.Duration arithmetic methods.

I see Temporal.Duration and Intl.DurationFormat as being very strongly coupled. If we want to decouple them, and let Intl.DurationFormat do things not supported by Temporal.Duration, then we should go back to the drawing board and also consider letting Intl.DurationFormat do arithmetic on its own, accept other data types like a number of milliseconds, etc.

Temporal.Duration wouldn't be able to balance between weeks and days in the first place, because it intentionally doesn't have a calendar. Intl.DurationFormat would be able to do so with the calendar specified in the locale string or the default calendar for the locale.

I'm not at all saying this is desirable or ideal, but I guess if you wanted to balance it yourself with ISO calendar rules you'd do something like this:

const duration = Temporal.Duration.from({ days: 15 });
const { days, ...fields } = duration.getFields();
new Intl.DurationFormat().format({ ...fields, weeks: days / 7, days: days % 7 });
// "2 weeks, 1 day"

The way you would balance in Temporal would be:

const june1 = Temporal.Date.from({ year: 2020, month: 6, day: 1 });
const today = Temporal.now.date("gregory");  // e.g., 2020-05-05

const duration = today.difference(june1, { largestUnit: "weeks" });
duration.toLocaleString();  // expected output: "3 weeks 6 days"

FYI: let's keep the conversation about how to perform balancing to #337, and keep this thread focused on the question about whether to add a weeks field to Temporal.Duration.

I would like to know what is the final decision about supporting weeks, because this is important for a decision about the source of the fields in DurationFormat.

Options discussed in the meeting today:

  1. Don't include weeks in Temporal.Duration. Leave rounding and balancing up to Intl.DurationFormat.
  2. Include weeks in Temporal.Duration as a convenience for Intl.DurationFormat so they can share the same field names and no math is done in Intl.DurationFormat, but don't change anything else in Temporal.
  3. Include weeks in Temporal.Duration and make sure that weeks are supported consistently throughout the API, e.g. Temporal.Date.from('2020-W20-4')

(taking off my "objective" hat) I'm not opposed to any of these 3 options, but I do have some practical concerns about adding weeks which I'll summarize below. If those are solved, it seems pretty harmless to me, but also not absolutely necessary.

Shortcut

First of all can we categorically confirm or deny that there are any calendars supported by 402 that have weeks ≠ 7 days? If we have any calendar where a week is not 7 days, then I feel strongly that the _only_ choice is to have Duration support weeks. (In other words, that makes option 1 out of bounds for me.) For the sake of argument I'll assume in the rest of this comment that this is not the case and that weeks are always 7 days.

Option 1

My argument for _not_ adding weeks is that so far I have only seen use cases that seem to be the responsibility of the presentation layer (product ships in 4 weeks, travel agency reminder about a trip in 2 weeks) or that are trivially doable with *7 in Temporal (postpone or extend an event by one week). Since the conversion is not calendar-dependent, I believe Intl.DurationFormat should be able to do this even if it's not a field in Temporal.Duration. e.g.:

const duration = Temporal.Duration.from({ days: 16 });
// (depending on which DurationFormat API is chosen)
duration.toLocaleString('en-US', { fields: ['weeks', 'days'] })
  // => '2 weeks, 2 days'

This doesn't suggest to me that Intl.DurationFormat has to go back to the drawing board if Temporal.Duration doesn't have a weeks field. (Note, for example, that Intl.RelativeTimeFormat has quarters as well as weeks, which Temporal.Duration also doesn't have.)

Option 2

On the other hand, my argument _for_ adding weeks is that { hours: 1, minutes: 30 } is a distinct duration from { minutes: 90 }, and we don't auto-balance. We assume that if a user has { minutes: 90 } then they intended for it to be like that. So why should we expect Intl.DurationFormat to guess that if a user has { days: 14 } that they actually want { weeks: 2 }?

Here is the practical concern from my earlier post that I think we'd need to solve before adding weeks, though: It's not serializable. ISO 8601 duration strings don't allow weeks with any other units, so P2W2D is not valid.

(I originally thought I had more concerns, but they don't seem to be problems after all.)

Option 3

I feel the same as option 2 for this one but in addition we'd have to audit the existing API surface of Temporal to figure out where else we wanted to support weeks or ISO year-week strings.

First of all can we categorically confirm or deny that there are any calendars supported by 402 that have weeks ≠ 7 days?

Looking at the list of CLDR modern-use calendars, which is the closest thing we have to a comprehensive list of 402 calendars, none of these have weeks that are not seven days.

However, there are a number of historical calendars in which weeks vary from 4 to 10 or more days. Wikipedia has a good discussion on the subject:

https://en.wikipedia.org/wiki/Week#%22Weeks%22_in_other_calendars
https://en.wikipedia.org/wiki/List_of_calendars#Non-standard_weeks

As long as the calendars use solar days, they are able to be implemented in Temporal as custom calendars. I would say that it would be a "nice-to-have" if those calendars could use odd-length weeks in Temporal, but not a deal breaker if there is some other compelling reason to force weeks to 7 days.

Since the conversion is not calendar-dependent, I believe Intl.DurationFormat should be able to do this even if it's not a field in Temporal.Duration ... This doesn't suggest to me that Intl.DurationFormat has to go back to the drawing board if Temporal.Duration doesn't have a weeks field.

Your example is aligned with @pdunkel's suggestion of Intl.DurationFormat performing balancing on the fields in the Temporal.Duration. This decision isn't locked in stone one way or the other, but it would amount to quite a bit of additional design if we needed to think about balancing in Intl.DurationFormat.

We assume that if a user has { minutes: 90 } then they intended for it to be like that.

Right. It makes Intl.DurationFormat substantially simpler if we leverage the fact that there is a difference between { minutes: 90 } and { hours: 1, minutes: 30 } in Temporal.Duration. However, based on what @pdunkel suggested, those two quantities should not be seen as different in Temporal.Duration, which would be a forcing function for adopting balance behavior in Intl.

It's not serializable. ISO 8601 duration strings don't allow weeks with any other units, so P2W2D is not valid.

I don't have a great solution to this one. We could just support P2W2D, despite the fact that it's not part of ISO 8601. We're already supporting time zone names (and maybe calendar identifiers), which aren't technically part of the spec.

Could we use the "comment" mechanism, like P2D[2W]?

Option 3

I have no strong opinion on whether or not we add weeks elsewhere in Temporal.

However, based on what @pdunkel suggested, those two quantities should _not_ be seen as different in Temporal.Duration, which would be a forcing function for adopting balance behavior in Intl.

Right, that would indeed force balancing to move to Intl.DurationFormat, but I'm saying that despite that originally being the intention of Temporal.Duration, it's not anymore, since we stopped treating Temporal.Duration as auto-balancing (#388).

Reingold and Dershowitz say:

A 7-day week is almost universal today. ... Other cycles of days have also been used, including 4-day weeks (in the Congo), 5-day weeks (in other parts of Africa, in Bali, and in Russia in 1929), 6-day weeks (Japan), 8-day weeks (in yet other parts of Africa and in the Roman Republic), and 10-day weeks (in ancient Egypt and in France at the end of the eighteenth century).

I think this slipped through the cracks, but IIRC during the bug squash session we decided it would not be objectionable to support weeks, the only difference of opinion was how far to let them permeate the data model. Correct me if I'm wrong! Does this still need discussion in the meeting?

The data model question is an important one. It would be nice if we can get that resolved sooner rather than later, since it directly affects Intl.DurationFormat. I think that's why we kept it on the meeting agenda.

Meeting, May 28: We will add weeks to the data model, and they will be calendar-dependent (not constrained to 7 days).

Was this page helpful?
0 / 5 - 0 ratings