`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.

3 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[1]
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:
 [1] unsafe_getindex(::LinRange{DateTime}, ::Int64) at .\range.jl:663
 [2] getindex(::LinRange{DateTime}, ::Int64) at .\range.jl:642
1 Like

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

1 Like