|
|
![]() |
|
||
|
|
|||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||
| 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. |
![]() |