我试图找到一种简单而强大的方法来在任意时区之间转换时间。
更新1:我不明白为什么会被投票。我做了我的研究并探索了可能性。这个问题并不像看起来那么简单。如果您认为该函数看起来像bTime = aTime + 3
,那么请重新考虑。时区和DST处于不断变化的状态。阅读本文以供参考:list of pending / proposed timezone changes。请注意,某些国家/地区实际上正在更改其时区,而不仅仅是DST设置!巴西将他们改变时钟的日期改为冬季!所有这些更改都会很快打破静态查找表。
更新2:我没有考虑快速而肮脏的黑客攻击,我可以自己想出来,非常感谢你。我没有得到报酬而忘记它的报酬;我想创建一个功能,一旦其他人可以安全地用于不同的内部项目,而不需要维护噩梦。 已知偶尔更改的硬编码常量是一个非常糟糕的软件设计(想想由一段非常非常旧的代码引起的Y2K错误)。
更新3 :此数据库看起来不错(虽然我不确定它是否足够稳定):https://timezonedb.com/api 他们甚至有一个TZ转换呼叫 - 正是我需要的! 我可能会尝试从VBA解析XML并分享我的结果。
这:http://www.cpearson.com/excel/TimeZoneAndDaylightTime.aspx仅解释如何转换我的(当前)TZ和另一个TZ。
这两篇SO文章(Getting Windows Time Zone Information (C++/MFC)和How do you get info for an arbitrary time zone in Windows?)谈论从注册表中获取信息。
这听起来有点过于复杂和耗时;此外,Windows似乎将TZ存储在他们的全名" (例如(UTC-08:00) Pacific Time (US & Canada)
)和我更喜欢使用缩写(例如EDT)来引用TZ。
更新:此外,依赖Windows注册表也可能不安全:不同的用户可能有不同的版本,有些可能不是最新的。这意味着由两个人运行的报告可能会提供两种不同的结果!
还有一种更简单的方法吗?编写查询表可能会有一段时间,但当政府决定取消DST或更改其他任何内容时,它将被破坏。
也许从互联网上获取TZ列表并解析它?..这样安全吗?..
答案 0 :(得分:4)
https://timezonedb.com/references/convert-time-zone
的API确实是在两个位置之间获得正确的全球时间,时区和时区偏移量的好地方< / strong>,考虑到过去/未来的夏令时变化。
建议的仅指定时区缩写的方法(例如&#34;将PST转换为EST&#34; )存在的问题是此API将您的区域逐字地< / em>,即使它们不正确。
因此,如果多伦多目前在EDT
,但您指定了EST
,那么您可能会得到错误的时间。使用&#34;全名&#34;像(UTC-08:00) Pacific Time (US & Canada)
一样会遇到同样的问题。
一种方法是指定时区名称,例如America/Vancouver
(列为here),或者使用适当的参数指定城市,国家和/或地区名称。
我写了一个函数来解决它,但它只适用于某些国家(见下文)。
结果(默认为XML
,但JSON
也可用。)
<result>
<status>OK</status>
<message/>
<fromZoneName>America/Vancouver</fromZoneName>
<fromAbbreviation>PDT</fromAbbreviation>
<fromTimestamp>1509516660</fromTimestamp>
<toZoneName>America/Toronto</toZoneName>
<toAbbreviation>EDT</toAbbreviation>
<toTimestamp>1509527460</toTimestamp>
<offset>10800</offset>
</result>
您需要决定很多选项和查找方法,但这是使用VBA函数的一个示例:
温哥华和温哥华之间的时差是多少?柏林圣诞节那天?
输入时间:
2018-12-25 00:00:00
=温哥华本地Unix时间1545724800
Function GetTimeZoneOffsetHours(fromZone As String, _
toZone As String, UnixTime As Long) As Single
Const key = "94RKE4SAXH67"
Const returnField = "<offset>"
Dim HTML As String, URL As String
Dim XML As String, pStart As Long, pStop As Long
URL = "http://api.timezonedb.com/v2/convert-time-zone?key=" & key & _
"&from=" & fromZone & "&to=" & toZone & "&time=" & UnixTime
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", URL, False
.Send
XML = .ResponseText
End With
pStart = InStr(XML, returnField)
If pStart = 0 Then
MsgBox "Something went wrong!"
Exit Function
End If
pStart = pStart + Len(returnField) + 1
pStop = InStr(pStart, XML, "</") - 1
GetTimeZoneOffsetHours = Val(Mid(XML, pStart, pStop - pStart)) / 60
End Function
Sub testTZ()
Debug.Print "Time Zone Offset (Vancouver to Berlin) = " & _
GetTimeZoneOffsetHours("America/Vancouver", _
"Europe/Berlin", 1545724800) & " hours"
End Sub
Unix / UTC时间戳:
Unix时间定义为&#34; 自1970年1月1日星期四00:00:00协调世界时(UTC)以来经过的秒数。&#34; < / p>
您可以在Unix和/或UTC或本地时间之间转换时间: epochconverter.com ...该网站还包含多种编程语言的转换公式。
例如,在Excel中将 Unix时间转换为GMT / UTC 的表格是:
=(A1 / 86400) + 25569
您还可以下载静态文件(SQL
或CSV
格式)here,而不是加密API,该页面也有示例查询。 然而谨慎使用:使用夏令时更容易犯错误(如上所述)。
我做了一个虚拟账户来获得&#34;演示&#34;在示例中使用,但您应该获得自己的(免费)密钥以供长期使用。 (如果它被过度使用锁定,我不负责任!)
一个好的替代时区API是 Google Maps Time Zone API 。不同之处在于您指定了Latitude&amp;经度。 它似乎工作很好没有密钥你需要register来获取密钥。
6月1日白宫的时区偏差是什么?
<强>结果强>:
{
"dstOffset" : 0,
"rawOffset" : -18000,
"status" : "OK",
"timeZoneId" : "America/Toronto",
"timeZoneName" : "Eastern Standard Time"
}
偏移量为-18000秒(-5小时)。
以下是我放在一起的功能,所以我可以信任&#34;我从不同的API获得的夏令时(DST)值,但是(正如其他人所讨论的)规则没有模式 plus 不断变化的国家/地区,甚至是城镇的某些部分。世界,所以这只适用于以下国家:
适用的国家是巴哈马,百慕大,加拿大,古巴,海地,圣皮埃尔和美国。 (来源: Daylight saving time by country **)
Function IsDST(dateTime As Date) As Boolean
'Returns TRUE if Daylight Savings is in effect during the [dateTime]
'DST Start (adjust clocks forward) Second Sunday March at 02:00am
'DST end (adjust clocks backward) First Sunday November at 02:00am
Dim DSTStart As Date, DSTstop As Date
DSTStart = DateSerial(Year(dateTime), 3, _
(14 - Weekday(DateSerial(Year(dateTime), 3, 1), 3))) + (2 / 24)
DSTstop = DateSerial(Year(dateTime), 11, _
(7 - Weekday(DateSerial(Year(dateTime), 11, 1), 3))) + (2 / 24)
IsDST = (dateTime >= DSTStart) And (dateTime < DSTstop)
End Function
以及我如何使用函数IsDST
*:
Public Function UTCtoPST(utcDateTime As Date) As Date
'Example for 'PST' time zone, where Offset = -7 during DST, otherwise if -8
If IsDST(utcDateTime) Then
UTCtoPST = utcDateTime - (7 / 24)
Else
UTCtoPST = utcDateTime - (8 / 24)
End If
End Function
Function UTCtimestampMStoPST(ByVal ts As String) As Date
'Example for 'PST', to convert a UTC Unix Time Stamp to 'PST' Time Zone
UTCtimestampMStoPST = UTCtoPST((CLng(Left(ts, 10)) / 86400) + 25569)
End Function
* 请注意,函数
IsDST
不完整:它没有考虑IsDST在凌晨2点实际生效之前/之后的小时数。特别是在春天,时钟从01:59
标准时间的最后一刻向前跳跃到03:00
DST,那天有23个小时,而在秋天,时钟从01:59
夏令时的最后时刻向后跳跃到01:00
标准时间,重复那个小时,那天有25个小时 ... 但是 ,如果有人想要添加该功能来更新功能,请随意!我在最后一部分缠绕我的头部时遇到了麻烦,并没有立即需要那么详细的水平,但我确信其他人会很感激!
最后,还有一个替代方案是我用来为各种目的轮询当前/未来/历史天气数据的API - 并且也恰好提供时区偏移 - 是DarkSky。
按纬度/经度查询并且是免费的(每天最多1000个电话),并提供&#34;超准确的天气数据&#34; (更多信息在美国,它预测天气下降到分钟和平方码! - 但我已经看到加拿大西海岸加拿大不可预测的非常准确!)
响应仅限JSON,最后一行是时区偏移与UTC / GMT 时间。
DarkSky示例调用:
https://api.darksky.net/forecast/85b57f827eb89bf903b3a796ef53733c/40.70893,-74.00662
它说它应该在Stack Overflow的总部接下来的60个小时下雨。 ☂
...但我不知道,到目前为止,这看起来像是一个非常美好的一天! ☀
<子> (flag) 子>
答案 1 :(得分:2)
我担心与时区有任何关系绝不是一项简单的任务(询问任何网页设计师,他们会说这是一项巨大的挑战)
有两种方法可以解决您的问题
1)简单方法 - 创建一个所有其他工作簿链接到的中央列表。这可以保存在SharePoint或共享驱动器上,然后您只需更新此表
即可2)困难的方法 - 使用网站API获取最新的时区数据。 https://www.amdoren.com/是一个很好的网站,您可以通过注册获得免费的API密钥。唯一的问题是你必须从网站解析Json文件。这并不容易,但如果你google&#34; vba parse json&#34;你会发现一些解决方案(它通常需要导入一些库并使用其他人的代码作为起点)
希望您找到合适的解决方案,如果您这样做可能值得分享,因为我确定会有其他人遇到同样的问题。