# `range` of `DateTime`s

I want to create a uniformly-spaced range of `DateTime` values with e.g. 100 points between two given values. `range` function doesn’t work for me: `range(DateTime(2000, 1, 1, 0, 0), DateTime(2000, 1, 2, 0, 0), length=100)` gives `MethodError: no method matching *(::Float64, ::DateTime)`, and I cannot find an easy way to do this. Note that `range` with `step` instead of `length` does work, e.g.: `range(DateTime(2000, 1, 1, 0, 0), DateTime(2000, 1, 2, 0, 0), step=Minute(1))`.
Am I missing some obvious solution here?

There was a similar question two years ago here - Linspace with DateTime - but there is no answer, and lots of stuff have changed in Julia since then.

4 Likes

The solution is in that same post:

``````function mylinspace(d1::DateTime, d2::DateTime, n::Int)
Δ = d2 - d1
T = typeof(Δ)
δ = T(round(Int, Dates.value(Δ)/(n - 1)))
d2 = d1 + δ*(n - 1)
return d1:δ:d2
end
``````
1 Like

I found this one, because I love comprehensions:

``````[ DateTime(Dates.UTInstant{Millisecond}(Millisecond(Int64(floor(x))))) for x in range(Dates.value(d1),Dates.value(d2),length=100)]
``````

But its not a range, just an array.

A major difference between this implementation and builtin `range(a, b, length)` (e.g. for numbers) is that the last element of `mylinspace` isn’t equal to `d2` argument. Even more, the last element can be larger that `d2`! And these are just the obvious things I noticed.

Anyway, it’s strange that `range` is not supported for `DateTimes`. This cannot be intentional, right?

Yea, I know. You are right that the last element can be larger, that’s a problem. But as to it being equal to `d2` `range` doesn’t do that either:

``````julia> range(0, 1, step = 0.11)[end]
0.99
``````

`range` with `step` doesn’t, but that’s fine - it’s impossible if `b-a` is not divisible by `step`. But `range` with `length` does have the property that `range(a, b, length)[end] == b` as far as I can see.

Just because the calculated step can be a Float. So range is exact only in the limits of Floats.

DateTime has a similar limitation in the sense that Nanosecond is the smallset step it can encode.

Perhaps it would be good to create an issue for this?

You can use `range` to create a `LinRange{DateTime}`, though it fails on `show`, or `getindex`. Only `first` seems to work, here on julia 1.3 rc2:

``````using Dates
starttime = DateTime(2000, 1, 1, 0, 0)
endtime = DateTime(2000, 1, 2, 0, 0)
r = range(starttime, endtime, length=5);  # no error as long as you suppress show with a ;
typeof(r)  # -> LinRange{DateTime}
first(r)  # -> 2000-01-01T00:00:00
r
``````
``````ERROR: MethodError: no method matching *(::Float64, ::DateTime)
Closest candidates are:
*(::Any, ::Any, ::Any, ::Any...) at operators.jl:529
*(::Float64, ::Float64) at float.jl:405
*(::AbstractFloat, ::Bool) at bool.jl:112
...
Stacktrace:
 unsafe_getindex(::LinRange{DateTime}, ::Int64) at .\range.jl:663
 getindex(::LinRange{DateTime}, ::Int64) at .\range.jl:642
``````
1 Like

I filed the issue: https://github.com/JuliaLang/julia/issues/35446

3 Likes

If you are fine with a uniformly-spaced (as good as possible) vector of DateTime values you can compute the range in unix and convert back to DateTime objects. For example:

function GetTimestampRange(firstTimestamp, lastTimestamp, length)
firstTimestampAsUnix = datetime2unix(firstTimestamp)
lastTimestampAsUnix = datetime2unix(lastTimestamp)
vecOfUnixTimestamps = [range(firstTimestampAsUnix, lastTimestampAsUnix, length = length)…]
return unix2datetime.(vecOfUnixTimestamps)
end

1 Like

If you’re willing to try NanoDates.jl, you can get a range similar to what you wanted originally. However, instead of giving range an integer length, you have to give it a Period.

``````using Dates, NanoDates

nd1 = NanoDate(2000, 1, 1, 0, 0)
nd2 = NanoDate(2000, 1, 2, 0, 0)
step = Nanosecond((nd2 - nd1).value ÷ 100) # The division must return an integer.
r100 = nd1:step:nd2
r15m = nd1:Minute(15):nd2
r4h = nd1:Hour(4):nd2
``````

What’s the benefit here compared to Dates? They also allow ranges with manually specified steps, as I understand.

I should have experimented a little bit more before posting. My newness to Julia is showing, and I didn’t realize DateTime could do nearly the same thing in this case.