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