Script determines when those fateful Sundays occur
I'm always caught off guard when that fateful Sunday rolls around when time either springs ahead or falls back an hour. The hour backward in fall isn't so bad. Although it still sneaks up on me, I don't mind having an extra hour to sleep or just relax. But that Sunday in early spring when I have to get up an hour earlier is a killer.
To make these new dates less of a rude awakening, I wrote a script named GetDLSDates.vbs. By simply double-clicking the script, I get a reminder of when daylight saving time begins and ends in the current year. Without having to change any code, this script will work the same year after year, even given the upcoming changes in daylight saving time. (For information about these changes, see the sidebar "Daylight Saving Time Is Changing in 2007.")
GetDLSDates.vbs uses Windows Management Instrumentation's (WMI's) Win32_TimeZone class to access information about the time zone and daylight saving time properties in a Windows OS. Thus, to understand how the script works, you need to know what several Win32_TimeZone class properties represent.
The Win32_TimeZone Class Properties
GetDLSDates.vbs relies on the following Win32_TimeZone class properties:
- Bias. The Bias property represents the difference in minutes between Greenwich Mean Time (GMT—also known as Coordinated Universal Time, or UTC) and local time. For example, Eastern time (US and Canada) has a Bias property value of -300. You can also find the bias represented in hours instead of minutes. For example, Windows' Date and Time Properties dialog box shows the bias between Eastern time and GMT as -05:00, which means GMT minus 5 hours.
- DaylightBias. The DaylightBias property is the offset value used when the Windows clock is set to automatically adjust for daylight saving time. In the Win32_Time-Zone class documentation, Microsoft states that the DaylightBias property value is added to the Bias property value to form the bias used during daylight saving time. The term "added" can be confusing. In most time zones, the DaylightBias property has a value of -60 minutes. If you add the DaylightBias property value to the Bias property value, you'll get a wrong value, such as
-300 + -60 = -360However, if you subtract the DaylightBias property value from the Bias property value, you get the correct value
-300 - -60 = -240because the double negative translates into a positive number:
-300 +60 = -240In this sense, you could say that you're adding the DaylightBias value to the Bias value.
- StandardBias. The StandardBias property is used to determine the bias when daylight saving time isn't in effect. It typically has the value of 0.
- DaylightMonth and Standard-Month. The DaylightMonth property represents the month in which daylight saving time starts, whereas the StandardMonth property represents the month in which daylight saving time ends. The possible values for both properties range from 1 to 12 and represent the corresponding months of the year. For example, when daylight saving time begins in April, the Daylight-Month property has a value of 4. When daylight saving time ends in October, the StandardMonth property has a value of 10.
- DaylightDayOfWeek and Standard-DayOfWeek. The DaylightDay-OfWeek property represents the day of the week when daylight saving time starts. Its counterpart, StandardDayOfWeek, represents the day of the week when daylight saving time ends. The possible value ranges for both properties are 0 through 6, with 0 representing Sunday and 6 representing Saturday. Typically, both values are set to 0 (Sunday).
- DaylightDay and StandardDay. The DaylightDay property represents the first (value of 1), second (2), third (3), fourth (4), or fifth (5) occurrence of the day specified by DaylightDayOfWeek. The Standard-Day property has the same usage and values as DaylightDay, except it indicates the first, second, third, fourth, or fifth occurrence of StandardDayOfWeek. So, for example, when daylight saving time begins on the first Sunday of April, the DaylightDay property would have a value of 1. When daylight saving time ends the last Sunday of October, the StandardDay property would have a value of 4 or 5, depending on when October 1 falls. For example, this year October 1 fell on a Sunday, so the last Sunday of the month is the fifth occurrence (i.e., StandardDay = 5).
- DaylightHour and StandardHour. The DaylightHour and Standard-Hour properties specify the hour of the day that daylight saving time begins and ends, respectively. In most cases, these property values are set to the value 2, which represents 2 A.M.
- DaylightMinute and Standard-Minute. The DaylightMinute and StandardMinute properties specify the minute of the day that daylight saving time begins and ends, respectively. In most cases, these property values are set to the value of 0.
- DaylightName and StandardName. The DaylightName property contains a string value that specifies the time-zone name when daylight saving time is in effect (e.g., Eastern Daylight Time). The StandardName property's string value specifies the time-zone name when daylight saving time isn't in effect (e.g., Eastern Standard Time).
Now that you know about the importantWin32_TimeZone class properties, let's take a look at how GetDLSDates-.vbs uses them.
Works Listing 1 shows GetDLSDates.vbs This script starts by creating an array named arDOW to hold the values of the seven days of the week. The array is modeled after how the StandardDayOfWeek and DaylightDayOfWeek properties values are defined. For example, array element 0 contains the value of "Sunday" and array element 6 contains the value of "Saturday." I'll describe how this array comes into play shortly.
Next, GetDLSDates.vbs gathers a collection of the local machine's time zone property values by querying the Win32_TimeZone class. When the DaylightBias property value is 0, the script immediately exits with a descriptive message. A value of 0 indicates that the Windows clock isn't set to automatically adjust for daylight saving time, possibly because a time zone (e.g., the Seoul time zone) or location (e.g., Hawaii) doesn't observe daylight saving time. When the DaylightBias property value isn't 0, the script uses a user-defined function named DLS and VBScript's TimeSerial function to display the starting and ending dates and time of daylight saving time. GetDLSDates.vbs displays the results in two dialog boxes, which show when daylight saving time begins and ends.
The DLS function determines the starting and ending dates (but not the time) of daylight saving time for the current year. As callout A in Listing 1 shows, this function takes three parameters: Mnth, occurrence, and dow. When the script is determining the starting date of daylight saving time, it uses the DaylightMonth, DaylightDay, and DaylightDayOfWeek properties to obtain the values for these parameters. When the script is determining the ending date, it uses the StandardMonth, StandardDay, and StandardDayOfWeek properties.
To determine the starting and ending times of daylight saving time, the script uses the DaylightHour, DaylightMinute, and DaylightSecond properties to obtain the starting time and the StandardHour, Standard-Minute, and StandardSecond properties to obtain the ending time. The TimeSerial function transforms these properties' values into a format that's easy to read.
The DLS function is the heart of GetDLSDates.vbs, so let's take a closer look at it. When this function receives the values for the Mnth, occurrence, and dow parameters, it first checks to make sure that the occurrence variable's value isn't greater than 5, as the code at callout B shows. This will never be the case if you're evaluating WMI's DaylightDay or StandardDay property. However, I included this code in case you want to use the function to get the date of a particular occurrence of a weekday in a given month (e.g., get the date of the last Saturday in December). The GetDLSDates.vbs script that you can download from the Windows Scripting Solutions Web site (see page 1 for download information) includes code for this purpose.
Next, the DLS function obtains the current year with VBScript's Now function and assigns that value to a variable named yr. The function then uses VBScript's MonthName function to turn the numerical value in the Mnth parameter to a string (e.g., turns the value of 3 into the string March) and assigns that string to the MName variable.
As I mentioned previously, Get-DLSDates.vbs works year after year, without having to change any code. To achieve this capability, the script uses a For...Next statement. For example, suppose you run this script next year. The For...Next loop first determines the first Sunday of the month that's specified in the MName variable. To make this determination, the code at callout C creates a string that includes the value in MName (in this case, March), one of the counter (i) variable's possible values (e.g., 1), and the value in yr (in this case, 2007). Using VBScript's CDate function, the loop transforms the resulting string (e.g., March 1, 2007) to a Date data type (e.g., 3/1/2007). Using VBScript's Weekday function, the code gets the value representing the weekday for that date (in this case, 4, which represents Thursday), then uses VBScript's WeekdayName function to transform that value into a string (i.e., Thursday).
At this point, the arDOW array comes into play. Recall that the dow parameter holds either the DaylightDayOfWeek or StandardDayOfWeek property value, which can range from 0 to 6. The loop uses this value within the arDOW array to get the associated string (e.g., arDOW(0) = "Sunday"). The loop then compares the WeekdayName function's string to arDOW's string. When the strings match, you have the date of first Sunday of the specified month (in this case, March 4). The If...Then loop uses this date with specified occurrence (i.e., the value in the occurrence variable) to find when saving daylight time starts or ends. As the code at callout D shows, the following equation is used
i + (7 * (occurrence-1))
The subtraction of 1 from the occurrence variable's value is necessary because you already have the first occurrence stored in the i variable.
For example, let's say that the DaylightMonth value is March, the DaylightDayOfWeek value is Sunday, and the DaylightDay value is 2 (i.e., the occurrence is the second Sunday of the month). After the code at callout C determines that the first Sunday of the month is March 4 (i.e., i = 4), the code at callout D calculates the second occurrence of Sunday with the equation
4 + (7 * (2-1))
So, in this case, saving daylight time starts on March 11.
Let's look at another example. Suppose that in the future, the US government implements a new Energy Policy Act, which changes the end of the daylight saving time to the fifth Sunday of August. In this scenario, the StandardMonth value is August, the StandardDayOfWeek value is Sunday, and the StandardDay value is 5. After the code at callout C finds the first Sunday of the month (e.g., i = 6), the code at callout D calculates the second occurrence of Sunday with the equation
6 + (7 * (5-1))
which produces a value of 34—as you know, there's no August 34. The script compensates for situations like this by checking the calculated day against the total number of days in any given month, as callout E shows. If the calculated day is greater than the number of days in the month, the code subtracts 7 from the calculated value, which gives the correct date. In this scenario, the code subtracts 7 from 34, which means that daylight saving time ends on August 27.
The DLS function ends by creating a string that consists of the month, the calculated day, and the year. The function then uses the CDate function to convert the string to a date data type, which GetDLSDates.vbs displays in a message box.
Note that although you can use GetDLSDates.vbs year after year to display daylight saving time information, you can't use this script to find this information for past or future years. This limitation lies in the Win32 _TimeZone class properties: They're specific to the current year only.
Don't Be Caught Off Guard
With GetDLSDates.vbs, you'll never get caught off guard when time springs ahead or falls back an hour. And with a little tweaking, you can use the script's DLS function to return other useful dates. For example, as I'll show you in a future article, you can use it to return the date when Microsoft releases its patches by passing the second Tuesday of a month to the function. You might also use the Bias and DaylightBias properties to offset date values that are in the GMT format in order to get more accurate date and time return values. For more information about the Win32_Time-Zone class properties, see Win32 _TimeZone Web page at http://msdn.microsoft.com/library/default.asp?url =/library/en-us/ wmisdk/wmi/ win32_timezone.asp.
Statement of Ownership
Statement of Ownership Management and Circulation for WINDOWS SCRIPTING SOLUTIONS as required by 39 U.S.C. 3685; WINDOWS SCRIPTING SOLUTIONS, publication no. 1537-4483, filed October 1, 2006, to publish twelve monthly issues each year for an annual subscription price of $129.00. The mailing address of the office of publication, the headquarters of general business of Kim Paulsen, Publisher; Karen Forster, Editorial and Strategy Director; is 221 E. 29th St., Loveland, CO 80538. The owner is Penton Media, Inc., 1300 E. 9th St., Cleveland, OH 44114-2543. There are no known bondholders, mortgages, or other security holders owning or holding one percent or more of the total amount of bonds, mortgages, or other securities. The average number of copies of each issue published during the twelve months preceding the filing date include: total number of copies (2,385); mail subscription (936); sales through dealers and carriers, street vendors, and counter sales (476); other classes mailed through the USPS (105); total paid and/or requested circulation (1,517); free distribution by mail carrier or other means and samples, complimentary, and other free copies (421); total distribution (1,938); copies not distributed (447) for a total of (2,385) copies. The actual number of copies of single issues published nearest to the filing date include: total number of copies (2,102); mail subscription (1,009); sales through dealers and carriers, street vendors, and counter sales (485); other classes mailed through the USPS (79); total paid and/or requested circulation (1,573); free distribution by mail carrier or other means and samples, complimentary and other free copies (36); total distribution (1,609); copies not distributed (493) for a total of (2,102) copies.
I certify that the statements made by me above are correct and complete: