# Getting AbsoluteTiming to display in hours, minutes, and seconds

I'm doing some extended length calculations and was wondering how I could get AbsoluteTiming to display in hours, minutes, and seconds. I googled and found nothing, so I borrowed some code, edited it, and wrote:

SetAttributes[myAbsoluteTiming, HoldAll];
myAbsoluteTiming[calculation_] :=
Module[{startTime, deltaTime, result}, startTime = SessionTime[];
result = calculation;
deltaTime = SessionTime[] - startTime;
hms = {Floor[deltaTime/3600],
Floor[Mod[Floor[deltaTime], 3600]/60],
Mod[Mod[deltaTime, 3600], 60]};
{hms, result}]


This appears to be about .0005 seconds slower than the AbsoluteTiming function.

Is that time difference accurate? Is there a better way of doing this? How would I improve upon my code?

• Could you add some detail about why you don't want to use AbsoluteTiming? It's not clear to me why you wouldn't just format the first output from that function. – dionys May 7 '16 at 18:45
• @dionys No reason, I just don't know how to format AbsoluteTiming. There wasn't anything on it in the wolphram help files, and I'm a beginner. – Elem-Teach-w-Bach-n-Math-Ed May 7 '16 at 19:20
• The deltaTimes = 3700; line looks like a leftover. – Karsten 7. May 7 '16 at 21:06
• @Karsten7. Ah, yes it is. I was setting deltaTime manually to test earlier. – Elem-Teach-w-Bach-n-Math-Ed May 7 '16 at 21:07

## 5 Answers

SetAttributes[hmsAbsTiming, HoldAllComplete];
hmsAbsTiming[calculation_] :=
MapAt[IntegerDigits[IntegerPart[#], MixedRadix[{24, 60, 60}]] &,
AbsoluteTiming[
calculation
], 1]


If you prefer a Quantity object:

SetAttributes[hmsAbsTiming2, HoldAllComplete];
hmsAbsTiming2[calculation_] :=
MapAt[UnitConvert[Quantity[#, "Seconds"], MixedUnit[{"Hours", "Minutes", "Seconds"}]] &,
AbsoluteTiming[
calculation
], 1]


There is a TimeString function in the GeneralUtilities context that is very convenient here.

Needs["GeneralUtilities"]

SetAttributes[hmsAbsTiming3, HoldAllComplete];
hmsAbsTiming3[calculation_] := MapAt[TimeString[#] &, AbsoluteTiming[calculation], 1]


Benchmark:

RepeatedTiming[hmsAbsTiming[Pause[0.001]], 30]
RepeatedTiming[hmsAbsTiming2[Pause[0.001]], 30]
RepeatedTiming[hmsAbsTiming3[Pause[0.001]], 30] • I'm getting: Quantity::unkunit: Unable to interpret unit specification MixedUnit[{Hours,Minutes,Seconds}] when I run the quantity one. – Elem-Teach-w-Bach-n-Math-Ed May 7 '16 at 20:40
• Here's an image: imgur.com/poRDnVM – Elem-Teach-w-Bach-n-Math-Ed May 7 '16 at 20:46
• You were right: \$Version returns "10.3.1 for Linux ARM (32-bit) (January 11, 2016)" for the Pi and is up-to-date. – Elem-Teach-w-Bach-n-Math-Ed May 8 '16 at 22:02
• @Elem-Teach-w-Bach-n-Math-Ed Starting version 9.0, you can use the built-in MixedRadixQuantity. The part UnitConvert[...] & in Karsten code could be replaced by MixedRadixQuantity[{0, 0, #}, {"Hours", "Minutes", "Seconds"}] &. – user31159 May 9 '16 at 7:07
• @Elem-Teach-w-Bach-n-Math-Ed Not documented, but this also works: UnitConvert[Quantity[#, "Seconds"], MixedRadix["Hours", "Minutes", "Seconds"]] &. – user31159 May 9 '16 at 7:15

Here's my take, borrowing some code from here and here:

ic = Function[x, With[{r = Round[x]}, r + Chop[x - r]], Listable];

SetAttributes[myTiming, HoldAllComplete];
myTiming[calculation_, tf : (Timing | AbsoluteTiming) : AbsoluteTiming] :=
Module[{timing = tf[calculation]},
Print[StringTemplate["h hr m min s s",
InsertionFunction -> (ToString[#, TraditionalForm] &)]
@ AssociationThread[{"h", "m", "s"},
ic[N[DMSList[SetPrecision[timing[], ∞]/3600]]]]];
If[Length[timing] == 2, timing[], Sequence @@ Rest[timing]]]


Some examples: Here is a simple and universal function which formats timings (for real-time monitoring of elapsed time one should replace Round with Floor):

formatTiming =
StringJoin[{If[# >= 100, ToString@#, IntegerString[#, 10, 2]] &@Floor[#/3600], ":",
IntegerString[Floor[Mod[#, 3600]/60], 10, 2], ":",
IntegerString[Mod[#, 60], 10, 2]} &@Round[#]] &;


Examples of use:

formatTiming@1

"00:00:01"

formatTiming@60

"00:01:00"

formatTiming[200*3600 + 60*2 + 2]

"200:02:02"

formatTiming[AbsoluteTiming[Pause][]]

"00:00:01"


Benchmark:

Needs["GeneralUtilities"]
RepeatedTiming[formatTiming[AbsoluteTiming[Pause[.001]][]], 30]

{0.0010, "00:00:00"}

• Another way: formatTiming = StringRiffle[Map[IntegerString[#1, 10, If[#1 > 99, Unevaluated[], 2]] &, DMSList[Round[#]/3600]], ":"] & – J. M.'s torpor Jun 1 '16 at 3:49

Using Mathematica's built-in unit conversion & getting rid of the annoying "0 years, 0 hours ...":

timeConvert=Quantity@@@(Delete[#,List/@Position[#,0][[All,1]]]&[
Transpose[{#[[1,1]],#[[2,1]]}]&[
UnitConvert[Quantity[#,"Seconds"],
MixedRadix["Years","Months","Days","Hours","Minutes","Seconds"]]]])&;

In:=timeConvert[14695241.8]
Out={Quantity[5, "Months"], Quantity[18, "Days"],Quantity[41.8, "Seconds"]}


I like @Karsten's approach of making a pure function that can be applied directly to format results from AbsoluteTiming, but if you're new to Mathematica this might be easier to follow:

SetAttributes[myAbsoluteTiming, HoldAllComplete];
myAbsoluteTiming[calculation_] :=
Module[{time, result, days, hours, minutes, seconds, format},
{time, result} = AbsoluteTiming[calculation];
With[{dy = 86400, hr = 3600, mn = 60},
days = Floor[time/dy];
time = Mod[time, dy];
hours = Floor[time/hr];
minutes = Floor[Mod[time, hr]/mn];
seconds = Floor[time - hr*hours - mn*minutes]];
format = IntegerString[#, 10, 2] &;
If[days > 0,
{StringJoin[Riffle[format /@ {hours, minutes, seconds}, {":"}], " +", IntegerString[days], " days"], result},
{StringJoin[Riffle[format /@ {hours, minutes, seconds}, {":"}]], result}]]

myAbsoluteTiming[Pause]
(* {00:00:01, Null} *)
`
• Thanks. Going to give this a try for comparison sake with the other answers to see which runs most efficiently. – Elem-Teach-w-Bach-n-Math-Ed May 7 '16 at 21:13