-
Notifications
You must be signed in to change notification settings - Fork 110
Instant.until(Instant, DateTimeUnit.TimeBased) and until(Instant, DateTimeUnit, TimeZone) maybe shouldn't be overloads #89
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
Comments
Semantically they are more or less overloads. One could implement fun Instant.until(other: Instant, unit: DateTimeUnit.TimeBased) = until(other, unit, TimeZone.UTC) Though such an implementation would throw more often than what we have now.
I don't see why we would want to discourage its use. The reason it doesn't take time zones into account is that it doesn't matter in which time zone to add 15 seconds to an |
Unless of course you're adding 15 seconds during a DST transition... From an internal "best practices" guide (emphasis my own):
I still don't think these should be overloads: they have slightly different behaviors (the fact that the behaviors are the same 99.9% of the time is actually even worse -- users won't know they have a bug until their code has some weird DST bug. |
Nope, DST transitions don't affect this operation. Functionally this is true because we even implement Semantically this is true because We need to know the time zone to add date-based units to Instants because when we need to add 2 days, that is, go from 21:30 of July 15 to 21:30 of July 17, the difference between the two moments may not always be 48 hours due to transitions. |
I think the behavior is well-defined, but the worry is that it's easy to mistake one for the other. In fact, if you're implementing val until1 = instant1.until(instant2, HOUR * 24)
val until2 = instant1.until(instant2, HOUR * 24, TimeZone.of("America/New_York"))
val until3 = instant1.until(instant2, DAY, TimeZone.of("America/New_York")) It's not immediately obvious that One thing you could do to disambiguate is to require a |
Could you elaborate on this? If the client code operates on a unit that's known to be time-based, there is no reason to pass the time zone as it would not be used anyway, and so the shorthand version is available and even preferred. If the unit is not known to be time-based, it's impossible to call the shorthand version, so there is no potential for confusion.
Is there a defensible implementation of
What do you propose to do in the polymorphic case where it's unknown whether the unit is date-based or time-based? Not providing an
Which functions are you talking about here? |
I agree there's no reason to use the time zone for time-based units. But having a method that sometimes ignores one parameter based on the value of another parameter will lead to people writing subtle bugs. For example, it's possible for someone to use a time-based unit that seems like a day-based unit: val DAYS = HOURS * 24
val lengthInDays = start.until(end, DAYS, timeZone) // I expect it to consider the time zone, but it won't I know that there's already a day-based
I'm not sure. I think I would consider excluding that by having no
I think the fact that the behavior is subtly but meaningfully different in that a whole parameter is either required or not applicable means that polymorphism in this case may be more confusing than helpful. People will write bugs because the type system silently ignores information it can't use rather than making the programmer be explicit. If you change that to
Sure, but that might be surprising to users who don't expect the time zone, a required parameter, to be ignored. |
Ok, I see your point now. Thank you for the thorough response! True, the compiler can prevent some mistakes if we process That said, there are trade-offs to this beyond just inconveniencing the user by forcing them to case on their units. The problem is, making this distinction would be inconsistent with the existence of However, Java Time already tried this with True, in the edge case when the only nonzero components of a The overall point is, the change you're proposing is not free and would lead to some difficult decisions. Also, I would think that people who do understand the dangers of DST transitions would also research what semantics the different val DAY = DateTimeUnit.HOUR * 24 // not DateTimeUnit.DAY so the compiler shuts up about the time zones
val lengthInDays = start.until(end, DAY) |
In the end, this doesn't seem worth pursuing. One important point is that now, Also, after looking through how people are using |
The following two APIs on
Instant
aren't really overloads:until(Instant, DateTimeUnit.TimeBased)
until(Instant, DateTimeUnit, TimeZone)
One takes timezones into account and the other one doesn't. That doesn't seem like a great pair of APIs to be overloads of one another. Perhaps the time-based one should have a longer, scarier name to discourage use? (e.g.,
timeUntil()
ortimeUnitsUntil()
)Same issue for the analogous
plus()
andminus()
overloads onInstant
.The text was updated successfully, but these errors were encountered: