1

I'm using ffprobe to get the sexagesimal time and after trimming the last three (unnecessary) digits I get the following format:

#examples
 0:05:51.15 
11:03:15.24

Is there a way to add these 2 so that the result is 11:09:06.39 ?

mklement0
  • 382,024
  • 64
  • 607
  • 775
YTZ
  • 876
  • 11
  • 26

1 Answers1

3

You can cast the strings to type [timespan], which allows you to perform arithmetic on the resulting objects, and to apply custom formatting on output:

PS> ([timespan] ' 0:05:51.15' + [timespan] '11:03:15.24').ToString('h\:mm\:ss\.ff')
11:09:06.39

Note: If there's a chance that the resulting time span exceeds 24 hours, more work is needed.[1]

Note how \-escaping must be used to specify the output separators as literals.
In this case, the simpler .ToString('g') would have yielded the same output, but only in cultures that use . as the decimal separator, because the standard g format specifier is culture-sensitive. See the [timespan]::ToString() documentation as well as the documentation on standard and custom time-span format specifiers.

By contrast, PowerShell uses the invariant culture when interpreting the input format cast to [timespan], where . is the decimal separator; similarly, using a [timespan] instance in expandable strings yields a culture-invariant representation; e.g.:

  • [timespan] '11:03:15.24' always works, irrespective of the current culture, because the invariant culture expects . as the decimal separator.
  • "$([timespan] '1' - 1)" always yields 23:59:59.9999999, irrespective of the current culture[2].

As No Refunds No Returns notes, if you're dealing with differently formatted input, possibly from a different culture, you can use [timespan]::Parse() / [timespan]::ParseExact() / [timespan]::TryParseExact()


Parsing the standard formats of a given culture:

[timespan]::Parse(' 0:05:51,15', 'fr-FR') # OK

Note the , as the decimal separator.

If you omit the culture argument (or pass $null), the current culture is applied. Note how that differs from using a [timespan] cast, which is always culture-invariant (and assumes . as the decimal separator).


Parsing with a custom format:

[timespan]::ParseExact(' 0:05:51,15'.Trim(), 'h\:mm\:ss\,ff', $null) # OK

Note that using such a literal custom format is never culture-sensitive, because all the separators must be specified as - escaped - literals (e.g., \:), so $null is passed as the culture argument (IFormatProvider).
Conversely, passing a specific culture only makes sense with the culture-sensitive standard format specifiers, g and G.

Parsing with a culture-aware custom format:

If you don't know what culture will be in effect at runtime, but you want to respect that culture's decimal separator in combination with a custom format, you need to dynamically embed the current culture's decimal separator in your custom format string:

$tsText = ' 0:05:51.15'
[timespan]::ParseExact($tsText.Trim(), 
  ('h\:mm\:ss\{0}ff' -f [cultureinfo]::CurrentCulture.NumberFormat.NumberDecimalSeparator),
  $null
) # OK in cultures that use "." as the decimal separator

[1] h and hh only ever reflect the hours not included in full days in the input time span. To reflect the number of days too, prepend something like d\. - there is no format specifier that allows you express the total number of hours across multiple days, but you can use general-purpose string formatting to achieve that - do note, however, that you'll also need custom parsing code in order to convert the resulting string back to a [timespan] instance:
$ts = [timespan] ' 1:05:51.15' + [timespan] '23:03:15.24'
'{0}:{1:mm\:ss\.ff}' -f [Math]::Floor($ts.TotalHours), $ts

[2] At the .NET level, calling .ToString() on objects typically yields a culture-sensitive representation (if the type supports it), but with [timespan] the output happens to be culture-invariant. By contrast, PowerShell explicitly uses the invariant culture behind the scenes in casts and string interpolation, so that "$var" and $var.ToString() may not yield the same representation - see this answer for details.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • **edit** I added your footnote solution to my main script and noticed that an error occurs when trying to do somethings like `$ts = [timespan] ' 1:05:51.15' + [timespan] '24:03:15.24'` >> `Cannot convert value "24:03:15.24" to type "System.TimeSpan". Error: "The TimeSpan could not be parsed because at least one of the numeric components is out of range or contains too many digits."` Does this mean that _timespan_ won't be able to handle it if _hours>24_? – YTZ Nov 27 '18 at 01:02
  • 1
    @YTZ: Yes, as a _string_ representation you won't be able to cast that or parse it via a standard or custom format - you'd need custom parsing code. Adding the days component would fix that, however. Generally, try to convert from strings early, then perform all calculations based on `[timespan]` instances, then convert back to a string representation, if needed. – mklement0 Nov 27 '18 at 01:59