PowerShell Get-Date UTC: Work with Time Zones in Scripts

PowerShell Get-Date UTC: Work with Time Zones in Scripts

PowerShell Tips Editor 3 min read
PowerShell Get-Date UTC: Work with Time Zones in Scripts

Scheduled scripts that compare dates, log timestamps, or calculate durations silently misbehave when clocks shift for Daylight Saving Time. The root cause is always the same: mixing local time and UTC without explicit conversion. Storing and comparing all times in UTC is the permanent fix, and PowerShell Get-Date UTC timezone handling makes it straightforward with -AsUTC and the [TimeZoneInfo] class.

Quick Answer / TL;DR

Use (Get-Date).ToUniversalTime() (PS 5.1) or Get-Date -AsUTC (PS 7.1+) to get the current UTC time. Store all timestamps as UTC and convert to local time only for display.

Get UTC Time with Get-Date -AsUTC

PowerShell 7.1 added the -AsUTC switch to Get-Date, which returns the current time as a UTC DateTime with the Kind property set to Utc. On PowerShell 5.1, use the .ToUniversalTime() method instead.

# PowerShell 7.1+ (recommended)
$utcNow = Get-Date -AsUTC
Write-Host "UTC time: $($utcNow.ToString('yyyy-MM-dd HH:mm:ss')) UTC"

# PowerShell 5.1 and 7.x (universal compatibility)
$utcNow = (Get-Date).ToUniversalTime()
Write-Host "UTC time: $($utcNow.ToString('yyyy-MM-dd HH:mm:ss')) UTC"

# Check the Kind property — confirms UTC vs Local
$utcNow.Kind    # outputs: Utc
(Get-Date).Kind # outputs: Local
UTC time: 2024-03-15 08:32:15 UTC

Convert UTC to Local Time

When displaying stored UTC timestamps to users in the local time zone, convert UTC to local time explicitly. The .ToLocalTime() method uses the system’s current time zone, including any DST offset.

# Convert UTC to local time for display
$storedUtc = [datetime]::ParseExact('2024-03-15T08:32:15Z', 'yyyy-MM-ddTHH:mm:ssZ', $null)
$local     = $storedUtc.ToLocalTime()

Write-Host "Stored UTC:  $($storedUtc.ToString('yyyy-MM-dd HH:mm:ss')) UTC"
Write-Host "Local time:  $($local.ToString('yyyy-MM-dd HH:mm:ss zzz'))"

# Convert Azure AD/Graph API ISO8601 timestamp
$apiTimestamp = '2024-03-15T08:32:15Z'
$localTime    = ([datetime]$apiTimestamp).ToLocalTime()
Write-Host "Sign-in at: $($localTime.ToString('ddd yyyy-MM-dd HH:mm'))"

Convert Between Arbitrary Time Zones

Use [TimeZoneInfo]::ConvertTimeBySystemTimeZoneId() to convert between any two named time zones without going through local time. This is essential for scripts that serve users in multiple time zones or work with data from different regions.

# Convert UTC to Eastern Standard Time
$utcTime = Get-Date -AsUTC
$eastern = [TimeZoneInfo]::ConvertTimeBySystemTimeZoneId($utcTime, 'Eastern Standard Time')
Write-Host "Eastern time: $($eastern.ToString('HH:mm:ss'))"

# Convert from one zone to another (not through UTC)
$nyTime   = [datetime]::Now
$tokyoTZ  = [TimeZoneInfo]::FindSystemTimeZoneById('Tokyo Standard Time')
$easternTZ = [TimeZoneInfo]::FindSystemTimeZoneById('Eastern Standard Time')

$tokyoTime = [TimeZoneInfo]::ConvertTime($nyTime, $easternTZ, $tokyoTZ)
Write-Host "When it is $($nyTime.ToString('HH:mm')) in New York, it is $($tokyoTime.ToString('HH:mm')) in Tokyo"

TimeZoneInfo Class Methods

The [TimeZoneInfo] class provides everything you need for time zone work. List all available time zones, find one by ID, and use it for conversions and DST checks.

# List all available time zone IDs
[TimeZoneInfo]::GetSystemTimeZones() | Select-Object Id, DisplayName | Format-Table -AutoSize

# Get a specific time zone
$londonTZ = [TimeZoneInfo]::FindSystemTimeZoneById('GMT Standard Time')
$istanbulTZ = [TimeZoneInfo]::FindSystemTimeZoneById('Turkey Standard Time')

# Check if DST is in effect for a specific time zone right now
$berlinTZ = [TimeZoneInfo]::FindSystemTimeZoneById('W. Europe Standard Time')
$berlinTZ.IsDaylightSavingTime([datetime]::UtcNow)   # True during summer

Store and Compare Times Correctly

Always store timestamps as UTC in files, databases, and logs. When comparing two timestamps, ensure both have the same Kind (both UTC or both Local). Comparing a UTC DateTime directly to a Local DateTime gives incorrect results because .NET compares the numeric ticks without accounting for the time zone offset.

# Safe timestamp comparison — both UTC
$startUtc = Get-Date -AsUTC
# ... do work ...
$endUtc   = Get-Date -AsUTC
$elapsed  = $endUtc - $startUtc
Write-Host "Elapsed: $($elapsed.TotalSeconds) seconds"

# Log timestamps in UTC with Z suffix for unambiguous parsing
$logEntry = "$(Get-Date -AsUTC -Format 'yyyy-MM-ddTHH:mm:ssZ') Script started"
Add-Content C:\Logs\app.log $logEntry

# Never compare mixed kinds directly
$utcTime   = Get-Date -AsUTC
$localTime = Get-Date
# $utcTime -lt $localTime   ← unreliable! Convert first
$localAsUtc = $localTime.ToUniversalTime()
$utcTime -lt $localAsUtc  # correct comparison

DST-Safe Date Calculations

Adding or subtracting days across a DST boundary in local time can produce off-by-one-hour results. Perform all date arithmetic in UTC and convert back to local time for display only.

# DST-safe: calculate 30 days ago in UTC
$thirtyDaysAgo = (Get-Date -AsUTC).AddDays(-30)

# Filter AD last-logon dates correctly
$cutoff = (Get-Date -AsUTC).AddDays(-90)
Get-ADUser -Filter * -Properties LastLogonDate |
    Where-Object { $_.LastLogonDate -lt $cutoff.ToLocalTime() } |
    Select-Object Name, LastLogonDate |
    Sort-Object LastLogonDate

Common Errors and Fixes

  • -AsUTC only available in PowerShell 7.1+. Calling Get-Date -AsUTC on Windows PowerShell 5.1 throws “A parameter cannot be found that matches parameter name ‘AsUTC’.” Use (Get-Date).ToUniversalTime() as the backward-compatible alternative in scripts that must run on both PS5 and PS7.
  • Comparing Local and UTC DateTimes directly gives wrong results. .NET DateTime objects have a Kind property (Local, Utc, or Unspecified). Comparing objects with different Kind values compares raw ticks without converting, giving results that are off by the UTC offset. Always ensure both operands share the same Kind before comparing.

Related Cmdlets / See Also

Wrapping Up

The golden rule for timezone-safe PowerShell: store all timestamps as UTC, convert to local time only when displaying to users, and perform all date arithmetic in UTC. Use Get-Date -AsUTC on PS7 or (Get-Date).ToUniversalTime() on PS5 for UTC timestamps, and [TimeZoneInfo]::ConvertTimeBySystemTimeZoneId() for converting between named time zones.

Send-Item -To