Private/ConvertFrom-GitHubTimestamp.ps1
|
# --------------------------------------------------------------------------- # ConvertFrom-GitHubTimestamp # Normalises a timestamp field from a GitHub API response into a UTC # [DateTime]. Returns $null for an absent, empty, or unparseable value. # # Normalising to UTC here (rather than leaving the raw value alone) is what # lets callers compute an elapsed duration with a plain [DateTime]::UtcNow # subtraction. # # The input is deliberately untyped, because the field does NOT arrive as a # string. ConvertFrom-Json - which Invoke-RestMethod uses internally - # recognises ISO-8601 values and hands back a [DateTime] already: Kind=Utc # for a 'Z' instant, Kind=Local for one with a numeric offset. Declaring the # parameter [string] would coerce that object back through ToString() in the # local culture, dropping the offset, and the reparse would then shift the # instant by the host's UTC offset. Accepting the object and converting by # Kind is the only way to stay correct on a host that is not on UTC. # # A malformed value yields $null rather than throwing: it is one field of # one row on a status report, and losing the elapsed time for that row is a # far better outcome than failing the whole poll. # # Private to the module - not exported. # --------------------------------------------------------------------------- function ConvertFrom-GitHubTimestamp { [CmdletBinding()] [OutputType([DateTime])] param( # A [DateTime] (the normal case, courtesy of ConvertFrom-Json), a # [DateTimeOffset], or an ISO-8601 string. $null yields $null. [Parameter(Position = 0)] [AllowNull()] $Timestamp ) if ($null -eq $Timestamp) { return $null } if ($Timestamp -is [DateTime]) { # Unspecified means the source carried no offset at all. GitHub always # sends one, so treat it as the UTC instant it claims to be rather # than silently re-interpreting it in the host's timezone. if ($Timestamp.Kind -eq [DateTimeKind]::Unspecified) { return [DateTime]::SpecifyKind($Timestamp, [DateTimeKind]::Utc) } return $Timestamp.ToUniversalTime() } if ($Timestamp -is [DateTimeOffset]) { return $Timestamp.UtcDateTime } $text = [string] $Timestamp if ([string]::IsNullOrWhiteSpace($text)) { return $null } try { return ([DateTimeOffset]::Parse( $text, [System.Globalization.CultureInfo]::InvariantCulture)).UtcDateTime } catch [System.FormatException] { return $null } } |