ConvertFrom-ISO8601Duration


ISO 8601 describes durations as a component of time intervals and define the amount of intervening time in a time interval.

From Wikipedia (https://en.wikipedia.org/wiki/ISO_8601#Durations):

Durations are represented by the format P[n]Y[n]M[n]DT[n]H[n]M[n]S or P[n]W as shown to the right. 
In these representations, the [n] is replaced by the value for each of the date and time elements that follow the [n]. Leading zeros are not required, but the maximum number of digits for each element should be agreed to by the communicating parties. The capital letters P, Y, M, W, D, T, H, M, and S are designators for each of the date and time elements and are not replaced.
P is the duration designator (for period) placed at the start of the duration representation.
Y is the year designator that follows the value for the number of years.
M is the month designator that follows the value for the number of months.
W is the week designator that follows the value for the number of weeks.
D is the day designator that follows the value for the number of days.
T is the time designator that precedes the time components of the representation.
H is the hour designator that follows the value for the number of hours.
M is the minute designator that follows the value for the number of minutes.
S is the second designator that follows the value for the number of seconds.

For example, "P3Y6M4DT12H30M5S" represents a duration of "three years, six months, four days, twelve hours, thirty minutes, and five seconds".

Date and time elements including their designator may be omitted if their value is zero, and lower order elements may also be omitted for reduced precision. For example, "P23DT23H" and "P4Y" are both acceptable duration representations.

In my case, I needed to convert the ISO 8601 duration format to a Timespan object.

First, I needed to parse the duration string (e.g. “P3Y6M4DT12H30M5S”) and extract the different parts. So cooked up the following regular expression pattern:

$regex='^P?T?((?\d+)Y)?((?\d+)M)?((?\d+)W)?((?\d+)D)?(T((?\d+)H)?((?\d+)M)?((?\d*(.)?\d*)S)?)/font>

Then, I needed to use those extracted parts and build me the Timespan object. The only problem is that the Timespan's constructor accepts only Days, Hours, Minutes, Seconds and Milliseconds:

PS C:> [System.TimeSpan]::new

OverloadDefinitions 
-------------------
timespan new(long ticks)
timespan new(int hours, int minutes, int seconds) 
timespan new(int days, int hours, int minutes, int seconds) 
timespan new(int days, int hours, int minutes, int seconds, int milliseconds)

What about my Years, Months and Weeks??

So I ended up creating a DateTime object with the minimum value for the date and time, and simply adding each parsed part:

$dt = [datetime]::MinValue
if ($Matches.Seconds) { $dt=$dt.AddSeconds($Matches.Seconds) }
if ($Matches.Minutes) { $dt=$dt.AddMinutes($Matches.Minutes) }
if ($Matches.Hours)   { $dt=$dt.AddHours($Matches.Hours) }
if ($Matches.Days)    { $dt=$dt.AddDays($Matches.Days) }
if ($Matches.Weeks)   { $dt=$dt.AddDays(7*$Matches.Weeks) }
if ($Matches.Months)  { $dt=$dt.AddMonths($Matches.Months) }
if ($Matches.Years)   { $dt=$dt.AddYears($Matches.Years) }
$dt-[datetime]::MinValue

Using these methods, I now have the ConvertFrom-ISO8601Duration function that can be downloaded from the TechNet Script Center repository at: https://gallery.technet.microsoft.com/scriptcenter/ConvertFrom-ISO8601Duration-704763e0

HTH,

\Martin.

Comments (0)

Skip to main content