October 23rd, 2012

Check for Daylight Savings Time by Using PowerShell

Doctor Scripto
Scripter

Summary: Brian Wilhite, guest blogger, discusses a function to check for transition to daylight savings time.

Microsoft Scripting Guy, Ed Wilson, is here. Today, we have a guest blogger. Brian Wilhite has been a guest in the past, and you can see his previous posts here. Brian is speaking at the Atlanta Windows PowerShell Saturday event (Alpharetta) on October 27, 2012. He is reprising his talk from the Charlotte Windows PowerShell Saturday event (it was standing-room only and was very well received). Tickets are still available for the event. For information about Windows PowerShell Saturday in Atlanta (Alpharetta), check out the PowerShell Saturday site.

Take it away, Brian …

It’s that time of year where most of us, in the United States, “gain” an hour of sleep by setting our clocks back one hour. I’ve been getting emails and comments about a Windows PowerShell function I created called Get-DSTInfo, which queries the Win32_TimeZone WMI Class to determine when the system “thinks” it needs to perform those automated changes. It’s that time of year where the IT community is looking for ways to ensure their systems are going to behave as expected. I’m always excited to see people in the world use some of the tools I create. For more information, see my previous Hey, Scripting Guy! Blog entry introducing this function.

Following is an image of what the output looks like when Get-DSTInfo runs locally.

Image of command output

Recently, I received some feedback from Justin Moore that my function didn’t display the DaylightChgDate and StandardChgDate Date/Time correctly for the Central Europe Time Zone. To learn more, we will need to dig into the Win32_TimeZone WMI Class. This class has the following information, which my function uses to calculate the actual date.

The command is shown here.

Get-CimInstance Win32_TimeZone | select *

The command and the output from the command are shown in the following image.

Image of command output

You’ll notice that the actual dates of the time changes are not present. However, what we do have is the StandardDay property, which means the First, Second, Third, Fourth, or Last day that the time changes. 

Here, in the United States, we will set our clocks back one hour on the first Sunday in November. In this case, the StandardDay property equals 1, meaning the First in “First Sunday of November.” The switch statement, shown below, highlights this concept.

Switch ($TimeZone.StandardDay)

 {

  1 {$STNDDay = “First”}

  2 {$STNDDay = “Second”}

  3 {$STNDDay = “Third”}

  4 {$STNDDay = “Fourth”}

  5 {$STNDDay = “Last”}

 }#End Switch ($TimeZone.StandardDay) 

Next, let’s take a look at the StandardDayOfWeek property, which means the day of the week the time change will occur. In the image above, it equals 0, which means Sunday in “First Sunday of November.” The switch statement follows.

Switch ($TimeZone.StandardDayOfWeek)

 {

  0 {$STNDWeek = “Sunday”}

  1 {$STNDWeek = “Monday”}

  2 {$STNDWeek = “Tuesday”}

  3 {$STNDWeek = “Wednesday”}

  4 {$STNDWeek = “Thursday”}

  5 {$STNDWeek = “Friday”}

  6 {$STNDWeek = “Saturday”}

 }#End Switch ($TimeZone.StandardDayOfWeek)

Finally, let’s review the StandardMonth property, which means the month the time change will occur, which, in this example, is 11 for November in “First Sunday of November.”

Switch ($TimeZone.StandardMonth)

 {

  1  {$STNDMonth = “January”}

  2  {$STNDMonth = “February”}

  3  {$STNDMonth = “March”}

  4  {$STNDMonth = “April”}

  5  {$STNDMonth = “May”}

  6  {$STNDMonth = “June”}

  7  {$STNDMonth = “July”}

  8  {$STNDMonth = “August”}

  9  {$STNDMonth = “September”}

  10 {$STNDMonth = “October”}

  11 {$STNDMonth = “November”}

  12 {$STNDMonth = “December”}

 }#End Switch ($TimeZone.StandardMonth)

The fun part of Windows PowerShell scripting is figuring out, with the above information, how to calculate the date, so let’s break the code down.

Below, I’m grabbing the current year to work from.

$CurrentYear = (Get-Date).Year

Next, using the information from the switch statements, I’m going to cast the data into a DateTime object.  For example, $SDate would equal Thursday, November 1, 2012 2:00:00 AM:

[DateTime]$SDate = “$STNDMonth 01, $CurrentYear $STNDHour`:00:00”

We are now going to use a While loop to determine and calculate the actual change date. I’m going to set $i to 0 and run the While loop as long as $i is less than $TimeZone.StandardDay. The first If Statement checks to see if the $SDate.DayOfWeek equals the $TimeZone.StandardDayOfWeek. If not, we will add a day to the $SDate variable and continue to do so until $SDate.DayOfWeek equals StandardDayOfWeek

If you’ve successfully followed along, we started out with November 1, 2012 as the $SDate and continued to add days until reaching November 4, 2012 since the first If Statement is now true, If ($SDate.DayOfWeek -eq $TimeZone.StandardDayOfWeek). The reason for this is because November 4, 2012 is on a Sunday and the $TimeZone.StandardDayOfWeek also equals Sunday 0

At the moment, we’ve incremented $i by 1 and $SDate equals November 4, 2012, and we will use the second If Statement If ($i -eq $TimeZone.StandardDay) to test if $i equals $TimeZone.StandardDay. In this case, it does, so we’ll assign $SFinalDate = $SDate (November 4, 2012).

$i = 0

While ($i -lt $TimeZone.StandardDay)

    {

        If ($SDate.DayOfWeek -eq $TimeZone.StandardDayOfWeek)

            {

                $i++

                If ($i -eq $TimeZone.StandardDay)

                    {

                        $SFinalDate = $SDate

                    }#End If ($i -eq $TimeZone.StandardDay)

                Else

                    {

                        $SDate = $SDate.AddDays(1)

                    }#End Else

            }#End If ($SDate.DayOfWeek -eq $TimeZone.StandardDayOfWeek)

        Else

            {

                $SDate = $SDate.AddDays(1)

            }#End Else

}#End While ($i -lt $TimeZone.StandardDay)

Back to the reason why this doesn’t work with the Central Europe Time Zone … as you can see in the following image, the StandardDay equals Last or 5. This will be an issue if there are only four Sundays in October, because according to the MSDN Win32_TimeZone reference, last equals 5. In this case, the loop logic will run through five times and will match the fifth Sunday of October to November 4, 2012, which, obviously, is incorrect because there are only four Sundays in October this year.

Image of command output

I thought for a minute and came up with this solution.

If ($SFinalDate.Month -ne $TimeZone.StandardMonth)

    {

        $SFinalDate = $SFinalDate.AddDays(-7)

    }#End If ($SFinalDate.Month -ne $TimeZone.StandardMonth)

The above code is placed just after the loop, and it will evaluate whether the loop landing date “month” matches the month the Win32_TimeZone information returns. If they do not match, it will set the $SFinalDate back seven days so that the date will be correct. Therefore, handling either condition for 4 or 5 for StandardDay will calculate the date correctly.

I have updated the function, and it is currently available in the Script Repository on TechNet.

I hope you’ve enjoyed exploring Windows PowerShell with me today. Until next time …

Thank you, Brian, for sharing this update with us. Awesome job.

Join me tomorrow when we will have another guest blogger.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Author

The "Scripting Guys" is a historical title passed from scripter to scripter. The current revision has morphed into our good friend Doctor Scripto who has been with us since the very beginning.

0 comments

Discussion are closed.