2

I need to convert time in seconds to HH:MM:SS.mm format. The seconds input is being read from an embedded device, and it is a double of the format seconds.millseconds. I tried the following conversion code but it fails:

set cpu_time [function_that_fetches_the_time]
puts "[clock format $cpu_time -format {%H:%M:%S}]"

This fails with the error

expected integer but got "98.92"

thrown from

"ParseFormatArgs {*}$args"
    (procedure "::tcl::clock::format" line 6)

I could convert the double to an integer and the above would work, but it'd be nice to have the milliseconds part in the output display too.

Also, what is the clock format specifier for milliseconds?

EDIT:

Seems only converting the double to an int doesn't work either. I tried

puts "[clock format [expr int($cpu_time)] -format {%H:%M:%S}]"

and it results in some strange time. For instance, when the embedded device returns 3.53 (and I cast it to a 3) the time printed out is 17:00:03.

Praetorian
  • 106,671
  • 19
  • 240
  • 328

4 Answers4

7

The simplest way to format an interval that works reliably is to just do it all by hand.

set cpu_time [function_that_fetches_the_time]
set cpu_ms   [expr { int(fmod($cpu_time, 1.0) * 1000) }]
set cpu_secs [expr { int(floor($cpu_time)) % 60 }]
set cpu_hrs  [expr { int(floor($cpu_time / 3600)) }]
set cpu_mins [expr { int(floor($cpu_time / 60)) % 60 }]
puts [format "%d:%02d:%02d.%3d" $cpu_hrs $cpu_mins $cpu_secs $cpu_ms]

You'll probably want to wrap this up in a procedure…

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
3

Regarding your edit, the reason it is showing up that way (17:00:03) is that clock format is expecting an integer number of seconds from the epoch. So, I'm guessing you are five time zones away from UTC? It is interpreting your "3" as 3 seconds past midnight on Jan 1, 1970 and then adjusting to your local time zone. Donal's answer is best if you are just converting seconds to a format (as opposed to an actual date/time to a formatted string). If you add the -gmt argument to your edited solution, you'll get the expected 00:00:03 (and then you can string append the ".53" millisecond to the result to include milliseconds.

ramanman
  • 863
  • 4
  • 7
0

the specifier for a millisecond is a single small s

try [clock format [clock seconds] -format "%H:%M:%S:%s"]

see this link

Rachel Gallen
  • 27,943
  • 21
  • 72
  • 81
  • That doesn't work, maybe the page you've linked to is for an older version of Tcl. From the Tcl 8.5 [clock man page](http://www.tcl.tk/man/tcl8.5/TclCmd/clock.htm#M61) `%s` just dumps the input argument as an integer. – Praetorian Jan 18 '13 at 22:34
0

Here's how I modified Donal Fellows answer, this could work a little better for some since it did for me.

proc time_cmd {cmd} {
    set start [clock milliseconds]
    eval $cmd
    set end [clock milliseconds]
    set runtime [expr $end - $start]
    set seconds [expr $runtime / 1000]
    set cpu_ms [expr $runtime % 1000]    
    set cpu_secs [expr { int(floor($seconds)) % 60 }]
    set cpu_mins [expr { int(floor($seconds / 60)) % 60 }]
    set cpu_hrs  [expr { int(floor($seconds / 3600)) }]
    puts [format "Command completed in %d:%02d:%02d.%-03d" $cpu_hrs $cpu_mins $cpu_secs $cpu_ms]
}
pieter3d
  • 135
  • 6