在VBA中获取时区信息(Excel)

Get Timezone Information in VBA (Excel)

我想确定VBA中特定日期不同国家/地区的GMT / UTC(包括夏令时)的时间偏差。 有任何想法吗?

编辑(来自自我回答):

谢谢0xA3。 我快速阅读链接页面。 我假设您只能为运行Windows的本地获取GMT的偏移量:

1
2
3
4
5
6
ConvertLocalToGMT    
DaylightTime  
GetLocalTimeFromGMT          
LocalOffsetFromGMT
SystemTimeToVBTime
LocalOffsetFromGMT

在Java中,您可以执行以下操作:

1
2
3
4
5
6
TimeZone bucharestTimeZone = TimeZone.getTimeZone("Europe/Bucharest");
    bucharestTimeZone.getOffset(new Date().getTime());

Calendar nowInBucharest = Calendar.getInstance(TimeZone.getTimeZone("Europe/Bucharest"));
    nowInBucharest.setTime(new Date());
    System.out.println("Bucharest:" + nowInBucharest.get(Calendar.HOUR) +":" + nowInBucharest.get(Calendar.MINUTE));

这意味着我可以获得不同国家(时区)的偏移量,因此我也可以得到布加勒斯特的实际时间。 我可以在VBA中这样做吗?


VBA不提供执行此操作的功能,但Windows API可以执行此操作。幸运的是,您也可以使用VBA的所有功能。本页介绍了如何操作:时区和时区夏令时

编辑:添加代码

为了后人的缘故,我在Guru Chip的页面中添加了完整的代码,可以在32位Office VBA中使用。 (这里有64位修改)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
Option Explicit
Option Compare Text
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' modTimeZones
' By Chip Pearson, used with permission from www.cpearson.com
' Date: 2-April-2008
' Page Specific URL: www.cpearson.com/Excel/TimeZoneAndDaylightTime.aspx
'
' This module contains functions related to time zones and GMT times.
'   Terms:
'   -------------------------
'   GMT = Greenwich Mean Time. Many applications use the term
'       UTC (Universal Coordinated Time). GMT and UTC are
'       interchangable in meaning,
'   Local Time = The local"wall clock" time of day, that time that
'       you would set a clock to.
'   DST = Daylight Savings Time

'   Functions In This Module:
'   -------------------------
'       ConvertLocalToGMT
'           Converts a local time to GMT. Optionally adjusts for DST.
'       DaylightTime
'           Returns a value indicating (1) DST is in effect, (2) DST is
'           not in effect, or (3) Windows cannot determine whether DST is
'           in effect.
'       GetLocalTimeFromGMT
'           Converts a GMT Time to a Local Time, optionally adjusting for DST.
'       LocalOffsetFromGMT
'           Returns the number of hours/minutes between the local time &GMT,
'           optionally adjusting for DST.
'       SystemTimeToVBTime
'           Converts a SYSTEMTIME structure to a valid VB/VBA date.
'       LocalOffsetFromGMT
'           Returns the number of minutes or hours that are to be added to
'           the local time to get GMT. Optionally adjusts for DST.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

' Required Types
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 31) As Integer
    StandardDate As SYSTEMTIME
    StandardBias As Long
    DaylightName(0 To 31) As Integer
    DaylightDate As SYSTEMTIME
    DaylightBias As Long
End Type

Public Enum TIME_ZONE
    TIME_ZONE_ID_INVALID = 0
    TIME_ZONE_STANDARD = 1
    TIME_ZONE_DAYLIGHT = 2
End Enum

' Required Windows API Declares
Private Declare Function GetTimeZoneInformation Lib"kernel32" _
    (lpTimeZoneInformation As TIME_ZONE_INFORMATION) As Long

Private Declare Sub GetSystemTime Lib"kernel32" _
    (lpSystemTime As SYSTEMTIME)

Function ConvertLocalToGMT(Optional LocalTime As Date, _
    Optional AdjustForDST As Boolean = False) As Date
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' ConvertLocalToGMT
' This converts a local time to GMT. If LocalTime is present, that local
' time is converted to GMT. If LocalTime is omitted, the current time is
' converted from local to GMT. If AdjustForDST is Fasle, no adjustments
' are made to accomodate DST. If AdjustForDST is True, and DST is
' in effect, the time is adjusted for DST by adding
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Dim T As Date
    Dim TZI As TIME_ZONE_INFORMATION
    Dim DST As TIME_ZONE
    Dim GMT As Date

    If LocalTime <= 0 Then
        T = Now
    Else
        T = LocalTime
    End If
    DST = GetTimeZoneInformation(TZI)
    If AdjustForDST = True Then
        GMT = T + TimeSerial(0, TZI.Bias, 0) + _
                IIf(DST=TIME_ZONE_DAYLIGHT,TimeSerial(0, TZI.DaylightBias,0),0)
    Else
        GMT = T + TimeSerial(0, TZI.Bias, 0)
    End If
    ConvertLocalToGMT = GMT
End Function

Function GetLocalTimeFromGMT(Optional StartTime As Date) As Date
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' GetLocalTimeFromGMT
' This returns the Local Time from a GMT time. If StartDate is present and
' greater than 0, it is assumed to be the GMT from which we will calculate
' Local Time. If StartTime is 0 or omitted, it is assumed to be the GMT
' local time.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Dim GMT As Date
    Dim TZI As TIME_ZONE_INFORMATION
    Dim DST As TIME_ZONE
    Dim LocalTime As Date

    If StartTime <= 0 Then
        GMT = Now
    Else
        GMT = StartTime
    End If
    DST = GetTimeZoneInformation(TZI)
    LocalTime = GMT - TimeSerial(0, TZI.Bias, 0) + _
            IIf(DST = TIME_ZONE_DAYLIGHT, TimeSerial(1, 0, 0), 0)
    GetLocalTimeFromGMT = LocalTime
End Function

Function SystemTimeToVBTime(SysTime As SYSTEMTIME) As Date
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' SystemTimeToVBTime
' This converts a SYSTEMTIME structure to a VB/VBA date value.
' It assumes SysTime is valid -- no error checking is done.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    With SysTime
        SystemTimeToVBTime = DateSerial(.wYear, .wMonth, .wDay) + _
                TimeSerial(.wHour, .wMinute, .wSecond)
    End With
End Function

Function LocalOffsetFromGMT(Optional AsHours As Boolean = False, _
    Optional AdjustForDST As Boolean = False) As Long
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' LocalOffsetFromGMT
' This returns the amount of time in minutes (if AsHours is omitted or
' false) or hours (if AsHours is True) that should be added to the
' local time to get GMT. If AdjustForDST is missing or false,
' the unmodified difference is returned. (e.g., Kansas City to London
' is 6 hours normally, 5 hours during DST. If AdjustForDST is False,
' the resultif 6 hours. If AdjustForDST is True, the result is 5 hours
' if DST is in effect.)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Dim TBias As Long
    Dim TZI As TIME_ZONE_INFORMATION
    Dim DST As TIME_ZONE
    DST = GetTimeZoneInformation(TZI)

    If DST = TIME_ZONE_DAYLIGHT Then
        If AdjustForDST = True Then
            TBias = TZI.Bias + TZI.DaylightBias
        Else
            TBias = TZI.Bias
        End If
    Else
        TBias = TZI.Bias
    End If
    If AsHours = True Then
        TBias = TBias / 60
    End If

    LocalOffsetFromGMT = TBias
End Function

Function DaylightTime() As TIME_ZONE
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' DaylightTime
' Returns a value indicating whether the current date is
' in Daylight Time, Standard Time, or that Windows cannot
' deterimine the time status. The result is a member or
' the TIME_ZONE enum.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Dim TZI As TIME_ZONE_INFORMATION
    Dim DST As TIME_ZONE
    DST = GetTimeZoneInformation(TZI)
    DaylightTime = DST
End Function


请注意解决方案中的小陷阱。

GetTimeZoneInformation()调用返回有关当前时间的DST信息,但转换日期可能来自具有不同DST设置的时段 - 因此,转换8月份的1月日期将应用当前偏差,从而产生比当前时间少1小时的GMT日期正确的(SystemTimeToTzSpecificLocalTime似乎更合适 - 尚未经过测试)

当日期来自另一年 - 当夏令时规则可能不同时,同样适用。 GetTimeZoneInformationForYear应该处理不同年份的变化。完成后我会把代码示例放在这里。

它似乎也没有提供一种可靠的方法来获得时区的3个字母缩写(Excel 2013支持格式()中的zzz - 未经测试)。

编辑16.04.2015:删除了IntArrayToString(),因为它已经存在于下面提到的cpearson.com文章中引用的modWorksheetFunctions.bas中。

添加代码以使用转换日期时激活的时区进行转换(此问题未在cpearson.com上解决)。为简洁起见,不包括错误处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Private Type DYNAMIC_TIME_ZONE_INFORMATION_VB
    Bias As Long
    StandardName As String
    StandardDate As Date
    StandardBias As Long
    DaylightName As String
    DaylightDate As Date
    DaylightBias As Long
    TimeZoneKeyName As String
    DynamicDaylightTimeDisabled As Long
End Type

Private Declare Function GetTimeZoneInformationForYear Lib"kernel32" ( _
    wYear As Integer, _
    lpDynamicTimeZoneInformation As DYNAMIC_TIME_ZONE_INFORMATION, _
    lpTimeZoneInformation As TIME_ZONE_INFORMATION _
) As Long

Private Declare Function GetDynamicTimeZoneInformation Lib"kernel32" ( _
    pTimeZoneInformation As DYNAMIC_TIME_ZONE_INFORMATION _
) As Long

Private Declare Function TzSpecificLocalTimeToSystemTimeEx Lib"kernel32" ( _
    lpDynamicTimeZoneInformation As DYNAMIC_TIME_ZONE_INFORMATION, _
    lpLocalTime As SYSTEMTIME, _
    lpUniversalTime As SYSTEMTIME _
) As Long

Function LocalSerialTimeToGmt(lpDateLocal As Date) As Date
    Dim retval As Boolean, lpDateGmt As Date, lpSystemTimeLocal As SYSTEMTIME, lpSystemTimeGmt As SYSTEMTIME
    Dim lpDTZI As DYNAMIC_TIME_ZONE_INFORMATION

    retval = SerialTimeToSystemTime(lpDateLocal, lpSystemTimeLocal)
    retval = GetDynamicTimeZoneInformation(lpDTZI)
    retval = TzSpecificLocalTimeToSystemTimeEx(lpDTZI, lpSystemTimeLocal, lpSystemTimeGmt)
    lpDateGmt = SystemTimeToSerialTime(lpSystemTimeGmt)
    LocalSerialTimeToGmt = lpDateGmt
End Function

有两种方法可以实现抵消:

  • 减去本地日期和转换的gmt日期:

    offset = (lpDateLocal - lpDateGmt)*24*60

  • 获得特定年份的TZI并计算:

    dst = GetTimeZoneInformationForYear(Year(lpDateLocal), lpDTZI, lpTZI)
    offset = lpTZI.Bias + IIf(lpDateLocal >= SystemTimeToSerialTime(lpTZI.DaylightDate) And lpDateLocal < SystemTimeToSerialTime(lpTZI.StandardDate), lpTZI.DaylightBias, lpTZI.StandardBias)

  • 警告:由于某种原因,lpTZI中填充的值不包含年份信息,因此您需要在lpTZI.DaylightDate和lpTZI.StandardDate中设置年份。


    以下是0xA3在答案中引用的代码。我不得不更改声明语句以允许它在Office 64bit中正常运行但我无法再在Office 32bit中进行测试。对于我的使用,我试图用时区信息创建ISO 8601日期。所以我使用了这个功能。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    Public Function ConvertToIsoTime(myDate As Date, includeTimezone As Boolean) As String

        If Not includeTimezone Then
            ConvertToIsoTime = Format(myDate,"yyyy-mm-ddThh:mm:ss")
        Else
            Dim minOffsetLong As Long
            Dim hourOffset As Integer
            Dim minOffset As Integer
            Dim formatStr As String
            Dim hourOffsetStr As String

            minOffsetLong = LocalOffsetFromGMT(False, True) * -1
            hourOffset = minOffsetLong \ 60
            minOffset = minOffsetLong Mod 60

            If hourOffset >= 0 Then
                hourOffsetStr ="+" + CStr(Format(hourOffset,"00"))
            Else
                hourOffsetStr = CStr(Format(hourOffset,"00"))
            End If

            formatStr ="yyyy-mm-ddThh:mm:ss" + hourOffsetStr +":" + CStr(Format(minOffset,"00"))
            ConvertToIsoTime = Format(myDate, formatStr)


        End If

    End Function

    以下代码来自http://www.cpearson.com/excel/TimeZoneAndDaylightTime.aspx

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    Option Explicit
    Option Compare Text
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ' modTimeZones
    ' By Chip Pearson, [email protected], www.cpearson.com
    ' Date: 2-April-2008
    ' Page Specific URL: www.cpearson.com/Excel/TimeZoneAndDaylightTime.aspx
    '
    ' This module contains functions related to time zones and GMT times.
    '   Terms:
    '   -------------------------
    '   GMT = Greenwich Mean Time. Many applications use the term
    '       UTC (Universal Coordinated Time). GMT and UTC are
    '       interchangable in meaning,
    '   Local Time = The local"wall clock" time of day, that time that
    '       you would set a clock to.
    '   DST = Daylight Savings Time

    '   Functions In This Module:
    '   -------------------------
    '       ConvertLocalToGMT
    '           Converts a local time to GMT. Optionally adjusts for DST.
    '       DaylightTime
    '           Returns a value indicating (1) DST is in effect, (2) DST is
    '           not in effect, or (3) Windows cannot determine whether DST is
    '           in effect.
    '       GetLocalTimeFromGMT
    '           Converts a GMT Time to a Local Time, optionally adjusting for DST.
    '       LocalOffsetFromGMT
    '           Returns the number of hours or minutes between the local time and GMT,
    '           optionally adjusting for DST.
    '       SystemTimeToVBTime
    '           Converts a SYSTEMTIME structure to a valid VB/VBA date.
    '       LocalOffsetFromGMT
    '           Returns the number of minutes or hours that are to be added to
    '           the local time to get GMT. Optionally adjusts for DST.
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''


    '''''''''''''''''''''''''''''''''''''''''''''''''''''
    ' Required Types
    '''''''''''''''''''''''''''''''''''''''''''''''''''''
    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 31) As Integer
        StandardDate As SYSTEMTIME
        StandardBias As Long
        DaylightName(0 To 31) As Integer
        DaylightDate As SYSTEMTIME
        DaylightBias As Long
    End Type

    Public Enum TIME_ZONE
        TIME_ZONE_ID_INVALID = 0
        TIME_ZONE_STANDARD = 1
        TIME_ZONE_DAYLIGHT = 2
    End Enum

    '''''''''''''''''''''''''''''''''''''''''''''''''''''
    ' Required Windows API Declares
    '''''''''''''''''''''''''''''''''''''''''''''''''''''
    #If VBA7 Then
        Private Declare PtrSafe Function GetTimeZoneInformation Lib"kernel32" _
        (lpTimeZoneInformation As TIME_ZONE_INFORMATION) As Long
    #Else
        Private Declare Function GetTimeZoneInformation Lib"kernel32" _
        (lpTimeZoneInformation As TIME_ZONE_INFORMATION) As Long
    #End If

    #If VBA7 Then
        Private Declare PtrSafe Sub GetSystemTime Lib"kernel32" _
            (lpSystemTime As SYSTEMTIME)
    #Else
        Private Declare Sub GetSystemTime Lib"kernel32" _
            (lpSystemTime As SYSTEMTIME)
    #End If




    Function ConvertLocalToGMT(Optional LocalTime As Date, _
        Optional AdjustForDST As Boolean = False) As Date
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ' ConvertLocalToGMT
    ' This converts a local time to GMT. If LocalTime is present, that local
    ' time is converted to GMT. If LocalTime is omitted, the current time is
    ' converted from local to GMT. If AdjustForDST is Fasle, no adjustments
    ' are made to accomodate DST. If AdjustForDST is True, and DST is
    ' in effect, the time is adjusted for DST by adding
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Dim T As Date
    Dim TZI As TIME_ZONE_INFORMATION
    Dim DST As TIME_ZONE
    Dim GMT As Date

    If LocalTime <= 0 Then
        T = Now
    Else
        T = LocalTime
    End If
    DST = GetTimeZoneInformation(TZI)
    If AdjustForDST = True Then
        GMT = T + TimeSerial(0, TZI.Bias, 0) + _
                IIf(DST = TIME_ZONE_DAYLIGHT, TimeSerial(0, TZI.DaylightBias, 0), 0)
    Else
        GMT = T + TimeSerial(0, TZI.Bias, 0)
    End If
    ConvertLocalToGMT = GMT

    End Function


    Function GetLocalTimeFromGMT(Optional StartTime As Date) As Date
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ' GetLocalTimeFromGMT
    ' This returns the Local Time from a GMT time. If StartDate is present and
    ' greater than 0, it is assumed to be the GMT from which we will calculate
    ' Local Time. If StartTime is 0 or omitted, it is assumed to be the GMT
    ' local time.
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Dim GMT As Date
    Dim TZI As TIME_ZONE_INFORMATION
    Dim DST As TIME_ZONE
    Dim LocalTime As Date

    If StartTime <= 0 Then
        GMT = Now
    Else
        GMT = StartTime
    End If
    DST = GetTimeZoneInformation(TZI)
    LocalTime = GMT - TimeSerial(0, TZI.Bias, 0) + _
            IIf(DST = TIME_ZONE_DAYLIGHT, TimeSerial(1, 0, 0), 0)
    GetLocalTimeFromGMT = LocalTime

    End Function

    Function SystemTimeToVBTime(SysTime As SYSTEMTIME) As Date
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ' SystemTimeToVBTime
    ' This converts a SYSTEMTIME structure to a VB/VBA date value.
    ' It assumes SysTime is valid -- no error checking is done.
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    With SysTime
        SystemTimeToVBTime = DateSerial(.wYear, .wMonth, .wDay) + _
                TimeSerial(.wHour, .wMinute, .wSecond)
    End With

    End Function

    Function LocalOffsetFromGMT(Optional AsHours As Boolean = False, _
        Optional AdjustForDST As Boolean = False) As Long
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ' LocalOffsetFromGMT
    ' This returns the amount of time in minutes (if AsHours is omitted or
    ' false) or hours (if AsHours is True) that should be added to the
    ' local time to get GMT. If AdjustForDST is missing or false,
    ' the unmodified difference is returned. (e.g., Kansas City to London
    ' is 6 hours normally, 5 hours during DST. If AdjustForDST is False,
    ' the resultif 6 hours. If AdjustForDST is True, the result is 5 hours
    ' if DST is in effect.)
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

    Dim TBias As Long
    Dim TZI As TIME_ZONE_INFORMATION
    Dim DST As TIME_ZONE
    DST = GetTimeZoneInformation(TZI)

    If DST = TIME_ZONE_DAYLIGHT Then
        If AdjustForDST = True Then
            TBias = TZI.Bias + TZI.DaylightBias
        Else
            TBias = TZI.Bias
        End If
    Else
        TBias = TZI.Bias
    End If
    If AsHours = True Then
        TBias = TBias / 60
    End If

    LocalOffsetFromGMT = TBias

    End Function

    Function DaylightTime() As TIME_ZONE
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ' DaylightTime
    ' Returns a value indicating whether the current date is
    ' in Daylight Time, Standard Time, or that Windows cannot
    ' deterimine the time status. The result is a member or
    ' the TIME_ZONE enum.
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Dim TZI As TIME_ZONE_INFORMATION
    Dim DST As TIME_ZONE
    DST = GetTimeZoneInformation(TZI)
    DaylightTime = DST
    End Function

    我建议创建一个Outlook对象并使用内置方法ConvertTime:https://msdn.microsoft.com/VBA/Outlook-VBA/articles/timezones-converttime-method-outlook

    超级简单,超级保存,只需几行代码

    This example converts the inputTime from UTC to CET:

    As a source/destination time zone you can use all time zones you can find
    in your registry under:
    HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Time Zones/

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    Dim OutlookApp As Object
    Dim TZones As TimeZones
    Dim convertedTime As Date
    Dim inputTime As Date
    Dim sourceTZ As TimeZone
    Dim destTZ As TimeZone
    Dim secNum as Integer
    Set OutlookApp = CreateObject("Outlook.Application")
    Set TZones = OutlookApp.TimeZones
    Set sourceTZ = TZones.Item("UTC")
    Set destTZ = TZones.Item("W. Europe Standard Time")
    inputTime = Now
    Debug.Print"GMT:" &amp; inputTime
    '' the outlook rounds the seconds to the nearest minute
    '' thus, we store the seconds, convert the truncated time and add them later
    secNum = Second(inputTime)
    inputTime = DateAdd("s",-secNum, inputTime)
    convertedTime = TZones.ConvertTime(inputTime, sourceTZ, destTZ)
    convertedTime = DateAdd("s",secNum, convertedTime)
    Debug.Print"CET:" &amp; convertedTime

    PS:如果您经常使用该方法,我建议您在子/函数之外声明Outlook对象。创建一次并保持活着。


    基于Julian Hess使用Outlook功能的出色建议,我构建了这个模块,它与Access和Excel一起使用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    Option Explicit

    'mTimeZones by Patrick Honorez --- www.idevlop.com
    'with the precious help of Julian Hess https://stackoverflow.com/a/45510712/78522
    'You can reuse but please let all the original comments including this one.

    'This modules uses late binding and therefore should not require an explicit reference to Outlook,
    'however Outlook must be properly installed and configured on the machine using this module
    'Module works with Excel and Access

    Private oOutl As Object 'keep Outlook reference active, to save time n recurring calls

    Private Function GetOutlook() As Boolean
    'get or start an Outlook instance and assign it to oOutl
    'returns True if successful, False otherwise
        If oOutl Is Nothing Then
            Debug.Print"~"
            On Error Resume Next
            Err.Clear
            Set oOutl = GetObject(,"Outlook.Application")
            If Err.Number Then
                Err.Clear
                Set oOutl = CreateObject("Outlook.Application")
            End If
        End If
        GetOutlook = Not (oOutl Is Nothing)
        On Error GoTo 0
    End Function

    Function ConvertTime(DT As Date, Optional TZfrom As String ="Central Standard Time", _
                                     Optional TZto As String ="W. Europe Standard Time") As Date
    'convert datetime with hour from Source time zone to Target time zone
    'valid Source & Target time zones can be found in your registry under: HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Time Zones/
    'this version using Outlook, properly handles Dailight Saving Times, including for past and future dates
    'it includes a fix for the fact that ConvertTime seems to strip the seconds
    'krammy85 2019-01-25 Edit: Outlook rounds minutes when it strips seconds, so modified code to strip seconds (without rounding) prior to running Outlook's ConvertTime.
        Dim TZones As Object
        Dim sourceTZ As Object
        Dim destTZ As Object
        Dim seconds As Single
        Dim DT_SecondsStripped As Date
        If GetOutlook Then
            'fix for ConvertTime stripping the seconds
            seconds = Second(DT) / 86400    'save the seconds as DateTime (86400 = 24*60*60)
            DT_SecondsStripped = DT - seconds
            Set TZones = oOutl.TimeZones
            Set sourceTZ = TZones.Item(TZfrom)
            Set destTZ = TZones.Item(TZto)
            ConvertTime = TZones.ConvertTime(DT_SecondsStripped, sourceTZ, destTZ) + seconds    'add the stripped seconds
        End If
    End Function

    Sub test_ConvertTime()
        Dim t As Date

        t = #8/23/2017 6:15:05 AM#
        Debug.Print t, ConvertTime(t), Format(t - ConvertTime(t),"h")
    End Sub