Download... the code. (4 kb)
There is a proliferation of date/time formats on the internet, egged on by competing
standards, setup by various international standards organizations. These dates appears in
email message headers, RSS feeds, etc... The two date/time standards that are used
most often are defined as ISO8601 and RFC822.
Unfortunately, Visual Basic does not provide an automatic way to convert these formats
into the native VB Date data type. The situation is made even more complicated because
ISO8601 and RFC822 also include time zone information. So it is not enough to be able
to parse out the time and date -- you also must convert the time zone information and
figure out what it means to your local time.
| Format |
Examples |
Notes |
| ISO8601 |
1997-07-16T19:20:30+01:00 or
1997-07-16T19:20:30Z
|
+01:00 means that the time zone is 1 hour ahead of GMT/UTC.
Z after the time means GMT/UTC
|
| RFC822 |
Tue, 23 Sep 2003 13:21:00 -07:00 or
Tue, 23 Sep 2003 13:21:00 GMT
|
-07:00 means that the time zone is 7 hour behind of GMT/UTC.
GMT means GMT/UTC. There are other written time zone settings,
but the code doesn't support them. Feel free to add support.
|
The code here parses these date formats, compares and applies the time zone information as it
relates to your time zone and returns the result in Visual Basic Date data type.
You can either download the code or copy and paste it from below into a module or class.
Then simply call InternetTimeToVbLocalTime method. Note that project
contains other really useful date/time routines, such as GetGmtTime (gets GMT time
based on your local time), GetTimeHere (gets your local time based on the GMT time),
GetTimeDifference (gets the difference in seconds between your local time and the
GMT time). And finally, you can sleep well at night, knowing that daylight savings time changes
around the world are all accounted for.
| Add the following to Module or Class |
Option Explicit
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(31) As Integer
StandardDate As SYSTEMTIME
StandardBias As Long
DaylightName(31) As Integer
DaylightDate As SYSTEMTIME
DaylightBias As Long
End Type
Private Declare Function GetTimeZoneInformation _
Lib "kernel32" (lpTimeZoneInformation As TIME_ZONE_INFORMATION) As Long
Private Const TIME_ZONE_ID_INVALID& = &HFFFFFFFF
Private Const TIME_ZONE_ID_STANDARD& = 1
Private Const TIME_ZONE_ID_UNKNOWN& = 0
Private Const TIME_ZONE_ID_DAYLIGHT& = 2
Private Declare Function InternetTimeToSystemTime Lib "wininet.dll" _
(ByVal lpszTime As String, _
ByRef pst As SYSTEMTIME, _
ByVal dwReserved As Long) _
As Long
Public Function GetGmtTime(Optional StartingDate As Variant) As Date
'Parameters: StartingDate (Optional). The function will figure
'out GMT time based on StartingDate
'If StartingDate is not provided, the current time will be used
Dim Difference As Long
Difference = GetTimeDifference()
If IsMissing(StartingDate) Then
'use current time
GetGmtTime = DateAdd("s", -Difference, Now)
Else
'use StartingDate
GetGmtTime = DateAdd("s", -Difference, StartingDate)
End If
End Function
Public Function GetTimeDifference() As Long
'Returns the time difference between
'local & GMT time in seconds.
'If the result is negative, your time zone
'lags behind GMT zone.
'If the result is positive, your time zone is ahead.
Dim tz As TIME_ZONE_INFORMATION
Dim retcode As Long
Dim Difference As Long
'retrieve the time zone information
retcode = GetTimeZoneInformation(tz)
'convert to seconds
Difference = -tz.Bias * 60
'cache the result
GetTimeDifference = Difference
'if we are in daylight saving time, apply the bias.
If retcode = TIME_ZONE_ID_DAYLIGHT& Then
If tz.DaylightDate.wMonth <> 0 Then
'if tz.DaylightDate.wMonth = 0 then the daylight
'saving time change doesn't occur
GetTimeDifference = Difference - tz.DaylightBias * 60
End If
End If
End Function
Public Function GetTimeHere(gmtTime As Date) As Date
'Parameters: gmtTime - Provides the time & date
'from which to make calculations
'Returns the time in your local time zone
'which corresposponds to GMT time
Dim Differerence As Long
Differerence = GetTimeDifference()
GetTimeHere = DateAdd("s", Differerence, gmtTime)
End Function
Public Function InternetTimeToVbLocalTime(ByVal DateString As String) As Date
'Currently we process 2 formats
'Rfc822 and Iso8601
'Iso8601 is either 1997-07-16T19:20:30+01:00 (25 bytes) or 1997-07-16T19:20:30Z (20 bytes)
'Rfc822 is Tue, 23 Sep 2003 13:21:00 -07:00 (32 bytes) or Tue, 23 Sep 2003 13:21:00 GMT (29 bytes)
'The key difference is that Iso8661 time has a latin letter T in position 11
DateString = Trim$(DateString)
If Mid$(DateString, 11, 1) = "T" Then
InternetTimeToVbLocalTime = Iso8601TimeToLocalVbTime(DateString)
Else
InternetTimeToVbLocalTime = Rfc822TimeToLocalVbTime(DateString)
End If
End Function
Private Function Iso8601TimeToLocalVbTime(ByVal sIso8601 As String) As Date
'format of the time is similar to this: 1997-07-16T19:20:30+01:00
'or 1997-07-16T19:20:30Z or 2003-10-09T09:40:46Z
'where Z is UTC (aka GMT time)
'formatting breakdown
' 1012141618202224
' 1997-07-16T19:20:30+01:00
' 1234567891113151719212325
Dim sYear As String
Dim sMonth As String
Dim sDay As String
Dim sHour As String
Dim sMinute As String
Dim sSecond As String
Dim sTimeZone As String
Dim dtDateTime As Date
Dim bSign As Boolean
Dim dGMT As Long
sYear = Left$(sIso8601, 4)
sMonth = Mid$(sIso8601, 6, 2)
sDay = Mid$(sIso8601, 9, 2)
sHour = Mid$(sIso8601, 12, 2)
sMinute = Mid$(sIso8601, 15, 2)
sSecond = Mid$(sIso8601, 18, 2)
sTimeZone = Mid$(sIso8601, 20)
dtDateTime = CDate(DateSerial(sYear, sMonth, sDay) & " " & _
TimeSerial(sHour, sMinute, sSecond))
'replace Z with +00:00 for easier processing
sTimeZone = Replace(sTimeZone, "Z", "+00:00", , , vbTextCompare)
'get the size
bSign = IIf(Left$(sTimeZone, 1) = "+", True, False)
'grab the hour & minutes
dGMT = Val(Mid$(sTimeZone, Len(sTimeZone) - 3, 2)) + (CInt(Right$(sTimeZone, 2)) * 100 / 60)
If bSign Then
dtDateTime = DateAdd("H", -dGMT, dtDateTime)
Else
dtDateTime = DateAdd("H", dGMT, dtDateTime)
End If
Iso8601TimeToLocalVbTime = GetTimeHere(dtDateTime)
End Function
Private Function Rfc822TimeToLocalVbTime(sRfc822 As String) As Date
Dim uSystemTime As SYSTEMTIME
Dim sWWW As String
Dim iHours As Integer
Dim dGMT As Long
Dim sHourDifferential As String
Dim dtDateTime As Date
Dim sSign As String
Dim bSign As Boolean
Dim sEscapedTime As String
Dim sTimeZoneString As String
Dim iPos As Integer
'true = positive
'false = negative
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sWWW = sRfc822
If InStr(1, sWWW, "GMT", vbTextCompare) > 0 Then
sWWW = Replace(sWWW, "GMT", "+0000")
End If
'check to make sure that the time zone is included
If Len(Trim$(sWWW)) = 25 Then
'add time zone
sWWW = sWWW & " +0000"
End If
If (InStr(1, sWWW, ",") = 0) Then sWWW = "Thu, " & sWWW
Call InternetTimeToSystemTime(sWWW, uSystemTime, 0&)
With uSystemTime
dtDateTime = CDate(DateSerial(.wYear, .wMonth, .wDay) & " " & _
TimeSerial(.wHour, .wMinute, .wSecond))
End With
'get the sign from the back end
'remove colons, in case the time is 07:00 instead of 0700
sEscapedTime = Replace(sWWW, ":", "")
sSign = Mid$(sEscapedTime, Len(sEscapedTime) - 4, 1)
bSign = IIf(sSign = "-", False, True)
'grab the hour & minutes
iPos = InStrRev(sWWW, " ")
If iPos > 0 Then
'get rid of the space and the +/- sign
sTimeZoneString = Mid$(sWWW, iPos + 2)
'escape it
sTimeZoneString = Replace(sTimeZoneString, ":", "")
sTimeZoneString = Replace(sTimeZoneString, " ", "")
'at this point we should have the following: 0700
dGMT = Val(Left$(sTimeZoneString, 2)) + Val(Right$(sWWW, 2)) * 100 / 60
'dGMT = Val(Mid$(sWWW, Len(sWWW) - 3, 2)) + (CInt(Right$(sWWW, 2)) * 100 / 60)
Else
dGMT = 0
End If
If bSign Then
dtDateTime = DateAdd("H", -dGMT, dtDateTime)
Else
dtDateTime = DateAdd("H", dGMT, dtDateTime)
End If
Rfc822TimeToLocalVbTime = GetTimeHere(dtDateTime)
End Function
Download... the code. (4 kb)