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
?
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
?
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.