# Constructing dates from a vector of numbers?

I have a solution of a differential equations problem, with a given time vector, say 50 values in the range [0,10]. I want to use date along the abscissa axis in the plot. So essentially, I want to associate time 0 from the differential equation to, say, October 1, 2020, and so on.

Question: Is there a way to take a vector, say `time = range(0,10,length=50)` and add an initial date so that the result becomes a vector of dates?

Question: Would I have to interpolate the solution of the differential equation at integer times to achieve this?

Not clear enough, if you have 0 as Oct 1st, what would 0.20408 (second element in your `time` array) be, Oct 2nd? if so, then you only really care how long the `time` vector is:

``````julia> time_d = range(Date(2020, 10, 1); step=Day(1), length=length(time))
Date("2020-10-01"):Day(1):Date("2020-11-19")
``````
1 Like

This is not quite what I need. This would be pretending that the time step is 1 day, but it is not. Differential equation solvers typically use variable step length.

Still, your answer helps me if I interpolate the solution once a day.

It is possible that I need to use `DateTime` (??) to handle it properly. And – you have a point: I need to specify which time of day the clock starts.

yes you need DateTime for finer grain

I did fixed step size because your `time` has fixed step.

Here is approximately what I was looking for:

``````function add_float2datetime(x,datetime)
d = Int(floor(x))
e = x-d
h = Int(floor(e*24))
e = e-h/24
m = Int(floor(e*24*60))
e = e-m/24/60
s = Int(floor(e*24*60*60))
e = e-s/24/60/60
ms = Int(floor(e*24*60*60*1e3))
return datetime+Day(d)+Hour(h)+Minute(m)+Second(s)+Millisecond(ms)
end
#
dt = DateTime(2020,10,1)
x = range(0,10,length=50)
#
``````

``````50-element Array{DateTime,1}:
2020-10-01T00:00:00
2020-10-01T04:53:52.653
2020-10-01T09:47:45.306
2020-10-01T14:41:37.959
⋮
2020-10-10T09:18:22.04
2020-10-10T14:12:14.693
2020-10-10T19:06:07.346
2020-10-11T00:00:00
``````

My function is not elegant… it could have been improved with test on argument types, and generalized in case `x` is something else than day.

Two other improvements…

• I could have skipped the “add to” part, i.e., argument `datetime` if it had been possible to create a `DateTime` type with zero value for month… Maybe there is another way to do that.
• Perhaps this function already exists? My second HP calculator, the HP-29c (produced in 1975; I bought it in 1979 or so), had functions -> H.MS and ->H .
1 Like

It can be written shorter in this way

``````using Dates
import Dates: DateTime

function Dates.DateTime(x::Float64, origin = DateTime(0))
time = Millisecond(Int(floor(Millisecond(Day(1)).value * x)))
return origin + time
end
``````

with the result

``````julia> dt = DateTime(2020,10,1)
2020-10-01T00:00:00

julia> x = range(0,10,length=50)
0.0:0.20408163265306123:10.0

julia> DateTime.(x, dt)
50-element Array{DateTime,1}:
2020-10-01T00:00:00
2020-10-01T04:53:52.653
2020-10-01T09:47:45.306
2020-10-01T14:41:37.959
``````

On the other hand, you can remove `origin` and convert time periods to time periods and adding origin later

``````function timeperiod(x::Float64)
Millisecond(Int(floor(Millisecond(Day(1)).value * x)))
end
``````

and

``````julia> timeperiod.(x)
50-element Array{Dates.CompoundPeriod,1}:
empty period
17632653 milliseconds
35265306 milliseconds
52897959 milliseconds
70530612 milliseconds
88163265 milliseconds
105795918 milliseconds

julia> dt + timeperiod.(x)
50-element Array{DateTime,1}:
2020-10-01T00:00:00
2020-10-01T04:53:52.653
2020-10-01T09:47:45.306
2020-10-01T14:41:37.959
2020-10-01T19:35:30.612
2020-10-02T00:29:23.265
2020-10-02T05:23:15.918
``````
4 Likes

Very nice!

What is not clear to me…

• do you add a method to function `DateTime` here?
• in other words: does your function definition constitute a modification/new method to the `Dates` package? [Probably not? By adding this function with name `Dates.DateTime`, it is only defined in the current session…??]

Yes. Well, not me, but @Skoffer does that, .

Yes. All now calls to `Dates.DateTime` can end up ambiguous because of that. This is the reason Type Piracy is not encouraged. If he added a new method using a a new type introduced by them, then there would be no risk of some code (loaded before this change and unaware of it) end up calling the new method when it was not wanted.

Addendum: @Skoffer did specifically `import` that function because if you get a function name by means of `using` you cannot add a new method to it, so as a safety net to avoid doing something disastrous without noticing.

4 Likes

Sorry for this confusion, I should have warn you that this is type piracy and it is not needed at all. You may use any other function name (like `add_datetime`) and it’ll work just fine.

On the other hand, it is not a first time I see request for constructing date time from float value, so I suppose it worth a PR to Dates or at least small separate package.

2 Likes

A design choice of `timeperiod(x;...)` is: should one allow the user to specify (i) the time unit of `x` (Day? Hour? etc.) and the accuracy (millisecond? second? etc.).

You should do what best suits your needs But the time unit is nice and rather cheap to implement, so why not?

``````using Dates

function timeperiod(x::Float64, timeunit=Day(1))
Millisecond(Int(floor(Millisecond(timeunit).value * x)))
end
``````

with an outcome

``````julia> origin = DateTime("2020-10-01")
2020-10-01T00:00:00

julia> x = range(0,10,length=50)
0.0:0.20408163265306123:10.0

julia> origin + timeperiod.(x)
50-element Array{DateTime,1}:
2020-10-01T00:00:00
2020-10-01T04:53:52.653
2020-10-01T09:47:45.306
2020-10-01T14:41:37.959

julia> origin + timeperiod.(x, Hour(1))
50-element Array{DateTime,1}:
2020-10-01T00:00:00
2020-10-01T00:12:14.693
2020-10-01T00:24:29.387
2020-10-01T00:36:44.081

julia> origin + timeperiod.(x, Day(7))
50-element Array{DateTime,1}:
2020-10-01T00:00:00
2020-10-02T10:17:08.571
2020-10-03T20:34:17.142
2020-10-05T06:51:25.714
``````
2 Likes