private/Convert-TimeSpan.ps1

Function Convert-TimeSpan {
<#
    .SYNOPSIS
        Convert an integer, string or timespan into a limited ISO8601 format
 
    .DESCRIPTION
        Convert an integer, string or timespan into a limited ISO8601 format string. The limitation is returning only up to Days: 'PxDTxHxMxS'
 
    .PARAMETER Duration
        Integer, timespan object to convert. Integer values are assumed to be seconds.
 
    .PARAMETER Format
        Option to choose DateTime or Time format for the resulting output. In DateTime format, seconds are ignored. In Time format the smallest possible unit of time is returned (Hours, Minutes, Seconds). Default value is DateTime
 
    .PARAMETER MinimumDuration
        Minimum duration validation check, default of none. Can either be a Timespan object or an integer number of seconds
 
    .PARAMETER MaximumDuration
        Maximum duration validation check, default of 365 days. Can either be a Timespan object or an integer number of seconds
 
    .EXAMPLE
        Convert-TimeSpan -Duration 3600
        Returns 'PT1H'
 
    .EXAMPLE
        Convert-TimeSpan -Duration 'PT7200.0s'
        Returns 'PT2H'
 
    .EXAMPLE
        Convert-TimeSpan -Duration ([timespan]::New(3, 10, 30, 0, 0)) -Format DateTime
        Returns 'P3DT10H30M'
 
    .EXAMPLE
        Convert-TimeSpan -Duration (New-TimeSpan -Days 2 -Hours 10 -Minutes 30) -Format Time
        Returns 'PT58.5H'
 
    .EXAMPLE
        Convert-TimeSpan -Duration (New-TimeSpan -Start '2020-01-01 13:00' -End '2020-01-02 14:30') -Format Time
        Returns 'PT25.5H'
 
    .NOTES
        For additional information please see my GitHub wiki page
 
    .FUNCTIONALITY
        None
 
    .LINK
        https://github.com/My-Random-Thoughts/Rapid7Nexpose
#>


    Param (
        [Parameter(Mandatory = $true)]
        [object]$Duration,

        [ValidateSet('DateTime','Time')]
        [string]$Format = 'DateTime',

        [object]$MinimumDuration = (New-TimeSpan),

        [object]$MaximumDuration = (New-TimeSpan -Days 365).Subtract(1)
    )

    Switch ($Duration.GetType().Name) {
        {'int32', 'double'} {
            $Duration = (New-TimeSpan -Seconds $Duration)
            $Format   = 'Time'
        }

        'string' {
            [void]($Duration -match "^P?(?:(\d+)D)?T(?:(\d+)H)?(?:(\d+)M)?(?:([0-9]+?(?:\.?(?<=\.)(?:[0-9]+))?)S)??$")
            If ($Matches) {
                $Duration = ([timespan]::New($Matches[1], $Matches[2], $Matches[3], 0, (($Matches[4] -as [double]) * 1000)))
            }
            Else {
                Throw "Duration is not in the correct ISO8601 format: $Duration"
            }
        }

        'timespan' {
            # Do nothing
        }

        Default {
            Throw "Duration is not in the correct format: $($Duration.GetType().Name)"
        }
    }

    If ($MinimumDuration -is [int]) { $MinimumDuration = (New-TimeSpan -Seconds $MinimumDuration) }
    If ($MaximumDuration -is [int]) { $MaximumDuration = (New-TimeSpan -Seconds $MaximumDuration) }

    If (($Duration.TotalMilliseconds -gt $MaximumDuration.TotalMilliseconds) -or ($Duration.TotalMilliseconds -lt $MinimumDuration.TotalMilliseconds)) {
        Throw "Duration given $Duration was outside the permitted range: $MinimumDuration - $MaximumDuration"
    }

    If ($Format -eq 'DateTime') {
        Return ('P{0}DT{1}H{2}M' -f $Duration.Days, $Duration.Hours, $Duration.Minutes)
    }
    ElseIf ($Format -eq 'Time') {
        If ($Duration.TotalMinutes -ge 60) {
            Return ('PT{0}H' -f ($Duration.TotalHours).ToString('0.####'))
        }
        ElseIf ($Duration.TotalSeconds -ge 60) {
            Return ('PT{0}M' -f ($Duration.TotalMinutes).ToString('0.####'))
        }
        Else {
            Return ('PT{0}S' -f ($Duration.TotalSeconds).ToString('0.####'))
        }
    }
    Else {
        Return $null
    }
}