How to Print/Parse a TimePeriod with a Specific Format?

Hi!

I want to parse and print durations in the format "HH:MM:SS.sss". Parsing seems to be pretty simple. if I do for example

julia> str = "1:02:23.234"
"1:02:23.234"
julia> t = Time(str)
01:02:23.234

this seems to work just fine. However, this is not a TimePeriod but a time.

If I want to go the other way and print TimePeriods in that format I’m running into problems:

julia> Dates.format(Time(Second(32)), "HH:MM:SS.sss")
"00:00:32.000"

works fine but

julia> Dates.format(Time(Second(432)), "HH:MM:SS.sss")
ERROR: ArgumentError: Second: 432 out of range (0:59)

throws an error. Dates.format does not take TimePeriods for an argument:

julia> Dates.format(Second(432), "HH:MM:SS.sss")
ERROR: MethodError: no method matching format(::Second, ::String)

Working with CompoundPeriods also does not work:

julia> d = Minute(2) + Second(10)
2 minutes, 10 seconds

julia> Dates.format(Time(d), "HH:MM:SS.sss")
ERROR: MethodError: no method matching Int64(::Dates.CompoundPeriod)

Does anyone know if there’s a built in way to print my duration in the desired format, is there any package that deals with this, or do I have to write a custom function?

You can use Time(0) + Second(…) instead of Time(Second(…)):

julia> Time(0) + Second(432)
00:07:12

julia> Dates.format(Time(0) + Second(432), "HH:MM:SS.sss")
"00:07:12.000"
1 Like

That’s it! Thanks! :slight_smile:

Actually, using the CompoundPeriods package it does:

using Dates, CompoundPeriods
d = Minute(2) + Second(10)
Dates.format(Time(d), "HH:MM:SS.sss")
"00:02:10.000"

There is an easier (more elegant?) solution.

  • You have to know that only Time, Date and DateTime types are printable (aka formatable)

Once you know this, you convert to one of these types. In your case, you want to convert to a Time type using the constructor function Dates.Time(...).

So do something like this

using Dates
d = Minute(2) + Second(10)
println(typeof(d)) # Dates.CompoundPeriod

time  = Dates.Time(canonicalize(Dates.CompoundPeriod(d)).periods...)
time_str::String = Dates.format(time, "HH:MM:SS")
println("$(time_str)")

The “special sauce” here is twofold

  • canonicalize converts any CompoundPeriod to the canonical form, the trick here being to created it from the splayed .periods field (this is what the d.periods... is about
  • you can then create a Time object from this CompountPeriod object