I’ve read and tried the functionality included in Julia 1.0 for dates and times… I do not find an easy way - without defining functions or making manual calculations - of doing something simple as calculating the average pace when running a distance… In Excel is just one line of code… For example, if the total time is 32m45s, the pace is 32m45s /5 = 6m33s… How can this be done in Julia?
What have you tried so far? Maybe have a look at the docs, especially the Period
or the Time
type (there do seem to be some missing arithmetic for durations though).
It seems Dates
is intended for use for actual dates “management”. Division of an actual date is not something meaningful (for example, what is something div( 09/06/2018 , 5)
supposed to mean?)
For your actual usage I think you’d be better of with something like Unitful.jl where just the unit “time” is defined.
But it seems it is not updated to Julia v1.0 yet.
Unitful is also a good idea, but you’re going to lose that separation between minutes and seconds - perhaps a new package for duration arithmetic would be good, since there doesn’t seem to be one? I’m thinking regular operations (*, /, %, +, -, for a start?) with conversion between different overflow points (e.g. 50h 32m 22s
would be possible without overflowing, but 50h 70m 22s
would not be; that would overflow to 51h 10m 22s
). Doesn’t seem too complicated.
Dates
does provide that mixed presentation to some degree, but breaks down when trying to add more seconds to this compund form:
julia> using Dates
julia> Minute(50)
50 minutes
julia> typeof(ans)
Minute
julia> Minute(50) + Minute(60)
110 minutes
julia> Minute(50) + Minute(60) + Second(30)
110 minutes, 30 seconds
julia> typeof(ans)
Dates.CompoundPeriod
julia> ans + Second(700)
ERROR: MethodError: no method matching +(::Type{Dates.CompoundPeriod}, ::Second)
Closest candidates are:
+(::Any, ::Any, ::Any, ::Any...) at operators.jl:502
+(::Dates.CompoundPeriod, ::Period) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.0/Dates/src/periods.jl:347
+(::Time, ::TimePeriod) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.0/Dates/src/arithmetic.jl:82
...
Stacktrace:
[1] top-level scope at none:0
Good catch on the distinction between a real Time and a Duration, @Evian!
Note that your ans
variable is the DataType
Dates.CompoundPeriod
, that is why it is not working.
julia> using Dates
julia> Minute(50)
50 minutes
julia> typeof(ans)
Minute
julia> Minute(50) + Minute(60)
110 minutes
julia> t = Minute(50) + Minute(60) + Second(30)
110 minutes, 30 seconds
julia> t + Second(700)
110 minutes, 730 seconds
What doesn’t work is division:
julia> t/5
ERROR: MethodError: no method matching /(::Dates.CompoundPeriod, ::Int64)
Closest candidates are:
/(::Missing, ::Number) at missing.jl:93
/(::BigInt, ::Union{Int16, Int32, Int64, Int8, UInt16, UInt32, UInt64, UInt8}) at gmp.jl:465
/(::BigFloat, ::Union{Int16, Int32, Int64, Int8}) at mpfr.jl:380
...
Stacktrace:
[1] top-level scope at none:0
On Julia v0.6.4 with Unitful
you are able to do that:
julia> using Unitful
julia> (32u"minute" + 45u"s")/5
393//1 s
But the result will always be in seconds…
Of course, thank you! It’s also not working for *
.
Yes, that’s what I meant when I said you’d be losing the distinction between the fields - which is quite useful when talking about a Duration. That’s why I suggested maybe a new package would be a good idea for this
I think that this is just a display/formatting issue. Work with seconds, display in mm:ss
While true, fixing that display for just that specific use case using Unitful seems not that easy - and to do it without type piracy or overwriting some other display seems outright impossible to me (unless I’m missing something). At least when trying to support the custom final overflow field I described above.
If the only thing I need to fix is displaying the result, I would just use a wrapper type and define Base.show
for it.
Thank you all of you for your answers and feedback. Here are my thoughts… You are the experts… As Date and Time are part of the Julia 1.0, I would extend the functionality for ‘duration’ in the next version, allowing for example operations. I would simplify the usage of period too by allowing its creation using a string. I would NOT create a separate package for it. If my memory still works, thats how other languages do.
What about
julia> d1
2018-09-03T11:49:09
julia> d2
2018-09-03T11:45:33
julia> period = d1-d2
216000 milliseconds
julia> Dates.format(convert(DateTime, period), "MM:SS")
"03:36"
julia> speed = 300/(Dates.value(period)/1000)
1.3888888888888888
-
on Date
, Time
, etc already returns a specific type for the difference between the two, what are you proposing to do differently?
julia> using Dates
julia> d1 = Dates.now(); sleep(5); d2 = Dates.now()
d2 - d1
2018-09-07T07:46:47.7
julia> d2 - d1
5008 milliseconds
@Tamas_Papp How would you convert these 5008 milliseconds to, say, seconds? AFAIK (correct me if I’m wrong) you have to use something like Dates.value(d2-d1)/1000
. Arguably (d2-d1)/1000
would be nicer. Or maybe convert(Second, d)
.
You cannot convert(Second, Δ)
since you get an InexactError
in general, but for display purposes (internal calculations within the show
method)
divrem(Δ, Millisecond(1000))
and similar should work.
This works as long you use time with its constrains, for example, number of hours less than 24…
as mentioned before 1) it does not allow hours greater than 24 (time and period are two different things) and 2) the results is milliseconds and it needs to be converted into minutes and seconds. I would expect a simple operation like d1 = 72m12s ; d1/5 = 14m26s400ms
You can do
julia> DateTime(0,1,1)+(Second(Minute(32))+Second(45))/5
0000-01-01T00:06:33
which is so far the shortest suggestion replicating the Excel example as closely as possible, I think.
It would be nicer not having to add a DateTime, to get a segmented period (days, hours, …).
julia> canonicalize(Dates.CompoundPeriod((Second(Minute(32))+Second(45))/5))
6 minutes, 33 seconds