【问题标题】:Retrieve current number of hours Local Machine is offset from UTC Time (with VBA)检索当前小时数本地计算机与 UTC 时间的偏移(使用 VBA)
【发布时间】:2018-06-09 07:52:04
【问题描述】:

人们在多个时区使用我的项目。

为了转换时间戳,使用 VBA 仅检索 本地计算机与 UTC 偏移的当前小时数的最快方法是什么?

【问题讨论】:

  • 如果您只是确定 current 偏移量,那么逻辑上您只能使用它来转换 current 时间戳。您无法保证偏移量在一个时间戳与下一个时间戳之间不会有所不同。

标签: excel vba ms-access timezone timezone-offset


【解决方案1】:

这里有两种现成的方法来检索与 UTC 时间偏移的当前小时数,仅此而已:

方法一:使用“任意”API

Option Explicit

Function hoursOffsetFromUTC() As Single
    'returns current #hours difference between UTC & Local System Time
    'On Error GoTo uError
    Dim xmlHTTP As Object, strUTC As String, dtUTC As Date
    Set xmlHTTP = CreateObject("MSXML2.XMLHTTP")
    xmlHTTP.Open "GET", "https://maps.googleapis.com/maps/api/" & _
        "timezone/json?location=" & Int(Rnd() * 99) & ",0&timestamp=" & Int(Rnd() * 99), False
    xmlHTTP.send 'send randomized reqeust to avoid cached results
    strUTC = Mid(xmlHTTP.getResponseHeader("date"), 6, 20)
    Set xmlHTTP = Nothing
    dtUTC = DateValue(strUTC) + TimeValue(strUTC)
    hoursOffsetFromUTC = Round((Now() - dtUTC) * 48, 0) / 2 'nearest 0.5
    Exit Function
uError:
    MsgBox "Couldn't get UTC time." & vbLf & vbLf & _
        "Err#" & Err & ": " & Err.Description, vbExclamation, "Error!"
End Function
  • 示例用法:MsgBox hoursOffsetFromUTC

方法二:使用 Windows API

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 LongPtr
    StandardName(0 To 31) As Integer
    StandardDate As SYSTEMTIME
    StandardBias As LongPtr
    DaylightName(0 To 31) As Integer
    DaylightDate As SYSTEMTIME
    DaylightBias As LongPtr
End Type

Private Declare PtrSafe Function GetTimeZoneInformation Lib "kernel32" _
    (lpTimeZoneInformation As TIME_ZONE_INFORMATION) As Long

Function hoursOffsetFromUTC_Win() As Single
    Dim TZI As TIME_ZONE_INFORMATION
    If GetTimeZoneInformation(TZI) = 2 Then
        hoursOffsetFromUTC_Win = 0 - ((TZI.Bias + TZI.DaylightBias) / 60)
    Else
        hoursOffsetFromUTC_Win = 0 - (TZI.Bias / 60)
    End If
End Function
  • 使用示例:MsgBox hoursOffsetFromUTC_Win

方法一代码较少,但需要互联网连接。它使用随机数调用 Google API 以避免缓存,并忽略响应正文,它获取响应标头中返回的请求日期并将其与本地系统时间进行比较。 (可以使用在标头中返回当前 UTC/GMT 的任何 API。)

方法二 需要声明两种类型和一个外部函数,但在没有互联网连接的情况下运行,使用来自 Windows 内部 kernel32 API 的功能。


转换时间戳:

  • 将数字 Unix/纪元时间戳转换为“Excel Time”:

    ( 时间戳 / 86400 ) + 25569 = ExcelTime

  • 或者,反过来,从 Excel 到纪元时间戳:

    (ExcelTime - 25569) * 86400 = 时间戳

(这些不包括时区调整,因此您可以根据需要添加/减去它。)


更多信息:

【讨论】:

  • 是否值得使用编译器定义来提供 32 位和 64 位的GetTimeZoneInformation 导入?
  • @Jeeped 是的.....我正在与之抗争。编码和测试对我来说很困难,因为无论是否使用 32/64 语法,它对我来说都运行良好
  • 为什么要生成一个随机数来传递选项 1 中的时间戳?通过这样做,您不一定要使用 current 偏移量。相反,您应该传递您计划转换的时间戳。
猜你喜欢
  • 1970-01-01
  • 2016-04-24
  • 2023-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
相关资源
最近更新 更多