20

I have a string representing a time in seconds and milliseconds. I want to convert it to a string in the format "hh:mm:ss,fff".

My solution still has the flaw that hours less than 10 are shown with one decimal instead of two:

PS> $secs = "7000.6789"
PS> $ts =  [timespan]::fromseconds($s)
PS> $res = "$($ts.hours):$($ts.minutes):$($ts.seconds),$($ts.milliseconds)"
PS> $res
PS> 1:56:40,679

What is the right way to achieve this? I'm sure there is a more elegant way with -f and datetime.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
nixda
  • 2,654
  • 12
  • 49
  • 82
  • Does `$res.ToString()` not fill your requirements? It does skip milliseconds if there are no relevant digits and it does append days if the hours would otherwise be higher than 23, which might not suit you. If that doesn't work, look into the `TimeSpan.ToString(string)` method, which takes a format string. The format string can either be a [standard timespan format](http://msdn.microsoft.com/en-us/library/ee372286(v=vs.110).aspx) or a [custom timespan format](http://msdn.microsoft.com/en-us/library/ee372287(v=vs.110).aspx). – Robert Westerlund Feb 18 '14 at 01:03

3 Answers3

48

In PowerShell 4.0

$s = "7000.6789"
$ts =  [timespan]::fromseconds($s)
("{0:hh\:mm\:ss\,fff}" -f $ts)

Output: 01:56:40,679


In PowerShell 2.0

$s = "7000.6789"
$ts =  [timespan]::fromseconds($s)
"{0:hh:mm:ss,fff}" -f ([datetime]$ts.Ticks)

Output: 01:56:40,679


And to go back the other way...

$text = "01:56:40,679"
$textReformat = $text -replace ",","."
$seconds = ([TimeSpan]::Parse($textReformat)).TotalSeconds
$seconds

Output: 7000.679

andyb
  • 2,722
  • 1
  • 18
  • 17
  • Thank you andyb, this works very well! (I was so free and inserted the full example, feel free to roll back). How would an example look for the complete reverse of this? For example from `01:56:40,697` to `7000.6789` – nixda Feb 19 '14 at 06:35
  • The PowerShell V2 solution worked for some of my scenarios, but for durations of >= 13 hours, the hh field returns 01-12. – Registered User Apr 04 '16 at 19:47
  • Thanks @RegisteredUser. I've modified the format strings to use the 24-hour version. – andyb Jun 16 '16 at 07:25
  • 1
    For your PowerShell 4.0 solution, I don't think the format string can include uppercase 'H' because this *results in an error*. (Probably 2016-06-16 edit?) Changing it to lowercase 'h' (`"{0:hh\:mm\:ss\,fff}"`) doesn't result in an error but I'm guessing accuracy of timespan format string will be limited to 12 hours or less. The error in PowerShell 4.0 is: `Error formatting a string: Input string was not in a correct format.. At line:1 char:1 + ("{0:HH\:mm\:ss\,fff}" -f $ts)` – JasDev Jul 06 '19 at 16:22
  • Yes, @JasDev, I think you are right. It seems the formatting logic for timespan does not support HH. I will revert back to 'hh'. – andyb Aug 02 '19 at 07:34
14

You could just use the ToString method on the TimeSpan object and specify the format you want to use. Either use one of the standard timespan formats or use a custom timespan format. For example, the following custom format gives the output you want:

$ts =  [timespan]::fromseconds("7000.6789")
$ts.ToString("hh\:mm\:ss\,fff")

This will output

01:56:40,679

Update: Updating to provide functions working in PowerShell v2

The above solution works well in PowerShell v4, but not in v2 (since the TimeSpan.ToString(string) method wasn't added until .NET Framework 4).

In v2 I guess you'll have to either create the string manually (like you are doing in the question) or doing an ordinary ToString() and manipulate the string. I suggest the former. Here's a function which works fine for that:

function Format-TimeSpan
{
    PARAM (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [TimeSpan]$TimeSpan
    )

    #Current implementation doesn't handle days.

    #By including the delimiters in the formatting string it's easier when we contatenate in the end
    $hours = $TimeSpan.Hours.ToString("00")
    $minutes = $TimeSpan.Minutes.ToString("\:00")
    $seconds = $TimeSpan.Seconds.ToString("\:00")
    $milliseconds = $TimeSpan.Milliseconds.ToString("\,000")

    Write-Output ($hours + $minutes + $seconds + $milliseconds)
}

Testing it using

$ts =  [timespan]::fromseconds("7000.6789")

Format-TimeSpan -TimeSpan $ts
$ts | Format-TimeSpan

Yields the following output:

01:56:40,679
01:56:40,679
Robert Westerlund
  • 4,750
  • 1
  • 20
  • 32
5

One line conversion :

[timespan]::fromseconds(354801857.86437).tostring()

return 4106.12:04:17.8640000

Alban
  • 3,105
  • 5
  • 31
  • 46