There is currently a PR on the repo with very lively discussion about what the following operation should do:
using Dates a = now() b = a + Nanosecond(1)
(the situation is analogous with
Currently, the result is always exactly equal to
a, because the
DateTime arithmetic implemented in
Dates simply truncates the non-
DateTime argument to milliseconds (as that is the supported precision of
DateTime), and whatever the result is, will be added to
julia> using Dates julia> a = now() 2023-08-18T14:35:44.462 julia> a === a + Nanosecond(1) true julia> a === a + Microsecond(999) true julia> a === a + Microsecond(1000) # now we're at the millisecond scale false julia> (a + Microsecond(1000)) === (a + Microsecond(1999)) true
This has consequences when trying to accumulate a number of durations into a
DateTime, for example to figure out how long some continued measurements took, perhaps from samples of an oscilloscope:
julia> a = now() julia> reduce(+, fill(Microsecond(1234), 10000), init=a) 2023-08-18T14:22:02.527 julia> a + reduce(+, fill(Microsecond(1234), 10000), init=Nanosecond(0)) 2023-08-18T14:22:04.867
This, where two different forms of accumulation lead to different results, happens because in the first form due to the repeated truncation there is an accumulation of error, and thus the result will not be as exact as it could be. In essence,
DateTime + Nanosecond or
DateTime + Microsecond are not associative. This is problematic, because the dataloss is silent, and near impossible to catch after the fact - especially if you don’t have access to the original data anymore.
There are more or less three ways to resolve this:
- Keep the current behavior, and simply document that this kind of arithmetic does some form of rounding.
- Increase the precision of
Nanosecondprecision (and not support smaller scales at all, effectively pushing the failure case to higher precisions, but not solving it entirely). This would necessitate an increase in size of
DateTime(from currently 64 bits to 128 bits, to accomodate the additional data needed to keep track of everything).
- Deprecate the existing behavior, and direct users to use
flooron their too-small-to-fit-in-
DateTimecalculations, to explicitly specify the behavior they want. Only arithmetic with exact results are allowed - the methods in question would be removed when (if ever) a breaking release in Julia happens.
I’m personally in favor of option 3), because it’s my believe that a programming language (and standard library, targeting a very general use case) should have as few foot guns as possible, and should give hints & nudges towards correct usage for their application, with as few guesses about what the user cares about as possible.
I’d like to hear what the community thinks though, and in particular I’d like to hear from people who often use this kind of arithmetic and what they’d expect to happen in these circumstances.