|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Visual Basic Locale/Regionalization
Routines GetTimeZoneInformation: Obtain Dates for Daylight and Standard Time Changes |
||
Posted: | Sunday April 08, 2001 | |
Updated: | Monday December 26, 2011 | |
Applies to: | VB4-32, VB5, VB6 | |
Developed with: | VB6, Windows 2000, Windows XP Pro | |
OS restrictions: | None | |
Author: | VBnet - Randy Birch, Chip Pearson, Bob Butler, Mathias Schiffer, Mark Boettger | |
Related: |
GetTimeZoneInformation: Past, Current and Future Daylight/Standard Dates RegQueryValueEx: Identify Time Zones by Time Zone Bias GetTimeZoneInformation: Determine when Daylight Saving Time Occurs GetTimeZoneInformation: Current, Standard and Daylight Bias GetTimeZoneInformation: Locale Standard and Daylight Time Zone Names |
|
Prerequisites | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
None. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The
original function posted in April 2001, while returning the correct time,
had a flaw that can be attributed to my misreading of the MSDN regarding
time zones. Specifically, the .wDay member of the SYSTEMTIME
structure does not specify the date (day) of the time zone change but
rather indicates which weekend in the month that the change takes place.
Therefore, this page provides updated and correct code to return the change dates and times for the transition to/from Standard time and Daylight Saving time (DST). To those in countries who may not be familiar with DST, DST refers to the date that local clocks "spring forward" one hour in order to provide an additional hour of light in the evenings. GetTimeZoneInformation is a weird bird. It does not return the year in its returned SYSTEMTIME structure, so the API always assumes the year is the current year. Therefore, in order for the date adjustment routine to work (using VB's DateSerial and DateDiff methods), some year must be passed as an additional parameter to the method. And this leads to an interesting side effect ... you can call GetTimeZoneInformation once, then loop through a number of years to retrieve the DST/STD times for those years. You can see a demo of this at GetTimeZoneInformation: Past, Current and Future Daylight/Standard Dates. Note that the code uses the VB6-specific (if I remember correctly) FormatDateTime method. Users of earlier versions of VB should use the Format$ methods detailed in the comments at the bottom of the page. The time zone code was inspired by newsgroup postings by Bob Butler and Excel MVP Chip Pearson. The date adjustment routine was provided by VB MVP Mathias Schiffer, with a correction for dates occurring on the first or last days of the month provided by Mark Boettger. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
BAS Module Code | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
None. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Form Code | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Add a label (Label1) for the current date, a command button (Command1) and four text boxes (Text1 - Text4) to a form. Other labels are optional. Add the following code: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Option Explicit '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved. ' Some pages may also contain other copyrights by the author. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Distribution: You can freely use this code in your own ' applications, but you may not reproduce ' or publish this code on any web site, ' online service, or distribute as source ' on any media without express permission. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Private Const TIME_ZONE_ID_UNKNOWN As Long = 1 Private Const TIME_ZONE_ID_STANDARD As Long = 1 Private Const TIME_ZONE_ID_DAYLIGHT As Long = 2 Private Const TIME_ZONE_ID_INVALID As Long = &HFFFFFFFF Private Type SYSTEMTIME wYear As Integer wMonth As Integer wDayOfWeek As Integer wDay As Integer wHour As Integer wMinute As Integer wSecond As Integer wMilliseconds As Integer End Type Private Type TIME_ZONE_INFORMATION Bias As Long StandardName(0 To 63) As Byte 'unicode (0-based) StandardDate As SYSTEMTIME StandardBias As Long DaylightName(0 To 63) As Byte 'unicode (0-based) DaylightDate As SYSTEMTIME DaylightBias As Long End Type Private Enum DateFormats vbGeneralDate = 0 vbLongDate = 1 vbShortDate = 2 vbLongTime = 3 vbShortTime = 4 End Enum Private Declare Function GetTimeZoneInformation Lib "kernel32" _ (lpTimeZoneInformation As TIME_ZONE_INFORMATION) As Long Private Sub Form_Load() Command1.Caption = "Get Time Zone Change Info" End Sub Private Sub Command1_Click() Dim tzi As TIME_ZONE_INFORMATION Dim tziYear As Long 'today's date Label1.Caption = Format$(Now, "long date") 'retrieve time zone info for the system Call GetTimeZoneInformation(tzi) 'The .wYear parameter in the StandardTime 'and DaylightTime members return as 0, 'and we have to pass a valid year as well, 'so use Year() to get the current year. tziYear = Year(Now) 'call a method that uses the time zone info 'returned to calculate the actual dates that 'daylight/standard time changes. Text1.Text = GetTimezoneChangeDate(tzi.DaylightDate, tziYear, vbLongDate) Text2.Text = GetTimezoneChangeTime(tzi.DaylightDate, vbLongTime) 'pass the same structure to retrieve 'the times as well Text3.Text = GetTimezoneChangeDate(tzi.StandardDate, tziYear, vbLongDate) Text4.Text = GetTimezoneChangeTime(tzi.StandardDate, vbLongTime) End Sub Private Function GetTimezoneChangeDate(tziDate As SYSTEMTIME, _ ByVal tziYear As Long, _ ByVal dwType As DateFormats) As String 'thanks to Mathias Schiffer for this routine Dim tmp As Date Dim MonthFirstWeekday As Long With tziDate Select Case .wDay 'week in month Case 1 To 4: 'week 1 to week 4 'Calculate the first day in the month, 'and then calculate the appropriate day 'that the time zone change will occur at MonthFirstWeekday = Weekday(DateSerial(tziYear, .wMonth, 1)) - 1 tmp = DateSerial(tziYear, _ .wMonth, _ (.wDayOfWeek - MonthFirstWeekday + .wDay * 7) Mod 7 + 1) Case 5: 'last week in month 'Calculate the month's last day, 'then work back to the appropriate 'weekday tmp = DateSerial(tziYear, .wMonth + 1, 0) tmp = DateAdd("d", tmp, _ -(Weekday(tmp) - .wDayOfWeek + 7 - 1) Mod 7) End Select End With 'Now that the date has been calculated, 'return it in the string format requested 'In VB6, you can use the FormatDateTime function 'to return date in specified format GetTimezoneChangeDate = FormatDateTime(tmp, dwType) End Function Private Function GetTimezoneChangeTime(tzi As SYSTEMTIME, _ ByVal dwType As DateFormats) As String Dim tmp As Date tmp = TimeSerial(tzi.wHour, tzi.wMinute, tzi.wSecond) GetTimezoneChangeTime = FormatDateTime(tmp, dwType) End Function |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comments | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
If your version of VB does not support the FormatDateTime function, use
the following code blocks instead in the GetTimezoneChangeDate and
GetTimezoneChangeTime routines:
'In VB4-32 or VB5, use Format$ instead in GetTimezoneChangeDate Select Case dwType Case vbGeneralDate: GetTimezoneChangeDate = Format$(tmp, "general date") Case vbLongDate: GetTimezoneChangeDate = Format$(tmp, "long date") Case vbShortDate: GetTimezoneChangeDate = Format$(tmp, "short date") End Select 'In VB4-32 or VB5, use Format$ instead in GetTimezoneChangeTime Select Case dwType Case vbLongTime: tmp = Format$(tmp, "long time") Case vbShortTime: tmp = Format$(tmp, "short time") End Select
As befits a global implementation of what North American's call
Daylight Saving Time, different countries around the world recognize different
start and end dates to this period. I know the code above, and on related pages,
works for the North American periods, but I'd like to hear from those on other
continents where the routine above also works for them, or what
modifications were necessary to make it work for your local zones. The following
is a listing of the countries observing DST or its equivalent, and the local
start/end periods, gleaned from an excellent reference to DST
located at http://webexhibits.org/daylightsaving/index.html
. Note too that not all provinces, states or regions recognize
DST, for example Saskatchewan in Canada, Central Indiana in the US.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
|||||
|
|||||
|
|||||
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |