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.


Continent Country Beginning and ending days
Africa Egypt Start: Last Friday in April
End: Last Thursday in September
  Namibia Start: First Sunday in September
End: First Sunday in April
Asia Most states of the former USSR Start: Last Sunday in March
End: Last Sunday in October
  Iraq Start: April 1
End: October 1
  Israel (Estimate, Israel decides the dates every year)
Start: First Friday in April
End: First Friday in September
  Lebanon, Kirgizstan Start: Last Sunday in March
End: Last Sunday in October
  Mongolia Start: Last Sunday in March
End: Last Sunday in September
  Palestine (Estimate)
Start: First Friday on or after 5 April
End: First Friday on or after 5 October
 
  Syria Start: April 1
End: October 1
  Iran Start: the first day of Farvardin
End: the first day of Mehr
Australasia
(region that encompasses Australia, Tasmania, New Zealand, and other islands in the South Pacific)
Australia - South Australia, Victoria, Australian Capital Territory, New South Wales, Lord Howe Island Start: Last Sunday in October
End: Last Sunday in March
  Australia - Tasmania Start: First Sunday in October
End: Last Sunday in March
  Fiji Start: First Sunday in November
End: Last Sunday in February
  New Zealand, Chatham Start: First Sunday in October
End: First Sunday on or after 5 March
  Tonga Start: First Saturday in October
End: First Saturday on or after 15 April
Europe European Union, Russia Start: Last Sunday in March
End: Last Sunday in October
  Greenland Start: First Sunday in April
End: Last Sunday in October
North America Canada, United States, Mexico, St. Johns, Bahamas, Turks and Caicos Start: First Sunday in April
End: Last Sunday in October
  Cuba Start: April 1
End: Last Sunday in October
South America Brazil Start: First Sunday in October
End: Last Sunday in February
  Chile Start: First Sunday on or after 9 October
End: First Sunday on or after 9 March
  Falklands Start: First Sunday on or after 8 September
End: First Sunday on or after 6 April
  Paraguay Start: First Sunday in October
End: Last Saturday in February
Antarctica Antarctica (same as Chile)


 
 

PayPal Link
Make payments with PayPal - it's fast, free and secure!

 
 
 
 

Copyright 1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy

 

Hit Counter