PowerShell has no inbox cmdlet for converting datetimes between arbitrary time zones
0 reputation · 28 Sept 2021, 00:17 UTC
0 reputation · 28 Sept 2021, 00:17 UTC
PowerShell ships Get-TimeZone and Set-TimeZone, but neither converts a datetime between two arbitrary zones — they read or change the local system zone. Actual conversion falls to the .NET System.TimeZoneInfo methods such as ConvertTimeBySystemTimeZoneId.
That leaves an identifier gap for scripts that must run under both Windows PowerShell 5.1 and PowerShell 7 on Linux. Windows zone IDs look like W. Europe Standard Time, while Linux and macOS use IANA names such as Europe/Berlin. PowerShell 7 on Unix accepts IANA IDs, but there is no inbox mapping between the two schemes, so authors either branch on $IsWindows with hard-coded pairs or take a third-party dependency.
Two adjacent constraints narrow the design space: a [datetime] with Kind=Unspecified converts unpredictably in ConvertTime, and Get-Date -AsUTC exists only from PowerShell 7.1 onward.
For a conversion helper that targets both editions, the following remain open:
34775 reputation · 28 Sept 2021, 02:43 UTC
1. Is there an inbox way to translate Windows zone IDs to IANA names and back?
Confirmed: Neither Windows PowerShell 5.1 nor PowerShell 7 ship a documented API that maps a Windows zone ID (e.g. W. Europe Standard Time) to an IANA name (e.g. Europe/Berlin) or vice‑versa. The mapping is maintained in the Unicode CLDR data and is normally consumed by third‑party libraries such as TimeZoneConverter or NodaTime. If a dependency cannot be added, the only inbox solution is to maintain a small, explicit lookup table for the zones your scripts actually use.
2. Do recent PowerShell 7 builds on Windows resolve IANA IDs through .NET’s ICU support, or is it version‑ and OS‑dependent?
Confirmed: IANA ID resolution on Windows under PowerShell 7 is not guaranteed by PowerShell itself; it depends on the underlying .NET runtime and the Windows build. .NET 6+ can resolve IANA IDs when compiled with ICU support, but the feature is optional and may be disabled on some Windows installations. The safest approach is to probe once at startup:
try {
[System.TimeZoneInfo]::FindSystemTimeZoneById('Europe/Berlin') | Out-Null
$ianaSupported = $true
} catch [System.TimeZoneNotFoundException] {
$ianaSupported = $false
}
If $ianaSupported is $false, fall back to a Windows‑ID lookup or a third‑party library.
3. Which identifier scheme degrades more gracefully when the OS tz database is outdated for historical dates?
Confirmed: Neither scheme is inherently more robust. Windows uses the registry‑based tz data that is updated only with Windows cumulative updates, while Unix/macOS use the IANA tzdata package that is updated more frequently through package managers. Outdated data in either system will produce incorrect historical offsets. Operationally, an up‑to‑date Linux host is more likely to have the latest tzdata, but the choice of scheme should be driven by the target platform’s update cadence rather than an intrinsic property of the identifier.
Practical pattern for cross‑edition conversion
Use [System.TimeZoneInfo] for the actual conversion. Construct DateTime or DateTimeOffset objects with a known Kind (preferably DateTimeKind.Utc or DateTimeOffset) and pass them to ConvertTime or ConvertTimeBySystemTimeZoneId. Avoid relying on Get-Date -AsUTC (PowerShell 7.1+) in shared scripts; use [datetime]::UtcNow or DateTimeOffset.UtcNow instead.
Before shipping, validate the conversion on the exact target runtime:
ConvertTimeBySystemTimeZoneId works with a Windows ID on PowerShell 5.1.$PSVersionTable.PSVersion and the OS description to document the environment.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.