As some of you know, I host a monthly online Twitter chat on the first Friday of every month using the #PSTweetChat tag (although the January 2021 chat will be on 8 January.) We get together and chat about all things PowerShell at 1:00PM Eastern Time. The challenge for the rest of the world is making sure they know what time that is for them. I've been on the other end of this as well. I need to attend an event that is 10:00AM Central Europe Standard Time. When is that for me? I spend my day in PowerShell, so there should be an easy way to answer that question.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
DateTime Shenanigans
And of course there is. The [DateTime] class has a method called ToLocalTime() which will convert a UTC time to your local time. In order to convert my 10:00AM CET event to my local time, I need to convert that time. to UTC and then to local time.
The first part, and yes this could be done a couple of ways, is to create a date time object for 10:00AM CET. I can't just run Get-Date because any result will be relative to my time zone. Well, actually I can.
$datetime = Get-Date "12/30/2020 10:00AM"
What I need to do is adjust this value to match the CET time zone. For that, I need to know the time zone. No problem.
$tzone = Get-TimeZone -Id "Central European Standard Time"
I'll assume you will look at help and examples for this command. This result includes a property that reflects a timespan for the UTC offset. In other words, how far off from UTC it is. For CET it is 1:00:00. I can use the AddHours() method to adjust the datetime value.
$remoteTime = $DateTime.AddHours( - ($tzone.BaseUtcOffset.totalhours))
This is the UTC value which I can now convert to my local time.
$remoteTime.ToLocalTime()
I am in Eastern time, so my UTC offset is -5 hours. CET is another hour beyond that for a total of 7 hours so 10:00AM CET is in fact 4:00AM for me. I think I may pass on this meeting.
ConvertTo-LocalTime
Now that I have the core mechanics worked out, I'll wrap it up in a PowerShell function.
Function ConvertTo-LocalTime {
<#
.Synopsis
Convert a remote time to local time
.Description
You can use this command to convert datetime from another timezone to your local time. You should be able to enter the remote time using your local time and date format.
.Parameter Time
Specify the date and time from the other time zone.
.Parameter TimeZone
Select the corresponding time zone.
.Example
PS C:\> ConvertTo-LocalTime "2/2/2021 2:00PM" -TimeZone 'Central Europe Standard Time'
Tuesday, February 2, 2021 8:00:00 AM
Convert a Central Europe time to local time, which in this example is Eastern Standard Time.
.Example
PS C:\> ConvertTo-LocalTime "7/2/2021 2:00PM" -TimeZone 'Central Europe Standard Time' -Verbose
VERBOSE: Converting Friday, July 2, 2021 2:00 PM [Central Europe Standard Time 01:00:00 UTC] to local time.
Friday, July 2, 2021 9:00:00 AM
The calculation should take day light savings time into account. Verbose output indicates the time zone and its UTC offset.
.Notes
Learn more about PowerShell: https://jdhitsolutions.com/blog/essential-powershell-resources/
.Inputs
None
.Link
Get-Date
.Link
Get-TimeZone
#>
[cmdletbinding()]
[alias("ctlt")]
[Outputtype([System.Datetime])]
Param(
[Parameter(Position = 0, Mandatory, HelpMessage = "Specify the date and time from the other time zone. ")]
[ValidateNotNullorEmpty()]
[alias("dt")]
[string]$Time,
[Parameter(Position = 1, Mandatory, HelpMessage = "Select the corresponding time zone.")]
[alias("tz")]
[string]$TimeZone
)
#parsing date from a string to accommodate cultural variations
$ParsedDateTime = Get-Date $time
$tzone = Get-TimeZone -Id $Timezone
$datetime = "{0:f}" -f $parsedDateTime
Write-Verbose "Converting $datetime [$($tzone.id) $($tzone.BaseUTCOffSet) UTC] to local time."
$ParsedDateTime.AddHours(-($tzone.BaseUtcOffset.totalhours)).ToLocalTime()
}
The function requires you to specify the datetime and its associated timezone. If the testing that I've been able to do, you should be able to specify the date using your local date time format. That's why the Time parameter is a string and I'm calling Get-Date. I need to be sure that the parsed value is valid for your culture. The rest of the code is simply a more compact version of what I just demonstrated.
Time Zone Completer
To make this even easier to use, I wanted to pre-populate possible time zone values. In other words, add auto-completion. In the same file as the function I have this bit of PowerShell code to setup the argument completer.
Register-ArgumentCompleter -CommandName ConvertTo-LocalTime -ParameterName TimeZone -ScriptBlock {
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
#PowerShell code to populate $wordtoComplete
(Get-TimeZone -ListAvailable | Sort-Object -Property ID).where({$_.id -match "$wordToComplete"}) |
ForEach-Object {
# completion text,listitem text,result type,Tooltip
[System.Management.Automation.CompletionResult]::new("'$($_.id)'", "'$($_.id)'", 'ParameterValue', $_.BaseUtcOffset)
}
}
The code in the scriptblock is executed and is what provides the completion values. You need to run a command that will generate results and each result is added as a CompletionResult object. I'm showing the parameter values for the New() method as a comment.
You also have the option to use the $WordToComplete parameter as a type of wildcard. In my code, the argument complete is getting time zone ids where the name matches whatever I type. This means I can start typing:
ConvertTo-LocalTime -Time "12/30/20 10:00AM" -TimeZone europe
And press Ctrl+Space to invoke PSReadline which shows me the possible values.
The 01:00:00 you see is the ToolTip value which is the BaseUTCOffset. This looks a little nicer in the PowerShell ISE.
By the way, if you type:
ConvertTo-LocalTime -Time "12/30/20 10:00AM" -TimeZone
And then press Ctrl+Space, PowerShell will prompt you to display all 140 possible values. I'll let you try that out for yourself.
Now I have a handy PowerShell tool which will tell me at a glance if I need to get early, or stay up late.
I hope you'll give this code a try and let me know what you think. I'm especially interested to hear how it works for those of use that have a non-North American culture. From my limited testing, I think you can enter a datetime using your local culture and everything should work as expected. But I would love confirmation.
Learn and Enjoy.