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.
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 :smile:
Here's the comment in the cookbook thread (https://github.com/tc39/proposal-temporal/issues/240#issuecomment-614936470) and down below it is a link to the earlier discussion.
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:
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.
IIRC @gibson042 has argued for negative durations in the past, though I'm having trouble finding the concrete issue.
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 oftoB - toA?
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
Durationparameter 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.
@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.
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.
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.
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?
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.Duration and Period can be negative.Interval can be negative. Joda ports to JS, .NET, etc. as you'd expect also support negatives. TimeInterval can be negative timedelta can be negativestd::chrono::duration supports negative durations and has an abs() method.date.addDays(-3).addHours(-12).differenceInSeconds(otherDate).Duration can be negative.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.
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.
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 hoursIMHO, if Temporal doesn't support negative durations, then I'd probably recommend removing arithmetic from the
Timeclass 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.
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.
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鈥擨 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.
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.
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
Bracketed IANA time zone suffixes are a clear extension of ISO 8601, and one that already exists in the broader ecosystem. Temporal.MonthDay does not seem to be covered by the current ISO 8601 data model (the closest thing I can find is XXXX-07-04 from 8601-2 Level 2 for "unspecified year"), although there is certainly risk of introduction. And calendar suffixing is something that I have a problem with unless we can get adoption outside of ECMAScript. All of these are of a different character than what we're talking about with Temporal.Duration.
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
PT3Hfor +3 hours andPNT3Hfor -3 hours.
That's being far too cavalier with standard formats that are intended for cooperative interchange.
I didn't think that was the case... can you provide an example?
Nope. I opened this issue before I'd fully understood the Temporal data model, so I was thinking of cases where you're measuring a duration across a DST boundary (#559). I meant that the ambiguity would be lost in serialization, but now I know Temporal better so I realize that the ambiguity is by design-- currently Temporal doesn't distinguish between clock-time Durations and absolute Durations, so it's up to the app to decide whether a particular persisted Duration is intended to be a clock time delta or an absolute time delta.
I have more feedback but am going to split it into a separate comment for clarity.
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鈥擨 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:
Duration can be signed, but all units must share the same sign.Duration methods that return numeric field values (property getters and getFields) must return negative values for every nonzero unit of a negative duration.Duration constructor must throw if it's passed non-zero units with different signs. 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 signDuration.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 signDuration.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. 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).
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.
@justingrant this got lost somewhere, thanks to GitHub's email routing, but for reference: https://github.com/tc39/proposal-temporal/issues/158#issuecomment-630363463
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.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.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. @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:
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:
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.
@ptomato wasn't at the meeting, but in my mind, the most compelling case in favor of negative durations is https://github.com/tc39/proposal-temporal/issues/240#issuecomment-614936470: 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.
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
Today we decided to move forward with negative durations. Please provide feedback on #782 which is the spec for this proposed change.
Most helpful comment
@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:
plusmatches RFC's 5545 order of operations, butminusseems to be the opposite.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
DateTimenotAbsolute) 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 docsillustrating negative cases: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-6H3Mmean that the3Mis +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:
Durationcan be signed, but all units must share the same sign.Durationmethods that return numeric field values (property getters andgetFields) must return negative values for every nonzero unit of a negative duration.Durationconstructor must throw if it's passed non-zero units with different signs.with,from,plus,minus) must throw if passed non-zero units with different signs.Duration.prototype.plusandDuration.prototype.minusshould ensure that the resultingDurationhas 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.Durationshould gain a few convenience properties/methods:Duration.prototype.negated()- reverse the signDuration.prototype.sign- 0, -1, or 1. Not included ingetFieldsbecause it's redundant. Not accepted bywithorfrombecause of potential conflicts.Duration.prototype.abs()- if negative, reverse the signDuration.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.