Press "Enter" to skip to content

Changing date time zones using PowerShell

Joshua Stenhouse 0

Over the past 6 months I’ve been doing an extensive amount of work with global backup reporting using PowerShell. One unique challenge that comes with global reporting is handling time zones. If you’re given a time in UTC (in my case from a REST API), how do you convert it to the local time zone so it makes sense to the user? Or what if you have a date from a local time zone, but need to convert it to UTC?

Easy you might say, just use “.AddHours(x).AddMinutes(x)” on the date and you’re all set. But wait, some time zones change, others don’t, what might be -5 hours from UTC now isn’t -5 hours all year long.

How do you then manage conversion for 50 different time zones? What day does each change on? How do you even begin to accommodate for that in your script?  It gets tricky very quickly, but the good news is I created a simple function that makes it super easy by using the World Time API.

You can download my Get-TimeZoneOffsets function from here:

The function takes the time zone specified, queries the World Time API (so internet access is required) and gets the current UTC offset in hours and minutes. Using these 2 values we can then adjust the UTC date in PowerShell to the local time zone. Or, add in a -Reverse switch and you’ll get the opposite values to convert from the local time zone to UTC. This way you always have the right offset required to convert either from or to UTC from any time zone in the world. Sweet!

Once you’ve run the function, start by typing:

Get-TimeZoneOffsets -ListAvailable

This gives you a list of all the time zone names available for selection. Then run:


$TimeZone = "America/New York"
$TimeZoneOffsets = Get-TimeZoneOffsets -TimeZone $TimeZone
 

On $TimeZoneOffsets you will have 2 values, hours and minutes to add (can be minus), assign them to variables using:


$HoursToAdd = $TimeZoneOffsets[0]
$MinutesToAdd = $TimeZoneOffsets[1]
 

Now take your date in UTC, for the example we will just a locally generated time in UTC, then we are going to convert it to the time zone specified above and show the result:


$UTCNow = [System.DateTime]::UtcNow
$TimeZoneAdjusted = $UTCNow.AddHours($HoursToAdd).AddMinutes($MinutesToAdd)
$TimeZoneAdjusted
 

Voila! At this point you might be asking “why can’t I just pass the date to the function and have it converted?”. There’s a good reason I didn’t build the function this way, efficiency. For my use case I need to find the offset once, then update multiple dates to the local time zone. If I had to pass the date each time to the function it would be querying the World Time API multiple times asking it the same question. Because the API is external and metered (you need a license for thousands of queries in quick succession), I decided it was better to ask once and re-use until I need to ask again.

Let’s now run through the same process but this time I have the local date and I need to know what that would’ve been in UTC. For demo purposes I’m just going to use Get-Date, but in the real-world you are being given the date in the local time zone already:


$TimeZone = "America/New York"
$TimeZoneOffsets = Get-TimeZoneOffsets -TimeZone $TimeZone -Reverse
$HoursToAdd = $TimeZoneOffsets[0]
$MinutesToAdd = $TimeZoneOffsets[1]

$LocalTimeZone = Get-Date
$TimeZoneUTC = $LocalTimeZone.AddHours($HoursToAdd).AddMinutes($MinutesToAdd)
$TimeZoneUTC
 

If you want to go serious next level date conversion ninja, combine the above 2 workflows in reverse to convert any time zone date to UTC, then to any other time zone needed. How cool is that?!

If you don’t want to download the zip file, you can copy the entire function from here:


################################################
# Creating the Get-TimeZoneOffsets function
################################################
Function Get-TimeZoneOffsets {
Param ($TimeZone, [switch] $ListAvailable, [switch] $Reverse)

# To see a list of available time zones run:
# Get-TimeZoneOffsets -ListAvailable

# Example of how to use the function to convert from UTC to the local timezone:
# $UTCNow = [System.DateTime]::UtcNow
# $TimeZoneOffsets = Get-TimeZoneOffsets -TimeZone "America/New York"
# $HoursToAdd = $TimeZoneOffsets[0]
# $MinutesToAdd = $TimeZoneOffsets[1]
# $TimeZoneAdjusted = $UTCNow.AddHours($HoursToAdd).AddMinutes($MinutesToAdd)
# $TimeZoneAdjusted

# To calculate UTC from the local time zone (using example generated locally for demo purposes), add reverse:
# $LocalTimeZone = Get-Date
# $TimeZoneOffsets = Get-TimeZoneOffsets -TimeZone "America/New York" -Reverse
# $HoursToAdd = $TimeZoneOffsets[0]
# $MinutesToAdd = $TimeZoneOffsets[1]
# $TimeZoneUTC = $LocalTimeZone.AddHours($HoursToAdd).AddMinutes($MinutesToAdd)
# $TimeZoneUTC

####################
# If -ListAvailable used, returning a list of time zones available
####################
IF ($ListAvailable)
{
# Creating URL
$WorldTimeZonesURL = "http://worldtimeapi.org/api/timezone/"
# GET to world time API
Try
{
$WorldTimeZones = Invoke-RestMethod -Uri $WorldTimeZonesURL -Method GET
$Status = "Success"
}
Catch
{
$Status = "Failed"
$ErrorMessage = $_.ErrorDetails; "ERROR: $ErrorMessage"
}
# Returning timezones
Return $WorldTimeZones
}
####################
# If -ListAvailable not used, returning timezone offsets
####################
IF ($TimeZone -ne $null)
{
# Replacing space with underscore in timezone name
$TimeZone = $TimeZone.Replace(" ","_").TrimEnd()
# Creating URL
$WorldTimeURL = "http://worldtimeapi.org/api/timezone/" + $TimeZone
# GET to world time API
Try
{
$WorldTime = Invoke-RestMethod -Uri $WorldTimeURL -Method GET
$Status = "Success"
}
Catch
{
$Status = "Failed"
$ErrorMessage = $_.ErrorDetails
Write-Error -Message $ErrorMessage -ErrorAction Stop
}
# Selecting UTC offset
$UTCOffset = $WorldTime.utc_offset
# Setting hours and minutes of offset from UTC
IF ($Status -eq "Success")
{
$HoursToAdd = $UTCOffset.SubString(0,3)
$MinutesToAdd = $UTCOffset.SubString(3).Replace(":","").TrimEnd()
}
####################
# If -Reverse used, returning timezone offset required to calculate UTC from the time zone specified
####################
IF ($Reverse) 
{
# Converting hours and minutes, if negative changed to positive and vice versa
$HoursToAdd = -$HoursToAdd
$MinutesToAdd = -$MinutesToAdd
}
####################
# Setting both to 0 if $Status Failed for API call to World Time API
####################
IF ($Status -eq "Failed")
{
$HoursToAdd = 0
$MinutesToAdd = 0
}
####################
# Returning offsets
####################
Return $HoursToAdd,$MinutesToAdd
}
}
####################
# End of script
####################
 

If you found this useful please like/comment/share. Can you think of any other time zone conversion related tasks you need to perform in PowerShell? If so, hit me up via the Drift chatbot. Happy scripting,

@JoshuaStenhouse

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Discover more from Virtually Sober

Subscribe now to keep reading and get access to the full archive.

Continue reading