Proposal-temporal: Allow relational comparison of zoneless dateful civil objects

Created on 27 Sep 2018  Â·  11Comments  Â·  Source: tc39/proposal-temporal

Originally raised in https://github.com/tc39/proposal-temporal/issues/42#issuecomment-424486284 , and related to #92.

I believe that same-type zoneless civil objects [edit: that include dates] should be comparable with each other via built-in operators (e.g., ECMAScript is not Java and shouldn't force consumers into methods).

CivilDate.fromString("1970-01-01") < CivilDate.fromString("+002018-09-27");
// → true (expanded year to show non-string comparison)

// abandoned after issue creation because clocks are modular
// CivilTime(12, 0) < CivilTime(13, 0);
// → ?

CivilDateTime.fromString("1970-01-01T00:00") < CivilDate.fromString("+002018-09-27T00:00");
// → true (expanded year to show non-string comparison)

And to be crystal clear (thanks @domenic):

So it's really a question as to what's more important: allowing relational comparisons within types, or disallowing them between types. You can't do both within JavaScript currently.

Most helpful comment

I can't think of any way to do so. So it's really a question as to what's more important: allowing relational comparisons within types, or disallowing them between types. You can't do both within JavaScript currently.

BigInt chose to disallow both. Whereas all previous types chose to allow both.

(Apologies if this was previously-covered ground. Hopefully my restating adds some value in its conciseness ^_^)

All 11 comments

The issue here is that doing this without coercing to .valueOf() would require us to go down the operator overloading road. If we do coerce to .valueOf() then we create comparability across types.

This seems like a good idea. The way to do this would probably be by adding toString()s that give back the comparable strings (i.e. biggest component to smallest). Then the relational comparison operators would operate on those string representations and do the right thing.

Not necessarily.

Instant.fromString("2018-01-01T00:00:00Z") > CivilDateTime.fromString("2018-01-01T00:00:00") === ?

By string comparison, will resolve to true, but the comparison is meaningless without a time zone on the right hand side. Depending on the time zone, it could be before, equal, or after.

Fair point, the issue is comparing _between_ types. My strategy (or other ones, e.g. valueOf()) would only make sense when comparing _within_ types.

How do we prevent people from comparing between types without introducing separate comparison functions?

I can't think of any way to do so. So it's really a question as to what's more important: allowing relational comparisons within types, or disallowing them between types. You can't do both within JavaScript currently.

BigInt chose to disallow both. Whereas all previous types chose to allow both.

(Apologies if this was previously-covered ground. Hopefully my restating adds some value in its conciseness ^_^)

Since BigInt disallowed both, this should do the same.

For most Instant & ZonedInstant / ZonedDateTime comparison is already possible by being explicit. instant.nanoseconds > zoned.instant.nanoseconds compares absolute time. instant.toString() > zoned.toString() compares the local parts (via strings).

So by just being explicit, you can do comparisons. Forcing the user to be explicit is definitely a good thing in the context of dates/times, since there are so many edge-cases that implicit things will have bugs by definition.

At a high level it does not make sense to allow comparisons between the different types. eg. it is fundamentally wrong to impose an ordering on LocalDate vs LocalDateTime or Instant vs ZonedDateTime. However comparing the same type, such as LocalDate to LocalDate, is common and should be enabled as best it can.

Since BigInt disallowed both, this should do the same.

BigInt disallowed both of what? 1n < 2n works just fine. Can you please clarify?

instant.nanoseconds > zoned.instant.nanoseconds compares absolute time

Per the current spec, that compares nanoseconds _since the last complete millisecond_, and even if that changes, the fact that it is a plausible interpretation makes that expression far less explicit than you're claiming.

instant.toString() > zoned.toString() compares the local parts (via strings).

Which wouldn't work if either has a negative year (e.g., "-000086-08-06") or if only one requires an expanded year (e.g., "+010000-01-01").

there are so many edge-cases that implicit things will have bugs by definition

I find your examples to be _less_ explicit than v1 < v2, and more buggy.

Also, and most importantly, you're talking about _instants_. This issue is about civil/local values.

nanoseconds since the last complete millisecond is changing in #97 since Instant objects have no concept of days or months. The thought being that it's just a counter of POSIX-seconds.

The split came from before BigInt was a thing. At that time it wasn't possible to represent nanoseconds since epoch. Now it is.

Contrast that with the Civil objects. There we have units. So all smaler units are only sub-parts of the next bigger unit.

IIUC, this issue pertains to the ability to be able to compare different objects. That has already been taken care of through Duration and the spec text on that is being finalized now so I’d be closing this. Please feel free to reopen if you think there’s something left to be addressed here.

Was this page helpful?
0 / 5 - 0 ratings