Using time (minutes, seconds) to calculate duration of events

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.

1 Like

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!

1 Like

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! :sweat_smile: 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 :slight_smile:

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

1 Like

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
3 Likes