# DateTime: Time division

I was wondering how division works on time intervals.

My naïve thought doesn’t work

``````using Dates
hr = Dates.Hour(1)
t1 = DateTime(2023, 1, 3)
r = 7.4
t2 = t1 + hr/r # ->InexactError: Int64(0.13513513513513511)
``````

The following works only for some values of `r`:

``````tdummy = t1 + hr
t2 = t1 + (tdummy - t1).value / r # -> works only for some values of r
``````

`tdummy - t1` is of type `Millisecond` and if the division results in an integer, the above code works.

The following works in general:

``````tdummy = t1 + hr
t2 = t1 + Dates.Millisecond(round((tdummy - t1).value/r))
``````

But, is this really what’s intended? I thought there should be a more elegant solution.

What is the standard way to express “t1 + onehour/r” for a general real number `r` ? It seems to me that we need a proper “time interval type” which works seamlessly with `DateTime`.

Yeah, float-based time intervals are often more convenient than integers. Julia doesn’t have them in stdlib, unfortunately.
See (my) `DateFormats.jl` package that helps dealing with different date/time formats, including decimal periods:

``````julia> using Dates, DateFormats

julia> DateTime(2023, 1, 3) + 1/7.4 *ₜ Hour
2023-01-03T00:08:06.486
``````
1 Like

Note that you can convert from lower to higher precision time periods where the answer is always the same (so you can do `Millisecond(Hour(1))` but not `Day(Month(1))`). This just skips the need for your dummy variable:

``````using Dates
hr = Dates.Hour(1)
t1 = DateTime(2023, 1, 3)
r = 7.4
t1 + Millisecond(round(Millisecond(hr).value/r))
``````

This does seem annoying. But the reason all sorts of fractional arithmetic doesn’t just work is because

Period types represent discrete, human representations of time.

as opposed to physical durations of time. The `lubridate` cheatsheet for `R` is good for seeing how complex things need to be to support date arithmetic fully.

1 Like

From which your example could be written, with the help of `CompoundPeriods`, as:

``````using Dates, CompoundPeriods
import Base: / , *
/(t::Dates.CompoundPeriod, x::Real) = canonicalize(Dates.CompoundPeriod(Millisecond(round(Int64,Dates.toms(t)/x))))
*(t::Dates.CompoundPeriod, x::Real) = canonicalize(Dates.CompoundPeriod(Millisecond(round(Int64,Dates.toms(t)*x))))

hr = Hour(1) |> CompoundPeriod
t1 = DateTime(2023, 1, 3)
r = 7.4
t2 = t1 + hr/r      # 2023-01-03T00:08:06.486

``````
3 Likes

Thanks!

Your code is corrupted on my screen (webbrowser) but I get what it is:

``````DateTime(2023, 1, 3) + period_decimal(Hour, 1/7.4)
``````

from the automatic email message sent me by discoursemail.com .

Thanks. I understand that. I understand that the `Dates` package isn’t designed with this usage in mind.

The original motivation of my post is to ask whether there is already a standard method to handle physical duration of time.

In the future, it would be nice if “we” have

``````using FloatingDates
del = Hour(1.25) # a CompoundPeriod
t1 = DateTime(2023, 1, 3) # a floating-point version
r  = 7.4
t2 = t1 + del/r
``````

to use `CompoundPeriod` implicitly.

I keep needing DateTime arithmetics in such a construct as

``````t1 = DateTime( . . . )
t2 = DateTime( . . . )
del = Hour(1) + Minute(30)
time_axis = (t1 + del/2):del:(t2 - del/2)
@assert length(time_axis) == length(somedata)
plot(time_axis, somedata)
``````

because I sometimes have to deal with datasets without a proper time axis.

In that case, do consider `Unitful.jl`:

Incidentally, your desired code does work if you change the compound period `del = Hour(1) + Minute(30)` to a simple period `del = Minute(90)`.

``````t1 = DateTime("2023-01-01")
t2 = DateTime("2023-01-02")
del = Minute(90)
time_axis = (t1 + del/2):del:(t2 - del/2)
``````

I wonder why using a compound period as a range step isn’t implemented? Perhaps we can get it added!

That also works, and was indeed my message before I edited it. I recently noticed that multiplication/division is more natural for this operation than the `period_decimal` function, and made a new `DateFormats` version with `*ₜ` and `/ₜ` operators. This message prompted me to actually release the new version, so I updated the message on discourse.
Meaning of `1/7.4 *ₜ Hour` is more obvious than `period_decimal(Hour, 1/7.4)`, so I suggest using this operator.

You seem to ignore the context of this discussion: It seems to me that you lift my words out of the context and propose a solution that doesn’t work in the present context. The following code doesn’t work:

``````using Dates
using Unitful
del = 1u"hr" + 5u"minute" + 2u"s"
t1 = DateTime(2023, 1, 29)
t2 = t1 + del/5 # MethodError: no method matching +(::DateTime, . . .
``````

From the context of this discussion, it’s clear that I’m wanting a method to handle physical duration of time together with `DateTime`. (But, it would be nice if `Dates` worked with the time in the `Unitful` package.)

I know that! Yours isn’t my “desired code”. Again you lift my example out of the context. The code you wrote stops working once we introduce division:

``````t1 = DateTime(2023, 1, 29)
t2 = DateTime(2023, 5, 29)
del = Minute(90) / 3.14
time_axis = (t1 + del/2):del:(t2 - del/2)
``````

Wanting a time interval type that allows for usual arithmetics as if it were a floating-point number together with DateTime, is the starting point of this discussion!