1

I am trying to convert a timestamp to milliseconds in a script using an external program. The external program outputs the time in the shortest possible format Example the external program can output any of the following formats:

"1:33.823" #1min:33 seconds.823 - shortest
"11:33.823" #11min:33 seconds.823 - short
"1:11:33.823" #1 hour 11min:33 seconds.823 - long

I need this value converted in milliseconds. so I tried [timestamp] $mystring but it complains about the format in the first case. I thought about parsing the format manually with something like

$format='h\:mm\:ss\.ff'
[timespan]::ParseExact($mystring,$format , $null) 

But the problem with this approach is that I have to predict every possible output format of the external program and implement all the cases manually (if shortest then $format=m\:ss\.fff else if short then $format=...

Or I can possibly split and define the string, loop from the back and define the attributes of the TimeSpan object manually.

My question is: are there any standard (good practice) conversion methods for my case provided in the language or are my "quick and dirty" solutions common?

Thanks

user206904
  • 504
  • 4
  • 16
  • It sounds like the "external program" is reporting elapsed time and not a timestamp. I think you want to use `[timespan]::Parse($mystring) `. – Jonathan Dodds Jan 08 '23 at 20:49
  • 1
    @JonathanDodds, yes it is elapsed time actually, `$t="1:33.823";[timespan]::Parse($t)` won't work, thus the question – user206904 Jan 08 '23 at 20:52
  • TimeSpan can accept an array : $formats = @("m:s.fff", "h:m:s.fff") Then use [timespan]::ParseExact($mystring,$formats , $null) but doesn't work. You need to use DateTime instead : [DateTime]::ParseExact($mystring,$formats , $null).TimeOfDay I debugged in c#. Have seen case in the past like this where timespan doesn't work but DateTime does. You always can use timeofday to convert DateTime to TimeSpan. – jdweng Jan 08 '23 at 21:44

1 Answers1

2

If you ensure that your time-span strings have at least 3 :-separated components, you can cast them directly to [timespan] (which, behind the scenes, delegates to [timespan]::Parse($inputString, [cultureinfo]::InvariantCulture))[1]

@(
  "1:33.823" #1min:33 seconds.823 - shortest
  "11:33.823" #11min:33 seconds.823 - short
  "1:11:33.823" #1 hour 11min:33 seconds.823 - long
) | ForEach-Object {
  $colonCount = ($_ -replace '[^:]').Length
  [timespan] ('0:' * [math]::Max(0, (3 - $colonCount - 1)) + $_)
}

The above transforms the input strings to 0:1:33.823, 0:11:33.823, and 1:11:33.823 before casting, i.e. prepends 0: components as needed.


[1] PowerShell by design uses the invariant culture when possible - see this answer for more information.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    this is indeed quite elegant, the idea I had for padding was to match and divide to 4 case with 4x if statements, if the string is case 1 (seconds only): pad with 2x 0 zeroes, if case 2 (minutes only), pad with -X zeroes, etc – user206904 Jan 09 '23 at 00:18