-
Notifications
You must be signed in to change notification settings - Fork 162
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Should Duration.from
accept non-integer values? (presumably for time units only)
#938
Comments
It seems very strange to prevent non-integer values. Why would that be preferred? |
I wasn't around when this decision was made, but if I had to guess at the rationale (others can confirm) it's because the Duration type's fields (years, months... nanoseconds) are integers only. So an input that contains a fraction must be broken up into constituent integral fields. We already do this for seconds where there's no possibility of an uneven remainder. But what about Another possible reason this isn't supported is that users may expect that we retain the decimal afterwards if dur = Temporal.Duration.from(`PT0.5H`);
result = {hours: duration.hours, minutes: duration.minutes} = dur;
// expected: {hours: 0.5, minutes: 0} ?
// OR
// expected: {hours: 0, minutes: 30} ? I think that the value of supporting fractional minutes and hours might outweigh those concerns, but there are pros and cons on both sides and I can see valid reasons to choose either approach. |
I would certainly assume that if i say "25 hours" it turns into "1 day and 1 hour", and so forth - but I'd also not expect anything to be integral. Units of time are always divisible. |
Decision 2020-10-09:
|
I feel strongly we should avoid treating Number options to
This could be addressed by the TC39 Decimal proposal, which could avoid this rounding. But for now, we'd have to answer tough questions like, "What happens with One way to resolve this would be to intelligently round Numbers to the answer that you "want them" to be, as If you wanted to interpret a string as a decimal Duration.from, that could work correctly, and I'd be fine with adding that feature. But I don't think we should allow Numbers for this purpose. |
The largest unit we'd accept with fractional units is I'm asking because if strings are OK, then what if we treated |
@justingrant I'm still really concerned about that kind of strategy. We'd be using Numbers for something that their data model just doesn't accurately represent. I talked more about this in my second-to-last paragraph above. |
@littledan - is your concern that Temporal won't be able to get accurate rounded-to-9-decimal-places results from a Or are you saying that the real problem is that by accepting At first I thought you were talking about the former, but are you actually talking about the latter? |
@justingrant I'm talking about the latter. We should accept data types as arguments which actually represent what's needed. Strings would be better than Numbers for the purpose you are describing. |
One way or another, behavior must be defined for each of the following:
And given that non-integer units have been identified as a relevant use case, I don't think any of those should return |
* polyfill: durations accept fractional time values Fixes: #938 * fixup! polyfill: durations accept fractional time values * fixup! polyfill: durations accept fractional time values * spec: add spec for handling fractional durations * Code review suggestions - Fix order-of-operations tests (which used 1.7 as a value for durations and relied upon it being truncated to 1, which we probably don't want regardless of the state of this) - Remove Duration.from subclass-invalid-arg test, which is no longer valid; the subclass constructor is never called with a non-float argument - Fix ecmarkup linter errors Co-authored-by: Philip Chimento <pchimento@igalia.com>
I'll reopen this and move it to the Stage 3 milestone since we got review feedback on it before it even landed in the polyfill 😝 |
@gibson042 Yes, I am advocating for throwing (or rounding to an integer) for the Number case, am indifferent on the string case, and believe the ISO 8601 case should be supported. |
And I am saying that rounding |
* polyfill: durations accept fractional time values Fixes: tc39/proposal-temporal#938 * fixup! polyfill: durations accept fractional time values * fixup! polyfill: durations accept fractional time values * spec: add spec for handling fractional durations * Code review suggestions - Fix order-of-operations tests (which used 1.7 as a value for durations and relied upon it being truncated to 1, which we probably don't want regardless of the state of this) - Remove Duration.from subclass-invalid-arg test, which is no longer valid; the subclass constructor is never called with a non-float argument - Fix ecmarkup linter errors Co-authored-by: Philip Chimento <pchimento@igalia.com>
The Temporal.Duration constructor, unlike Temporal.Duration.from(), would previously drop the fractional part of numbers given to it. from() throws if given a non-integer number, because Temporal.Duration.from('PT1.1H') results in 1 hour, 6 minutes, but Temporal.Duration.from({ hours: 1.1 }) cannot be exact, yet should not silently drop the .1, as discussed in issue #938. Temporal.Duration(0, 0, 0, 0, 1.1) should now throw the same exception as Temporal.Duration.from({ hours: 1.1 }) in order to be consistent and avoid the surprise to users of silently dropping the .1. Closes: #1832
The Temporal.Duration constructor, unlike Temporal.Duration.from(), would previously drop the fractional part of numbers given to it. from() throws if given a non-integer number, because Temporal.Duration.from('PT1.1H') results in 1 hour, 6 minutes, but Temporal.Duration.from({ hours: 1.1 }) cannot be exact, yet should not silently drop the .1, as discussed in issue #938. Temporal.Duration(0, 0, 0, 0, 1.1) should now throw the same exception as Temporal.Duration.from({ hours: 1.1 }) in order to be consistent and avoid the surprise to users of silently dropping the .1. Closes: #1832
The Temporal.Duration constructor, unlike Temporal.Duration.from(), would previously drop the fractional part of numbers given to it. from() throws if given a non-integer number, because Temporal.Duration.from('PT1.1H') results in 1 hour, 6 minutes, but Temporal.Duration.from({ hours: 1.1 }) cannot be exact, yet should not silently drop the .1, as discussed in issue #938. Temporal.Duration(0, 0, 0, 0, 1.1) should now throw the same exception as Temporal.Duration.from({ hours: 1.1 }) in order to be consistent and avoid the surprise to users of silently dropping the .1. Closes: #1832
The Temporal.Duration constructor, unlike Temporal.Duration.from(), would previously drop the fractional part of numbers given to it. from() throws if given a non-integer number, because Temporal.Duration.from('PT1.1H') results in 1 hour, 6 minutes, but Temporal.Duration.from({ hours: 1.1 }) cannot be exact, yet should not silently drop the .1, as discussed in issue #938. Temporal.Duration(0, 0, 0, 0, 1.1) should now throw the same exception as Temporal.Duration.from({ hours: 1.1 }) in order to be consistent and avoid the surprise to users of silently dropping the .1. Closes: #1832
The Temporal.Duration constructor, unlike Temporal.Duration.from(), would previously drop the fractional part of numbers given to it. from() throws if given a non-integer number, because Temporal.Duration.from('PT1.1H') results in 1 hour, 6 minutes, but Temporal.Duration.from({ hours: 1.1 }) cannot be exact, yet should not silently drop the .1, as discussed in issue #938. Temporal.Duration(0, 0, 0, 0, 1.1) should now throw the same exception as Temporal.Duration.from({ hours: 1.1 }) in order to be consistent and avoid the surprise to users of silently dropping the .1. Closes: #1832
#937 reminded me that time units are often thought of using non-integer values e.g. 2.5 hours. But there's no easy way to get a non-integer value into a
Temporal.Duration
without users manually doing the calculations themselves to split into integer units.Obviously some fractions are more problematic than others, e.g.
{hours: 0.666666666666}
per #937.But the general idea of accepting non-integer values in
from
seems like a reasonable one to consider, esp. because the ISO spec supports it. (see below)Some units (e.g. months) are problematic than others while use-cases for fractions are almost always focused on hours or smaller, so a reasonable compromise might be to accept non-integer values for the smallest time unit but not on days or larger. This is similar to the decision we made recently to limit
round
tosmallestUnit
of days or smaller.ISO 8601 specifically allows decimals for the smallest unit in a time representation, even if the smallest unit isn't "seconds". From Wikipedia:
For times:
For durations
The text was updated successfully, but these errors were encountered: