Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No negative durations? #558

Closed
justingrant opened this issue May 12, 2020 · 25 comments · Fixed by #811
Closed

No negative durations? #558

justingrant opened this issue May 12, 2020 · 25 comments · Fixed by #811
Labels
behavior Relating to behavior defined in the proposal enhancement has-consensus non-prod-polyfill THIS POLYFILL IS NOT FOR PRODUCTION USE! spec-text Specification text involved

Comments

@justingrant
Copy link
Collaborator

justingrant commented May 12, 2020

In docs for Duration, I was surprised that no negative durations were allowed. This limitation seems to make DX much harder for subtracting Durations and calculating differences between DateTime/Absolute/Date/Time values, because before doing the subtraction operation you'd need to check which one was greater.

This is also different behavior from all date libraries that I'm familiar with, all of which support negative results that can be returned from their equivalent of difference().

Would it be possible to relax this rule to support only the largest unit being negative? So you could have "-3 days" but not "3 days and -12 hours".

It's OK if there's no ISO serialization possible for negative durations, especially given that there are already other cases where the value is not ISO serializable.

@ptomato
Copy link
Collaborator

ptomato commented May 13, 2020

I did find while writing the cookbook that sometimes it was useful to have a signed duration, and it was on my list to open an issue to discuss it when the cookbook was done 😄

Here's the comment in the cookbook thread (#240 (comment)) and down below it is a link to the earlier discussion.

@justingrant
Copy link
Collaborator Author

Yep. Here's a simple use-case I'd recommend for verifying DX of Duration: a flight tracker app estimates arrival times by looking at the last flight between the same pair of cities and assuming that the current flight will be early or late by the same amount. With signed durations, this is trivial:

const diff = previousFlight.scheduled.difference(previousFlight.actual);
const estimate = thisFlight.scheduled.add(diff);

With only unsigned durations, you need this:

const sign = previousFlight.scheduled.compare(previousFlight.actual);
const diff = previousFlight.scheduled.difference(previousFlight.actual);
const estimate = sign < 0 ? thisFlight.scheduled.subtract(diff) : thisFlight.scheduled.add(diff);

The latter is:

  • 50% more function calls
  • about 2x as much typing
  • requires conditional logic which means 2x unit tests to get 100% coverage
  • a new potential error case if subtract and add are reversed in their branch of the conditional

Another use-case is for a formatting function to display relative time, e.g. "2 days ago" or "in 2 hours". Having this function to accept a single Duration parameter is a lot clearer than having to pass a sign and a Duration every time.

Another case: code often assumes that it "knows" the order of two dates. If that code's assumption is ever wrong, a negative value is more likely to trigger an obvious failure like a crash or unit-test failure because none of the surrounding code or tests expects a negative value. But if a positive value is returned, that's normal behavior so is less likely to be caught before shipping.

A special case variation of the "knows the order" case above is handling local times in the hour before and after DST ends. For times in this weird period, it's possible for the Absolute difference to be positive while the DateTime difference can be negative, or vice versa. So even if app code doesn't bother calling compare because it "knows" which time is later, those assumptions may intermittently break around DST transitions.

@littledan
Copy link
Member

IIRC @gibson042 has argued for negative durations in the past, though I'm having trouble finding the concrete issue.

@justingrant
Copy link
Collaborator Author

BTW, I found one another place where negative durations came up: @devbww (one of the Google date library maintainers) said:

The only specific thing I have to add at the moment concerns, "Negative durations make no sense." I would take the opposite position. Indeed, if "Durations can only be created through the minus method on temporal objects," like toA - toB, what is the value of toB - toA?

@ptomato
Copy link
Collaborator

ptomato commented May 18, 2020

Another use-case is for a formatting function to display relative time, e.g. "2 days ago" or "in 2 hours". Having this function to accept a single Duration parameter is a lot clearer than having to pass a sign and a Duration every time.

I'd guess this should be achieved with new Intl.RelativeTimeFormat().format(-2, 'days') anyway.

@justingrant
Copy link
Collaborator Author

@ptomato - Imagine you wanted to write a function that enabled multi-unit display of relative times (e.g. 1 minute and 30 seconds ago). A Duration would be the logical argument for that function, but only if you could supply a negative duration.

@sffc
Copy link
Collaborator

sffc commented May 18, 2020

FYI, the latest consensus from the champions group on this subject is what @pdunkel stated here:

https://github.com/tc39/proposal-temporal/blob/main/meetings/agenda-minutes-2019-09-10.md

RG: I wanted to bring up Duration. I saw some spec text that indicated that negative durations are not supported. I think that's a necessary capability.

PD: Negative durations are not supported by ISO 8601 strings either. We support them secondarily, because you can use the + or - operations on them, taking differences, etc. But the difference between two times is never going to be negative. If you have a date, say August 1, 2018, 12:00:00, and August 2, 2018, 8:00:00, which is afterwards, you have the time part, which is negative, and the date part is positive, and now you have a mix. So you really want the difference between two dates and times, which is a length of time, a duration. With + and -, we can do the addition and subtract, and you can do it explicitly, but the duration value is always positive. It makes life simpler, but you can still do the math you need.

RG: I agree it's possible to recover it, but that's the nature of my objection. + and - are operations, but Duration is state. Before we introduced compare, you couldn't even tell the order.

PD: That's why compare is important, but for me, I think going with ISO 8601, saying durations are never negative (there's no syntax to express negative durations), I would rather follow that route. We need compare anyhow for list sorting, and I would rather go down that route.

@ljharb
Copy link
Member

ljharb commented May 18, 2020

It seems very strange to me that what is effectively a - b and b - a would always result in the same value, for nonzero a/b.

@justingrant
Copy link
Collaborator Author

BTW, I did a quick review of how other JS libraries and other platforms handle negative durations. I couldn't find any major library or platform that disallowed negative durations, including libraries like Abseil Time that do duration balancing like Temporal does.

Here's the ones that do support negative durations. Did I miss any major platforms or libraries?

  • momentjs - can be negative. There's also negative serialization support by adding a leading minus to ISO 8601 formats. Apparently other libraries do this too, as asserted here.
  • Abseil Time (Google's C++ library that uses a similar object model to Temporal). Interestingly, Abseil does similar "duration balancing" like Temporal while still managing to support negative durations, so I assume they've figured out the logic that'd be needed for balancing negative units which seems like it'd be the hardest part of supporting negative durations in Temporal.
  • .NET - TimeSpan can be negative. .NET also had a TimeSpan.Negate method which reverses the sign, which would be a good idea if Temporal ends up supporting negative durations.
  • Java - Duration and Period can be negative.
  • JodaTime - Interval can be negative. Joda ports to JS, .NET, etc. as you'd expect also support negatives.
  • iOS/MacOS - TimeInterval can be negative
  • Python - timedelta can be negative
  • C++ STL - std::chrono::duration supports negative durations and has an abs() method.
  • date-fns doesn't have a Duration concept at all. That library supports negative durations by not doing any math on times or dates as a whole. Instead, math is only done one unit at a time, so all operations are done on scalar signed ints. Math with multiple units is chained together, e.g. date.addDays(-3).addHours(-12).differenceInSeconds(otherDate).
  • Flutter - Duration can be negative.
  • Rails - ActiveSupport::Duration::ISO8601Parser apparently supports the negated extension of ISO 8601.

This other-library review was an interesting exercise. I found a few good ideas that were unrelated to negative durations, so I'll file them as separate suggestions.

@justingrant
Copy link
Collaborator Author

Here's another case: "I worked from 8:00AM until 10:00PM. How many hours did I work?"

`You worked ${new Temporal.Time(22).difference(new Temporal.Time(8)).hours} hours`

expected: You worked 14 hours
actual: You worked 10 hours

IMHO, if Temporal doesn't support negative durations, then I'd probably recommend removing arithmetic from the Time class to avoid this case.

@Ms2ger
Copy link
Collaborator

Ms2ger commented May 19, 2020

Here's another case: "I worked from 8:00AM until 10:00PM. How many hours did I work?"

`You worked ${new Temporal.Time(22).difference(new Temporal.Time(8)).hours} hours`

expected: You worked 14 hours
actual: You worked 10 hours

IMHO, if Temporal doesn't support negative durations, then I'd probably recommend removing arithmetic from the Time class to avoid this case.

This calculation will fail if your workday crosses a DST transition, will it not? I imagine you'd want to use Absolute for this to be completely correct.

@ryzokuken ryzokuken added behavior Relating to behavior defined in the proposal enhancement non-prod-polyfill THIS POLYFILL IS NOT FOR PRODUCTION USE! spec-text Specification text involved labels May 20, 2020
@ryzokuken ryzokuken modified the milestones: Stable API, Stage 3 May 20, 2020
@ryzokuken ryzokuken removed this from the Stage 3 milestone May 20, 2020
@justingrant
Copy link
Collaborator Author

justingrant commented May 29, 2020

This calculation will fail if your workday crosses a DST transition, will it not? I imagine you'd want to use Absolute for this to be completely correct.

Yep, agreed. A variant of that use case where Absolute won't work would be: "I have a recurring 14-hour shift every Friday from 6am-8pm. How much will I get paid on those days?" But my concerns about Time are secondary to the main question of whether Durations should allow negatives. Let's continue Time-related discussion at #597 and focus this issue on whether Duration should be negative.

Moment.js, Abseil Time, .NET, Java, JodaTime, iOS/MacOS, Python, C++ STL, Flutter, Rails, etc. all allow negative durations. Are there any other major libraries that prevent negative durations?

Note that wanting a positive-only duration is a common use-case, so we could offer an difference option to opt into an absolute value, e.g. {result: 'signed' | 'unsigned'}. Or Duration.prototype.abs(). Or both.

@gibson042
Copy link
Collaborator

It's OK if there's no ISO serialization possible for negative durations, especially given that there are already other cases where the value is not ISO serializable.

I didn't think that was the case... can you provide an example?

Regardless, I want to pull in a relevant excerpt from the cookbook comment I just left:

I'm currently inclined towards both Temporal.ZonedDateTime and signed Temporal.Duration, although the latter comes with serialization/deserialization concerns because ISO 8601 durations are unsigned (resulting in some libraries supporting/preferring negative-valued time elements such as A) PT1H-210M while others support/preferring only a single leading negation such as B) -PT2H30M or conceivably even C) P-T2H30—I prefer the latter model, C specifically if there's a gun to my head because it maintains the leading "P", but all of the syntax changes make me uncomfortable because 8601 is very particular about designators).

I believe serialization/deserialization is the only substantial objection to signed Temporal.Duration, but it's a pretty big one if it would be the first deviation from ISO 8601 as I suspect. On the other hand, though, forcing authors to construct their own { sign, duration } boxes seems like a high price to pay for this (foolish?) consistency, especially when "other libraries" have already homesteaded at least A and B.

@sffc
Copy link
Collaborator

sffc commented May 29, 2020

There are a number of areas where we are deviating from ISO-8601 string syntax, documented here:

https://github.com/tc39/proposal-temporal/blob/main/docs/iso-string-ext.md

I think we should not block this feature merely on ISO-8601 string syntax. We can just make another extension to the string syntax and document it. For example, something like PT3H for +3 hours and PNT3H for -3 hours.

@justingrant
Copy link
Collaborator Author

justingrant commented May 30, 2020

some libraries supporting/preferring negative-valued time elements such as A) PT1H-210M while others support/preferring only a single leading negation such as B) -PT2H30M or conceivably even C) P-T2H30—I prefer the latter model, C specifically if there's a gun to my head because it maintains the leading "P"

@gibson042 - are there other libraries that support C? I could only find A and B. Both Java and Luxon seem to support both A and B.

My suggestion would be to support only B, for two reasons: 1) it's already used in RFC 5545, while A doesn't seem to be standardized anywhere; 2) I think A introduces a lot of extra complexity for developers without clear real-world use cases, especially for persistence. Details are below, including a specific proposal for how negative durations could work across Temporal.

RFC 5545 Durations

iCalendar durations are standardized in RFC 5545. AFAIK, Durations in this standard are designed for two use cases: to define the length of meetings in local clock time AND to model the reminder time delta before calendar events. "Snoozed" reminders can show up after an event, so they needed to specify negative durations.

This calendar-reminder use case also requires deterministic arithmetic behavior, because it'd be bad for one calendar app showing you a reminder at a different time than another. Therefore the spec defines a specific order of operations (add or subtract larger units before smaller ones) and specific DST behavior. I'll post the DST behavior over in #559 to keep this issue focused on negativity.

Unfortunately, the calendar reminder use case (and therefore that standard) also excludes months and years, probably for the same non-determinism reasons that Duration lacks day/month/year balancing and compare. So this standard is not a perfect match for Temporal's use cases that also include months and years for formatting (but not math) purposes.

But it seems like a reasonable homestead to follow, especially because that format is also supported by other libraries like Luxon (probably moment too, but not sure) and platforms like Java.

It also seems reasonable to follow RFC's 5545 order-of-operations behaviors for date/time math, if only because order-of-operations is somewhat arbitrary and I don't see any reason to not follow the standard. Do you? FWIW, Temporal's current order of operations is inconsistent: plus matches RFC's 5545 order of operations, but minus seems to be the opposite.

// minus current behavior: days first, then months
new Temporal.DateTime(2020, 7, 1).minus({months: 1, days: 1}).toString()
// => "2020-05-30T00:00"
new Temporal.DateTime(2020, 7, 1).minus({months: 1}).minus({days: 1}).toString()
// => "2020-05-31T00:00"
new Temporal.DateTime(2020, 7, 1).minus({days: 1}).minus({months: 1}).toString()
// => "2020-05-30T00:00"

// plus current behavior: months first, then days
new Temporal.DateTime(2020, 6, 30).plus({months: 1, days: 1}).toString()
"2020-07-31T00:00"
new Temporal.DateTime(2020, 6, 30).plus({months: 1}).plus({days: 1}).toString()
// => "2020-07-31T00:00"
new Temporal.DateTime(2020, 6, 30).plus({days: 1}).plus({months: 1}).toString()
// => "2020-08-01T00:00"

Adopting RFC 5545's DST behavior is an interesting discussion but IMHO it's out of scope of this issue. Let's discuss over in #559 unless you think there's a reason to combine.

Adopting RFC 5545's assumption that all Durations are nominal (aka DateTime not Absolute) is kinda tied up with the DST issue, so probably best to discuss those together.

Why not A? (where each component can have a different sign)

Java, Luxon, and (I suspect, but haven't confirmed yet) moment.js support A too. Here's examples from the Java Duration docs illustrating negative cases:

    "P2DT3H4M"  -- parses as "2 days, 3 hours and 4 minutes"
    "P-6H3M"    -- parses as "-6 hours and +3 minutes"
    "-P6H3M"    -- parses as "-6 hours and -3 minutes"
    "-P-6H+3M"  -- parses as "+6 hours and -3 minutes"

I'm skeptical of A, for a few reasons. First, if you don't read the docs you won't know how to resolve this ambiguity: does P-6H3M mean that the 3M is +3 minutes or -3 minutes? Java says the former, but it's not standardized so some other implementation could decide it has the other meaning. On the other hand, a leading minus sign (aka B) unambiguously refers to the duration as a whole.

Second (and probably more important) A in other libraries implies mixed-sign components, so if we went with A then users may expect mixed-sign components in Temporal too. But I don't know any significant, non-contrived use cases for a persisted duration with mixed-sign components. I'd be hesitant to support a non-standardized feature in Temporal without known, important use cases that justify doing so.

Some background: duration types typically serve two purposes: to model a real-world time deltas (e.g. reminder time for calendar events, stopwatch time since a particular event, age of a person, etc.) or to provide a property bag format that developers can use to perform math on date/time data. B implies the former. A implies the latter: the duration may not represent a real thing in the real world; it may only represent a serialization of multiple, opposite-sign/different-units math operations that the developer wants to do later. I'm not aware of use cases where that "multiple, opposite-sign/different-units math operations" must be persisted as a single Duration. I can see use-cases for wanting to persist multiple math operations (e.g. an Undo stack in a calendar app), but that seems better modeled as an array of durations, where each duration represents an actual real-world quantity.

Also, I'm not even sure that the "multiple, opposite-sign/different-units math operations" case needs any support, even if only in code and not persisted. Duration math is already complicated (balancing, etc.) both conceptually for developers to learn and for implementers of Temporal. Allowing entire durations to be signed is conceptually simple: addition becomes subtraction and vice versa. Implementation is trivial for the same reason. But mixed intra-duration signs are harder to reason about, harder to test, harder to implement, etc.

Finally, mixed signs in our API has the same must-read-the-docs ambiguity as the persistence format: does Duration.prototype.with({ hour: -1, minute: 30 }) mean -90 minutes or -30 minutes? Given that the workaround (2+ method calls) is trivial for the developer, I'm inclined to exclude the mixed-sign case... not only for overall-negative durations, but in all cases.

Proposal

I thought it'd be helpful to have a specific proposal to discuss, so I wrote one up below:

  • A Duration can be signed, but all units must share the same sign.
  • Temporal would emit and accept a leading minus sign (aka B) when persisting and parsing negative durations. Intra-duration minus signs are not supported and must throw when parsed.
  • Duration methods that return numeric field values (property getters and getFields) must return negative values for every nonzero unit of a negative duration.
  • The Duration constructor must throw if it's passed non-zero units with different signs.
  • APIs that accept "Duration-like" objects (with, from, plus, minus) must throw if passed non-zero units with different signs.
  • Duration.prototype.plus and Duration.prototype.minus should ensure that the resulting Duration has consistent signs for all units, just like it does today for positive-only results. {disambiguation: balanceConstrain'} for negative results should do the mirror image of what it does for positive results: do the minimum amount of balancing needed to get all units to have the same sign.
  • Duration should gain a few convenience properties/methods:
    • Duration.prototype.negated() - reverse the sign
    • Duration.prototype.sign - 0, -1, or 1. Not included in getFields because it's redundant. Not accepted by with or from because of potential conflicts.
    • Duration.prototype.abs() - if negative, reverse the sign
  • Temporal must adopt RFC 5545 order of operations (larger units added/subtracted first) for all plus/minus operations (both when adding a duration to another type, or when adding durations to each other).
  • Open issue: how should Duration.prototype.toLocaleString() behavior change (if at all) for negative durations? Should it return the same string, because (in English at least) there's not generic language to express a duration that goes backwards? Or should it throw, for the same reason? My instinct would to do the "same as positive" output in English, but I could potentially see other languages doing things differently... although I don't have enough intl contex to have a strong opinion either way.

@gibson042
Copy link
Collaborator

I agree with your reasoning and your suggestions, modulo bikeshedding on names (I have a moderate-to-strong preference for negated rather than negate to better indicate the receiver's immutability, and a weak preference for magnitude rather than abs).

@justingrant
Copy link
Collaborator Author

Cool! negated sounds good. It's also what Java uses, for the same reason probably. I edited the proposal above to use it.

re: abs, if it were Math.magnitude() then I'd agree, but IMHO there's a really high bar to pick anything other than abs given the discoverability benefit of matching Math for the same operation. A surprisingly large number of novice web devs may not have a strong math/science background and may not know that "magnitude" or "absolute value" are roughly synonymous, or may be learning both concepts for the first time. So I'd strongly recommend using a familiar name here.

@ryzokuken
Copy link
Member

@justingrant this got lost somewhere, thanks to GitHub's email routing, but for reference: #158 (comment)

@justingrant
Copy link
Collaborator Author

justingrant commented Jun 11, 2020

We discussed this issue in the 11 Jun 2020 champions meeting but didn't come to resolution.
(@littledan , @ptomato, @ryzokuken couldn't attend). It was a long discussion so I tried to summarize. @pdunkel @sffc @jasonwilliams @gibson042 let me know if I missed anything important.

@pdunkel: here's history about why negative durations were avoided:

  • Duration was envisioned as a property bag (more like a literal than a type) and "no negatives" mirrors JS's behavior where numeric literals are always positive.
  • There's only a handful of people in the world who really understand the corner cases around time/date math, so we must be careful around introducing unexpected behavior.
  • plus and minus are logically different with different order of operations, so it's helpful to keep them separate and not blur the lines, e.g. plus a negative duration.
  • It's required to ensure that plus/minus operations can be reversible, which requires different order-of-operations for subtraction vs. addition. Order-of-operations differences can cause subtle bugs that will likely only be caught downstream.
  • difference was carefully named to imply an absolute value result. We could call it "absoluteDifference" if we find that developers don't grasp the connotation.
  • Negative durations add a lot of complexity, so negative durations would need clear positive value-add to outweigh the problems.

@jasonwilliams If negative durations are so widely used, it would be good to understand why.

@pdunkel What I heard from other libraries was negatives were put in without a lot of thought, e.g. "if positive, why not negative?". Following other libraries is not a good reason to do it.

@sffc (or @gibson042?)

  • plus/minus could use the opposite order of operations if the duration were negative, so order-of-operations doesn't seem to be a reason to avoid negative durations.

@justingrant:

  • Bugs will happen if developers believe that dates (or times or datetimes or...) are in one order, but sometimes they're in another order. Like @pdunkel's order-of-operations example above, these bugs will often propagate downstream and be hard to diagnose.
  • A secondary concern is that adding negative durations later along the path to Stage 4 would be a pretty severe breaking change.
  • re: naming, it would be a naming issue if developers didn't realize that difference calculated an absolute value. But the problem is when developers know that difference returns an absolute value but don't care because they already believe (incorrectly) that arguments are always properly ordered.

@pdunkel If we wanted to be stricter, then out-of-order arguments to difference() could throw.

@justingrant:

  • Agree. If we don't want negative durations, then I'd strongly support throwing, because it'd address my top concern about hard-to-find bugs from accidental mis-ordered arguments.
  • It'd also reduce the negative durations question to purely an ergonomics and performance issue which should be easier to resolve via community feedback, compared to obscure mis-ordered-data cases that'd probably only show up in production.
  • Unlike negative durations, adding a misordered-argument exception to difference() would be an easy change to make ASAP, so that depending on the feedback we get we can later decide to add negative durations, to leave the exception, or to revert to the absolute-value behavior-- and none of those changes would be very impactful for early adopters.

After thinking about this after the meeting, I've changed my opinion. If there's not consensus that negative durations are the way to go, then it doesn't make sense to make that expensive change now. Instead, I think we get most of the benefit from throwing an exception and punting a final decision until there's more early adopter feedback-- and I think an exception could help us get that feedback. I filed #663 to track this suggestion and I'm happy to PR it.

@sffc
Copy link
Collaborator

sffc commented Jun 11, 2020

@ptomato wasn't at the meeting, but in my mind, the most compelling case in favor of negative durations is #240 (comment): we have concrete data that passing around a { duration, sign } tuple is a common operation when dealing with Temporal.

We didn't fully have time to discuss the semantics of negative durations in the arithmetic methods, but my suggestion, recorded in the notes, was that the current semantics of .minus(duration) would be used when a negative duration is passed to .plus(), and we would remove the .minus() method. Additionally or alternatively, the .negated() method could perform any transformations necessary to preserve the proper order of operations.

justingrant added a commit to justingrant/proposal-temporal that referenced this issue Jun 12, 2020
Fixes tc39#663. Fixes tc39#597.  Changes `difference()` to throw if `other`is
larger than `this`. Goal: encourage feedback about long-term solution:
option 1 - previous behavior: `difference()` returns an absolute value
option 2 - behavior in this commit: throw if other is larger
option 3 - negative durations (tc39#558)

Tests are updated to make it easy to choose any of the three options.
Tests for option 1 are commented out in case we want to revert.
The rest of test changes were reversing arguments so that choosing any
of the options will break few tests.
justingrant added a commit to justingrant/proposal-temporal that referenced this issue Jun 12, 2020
Fixes tc39#663. Changes `difference()` to throw if `other`is
larger than `this`. Goal is encourage feedback about long-term solution:
option 1 - previous behavior: `difference()` returns an absolute value
option 2 - behavior in this commit: throw if other is larger
option 3 - negative durations (tc39#558)

Tests are updated to make it easy to choose any of the three options.
Tests for option 1 are commented out in case we want to revert.
The rest of test changes were reversing arguments so that choosing any
of the options will break few tests.

Because `difference` is now unidirectional, it doesn't make sense to
restrict `Time.prototype.difference` to 12 hours max. Fixes tc39#597.
@justingrant
Copy link
Collaborator Author

justingrant commented Jun 12, 2020

After today's meeting, I built a PR #667 which will throw if difference() argument is out of order. I don't think that this is ideal long-term ergonomics, but I do think that this change will help us get early adopter feedback about which long-term option they'd like to see:
1 - revert to previous absolute value behavior
2 - keep the "out-of-order duration throws" behavior
3 - negative durations

justingrant added a commit to justingrant/proposal-temporal that referenced this issue Jun 12, 2020
Fixes tc39#663. Changes `difference()` to throw if `other`is
larger than `this`. Goal is encourage feedback about long-term solution:
option 1 - previous behavior: `difference()` returns an absolute value
option 2 - behavior in this commit: throw if other is larger
option 3 - negative durations (tc39#558)

Tests are updated to make it easy to choose any of the three options.
Tests for option 1 are commented out in case we want to revert.
The rest of test changes were reversing arguments so that choosing any
of the options will break few tests.

Because `difference` is now unidirectional, it doesn't make sense to
restrict `Time.prototype.difference` to 12 hours max. Fixes tc39#597.
justingrant added a commit to justingrant/proposal-temporal that referenced this issue Jun 13, 2020
Fixes tc39#663. Changes `difference()` methods to throw if `other`is
larger than `this`. Goal is encourage feedback about long-term solution:
option 1 - previous behavior: `difference()` returns an absolute value
option 2 - behavior in this commit: throw if other is larger
option 3 - negative durations (tc39#558)

Tests are updated to make it easy to choose any of the three options.
Only a few tests were functionally changed (e.g. to add throws() tests).
The rest of test changes were reversing arguments so that choosing any
of the options later will break relatively few tests.

Because `difference` is now unidirectional, it doesn't make sense to
restrict `Time.prototype.difference` to 12 hours max. Fixes tc39#597.
justingrant added a commit to justingrant/proposal-temporal that referenced this issue Jun 13, 2020
Fixes tc39#663. Changes `difference()` methods to throw if `other`is
larger than `this`. Goal is encourage feedback about long-term solution:
option 1 - previous behavior: `difference()` returns an absolute value
option 2 - behavior in this commit: throw if other is larger
option 3 - negative durations (tc39#558)

Tests are updated to make it easy to choose any of the three options.
Only a few tests were functionally changed (e.g. to add throws() tests).
The rest of test changes were reversing arguments so that choosing any
of the options later will break relatively few tests.

Because `difference` is now unidirectional, it doesn't make sense to
restrict `Time.prototype.difference` to 12 hours max. Fixes tc39#597.
ptomato pushed a commit that referenced this issue Jun 15, 2020
…pe.difference` to 12 hours (#667)

* difference: throw out-of-order; zap Time 12h limit
Fixes #663. Changes `difference()` methods to throw if `other`is
larger than `this`. Goal is encourage feedback about long-term solution:
option 1 - previous behavior: `difference()` returns an absolute value
option 2 - behavior in this commit: throw if other is larger
option 3 - negative durations (#558)

Tests are updated to make it easy to choose any of the three options.
Only a few tests were functionally changed (e.g. to add throws() tests).
The rest of test changes were reversing arguments so that choosing any
of the options later will break relatively few tests.

Because `difference` is now unidirectional, it doesn't make sense to
restrict `Time.prototype.difference` to 12 hours max. Fixes #597.
@ptomato
Copy link
Collaborator

ptomato commented Jul 7, 2020

#731 is another bit of feedback in favour of negative durations.

@justingrant
Copy link
Collaborator Author

Today we decided to move forward with negative durations. Please provide feedback on #782 which is the spec for this proposed change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
behavior Relating to behavior defined in the proposal enhancement has-consensus non-prod-polyfill THIS POLYFILL IS NOT FOR PRODUCTION USE! spec-text Specification text involved
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants