Convert between arbitrary timezones

心已入冬 提交于 2019-12-06 00:30:59

The API at https://timezonedb.com/references/convert-time-zone is indeed a great place to get the correct worldwide time, timezone, and timezone-offset between two locations, taking into account past/future Daylight Savings changes.

A problem with your suggested method of specifying only the Time Zone Abbreviations (such as "convert PST to EST") is that this API takes your zones literally, even if they are incorrect.

So, if Toronto is currently on EDT but you specify EST, you'll probably get the incorrect time. Using "full names" like (UTC-08:00) Pacific Time (US & Canada) would have the same issue.

A way around that is to specify the time zone names like America/Vancouver (as listed here), or else specify the city, country and/or region name with the appropriate parameters.

I wrote a function to figure it out but it only applies to certain countries (see further down).


What time was it in Toronto last Halloween at 11:11pm Vancouver time?

http://api.timezonedb.com/v2/convert-time-zone?key=94RKE4SAXH67&from=America/Vancouver&to=America/Toronto&time=1509516660

Result: (Default is XML but JSON is also available.)

<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>

Getting the data programmatically:

There are plenty of options and lookup methods you will have to decide upon, but here's one example using a VBA Function:

What will be the time difference between Vancouver & Berlin on Christmas Day?

Input Time: 2018-12-25 00:00:00 = Vancouver Local Unix time 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 Timestamps:

Unix time is defined as "the number of seconds that have elapsed since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970."

You can convert times between Unix and/or UTC or Local time at: epochconverter.com ... the site also has conversion formulas for several programming languages.

For example, the formua to convert Unix time to GMT/UTC in Excel is:

=(A1 / 86400) + 25569

You could also download static files (in SQL or CSV format) here instead of caling the API, and the page also has sample queries. However use caution: it's easier to make mistakes with Daylight Savings (as mentioned above).

I made a dummy account to get the "demo" used in the examples, but you should get your own (free) key for long-term use. (I'm not responsible if it gets locked out from over-use!)


An good alternative Time Zone API is Google Maps Time Zone API. The difference is that you specify Latitude & Longitude. It seems to work just fine without a key You'll need to register for a key.

What will the Time Zone Offset be on June 1st at the White House?

https://maps.googleapis.com/maps/api/timezone/json?location=38.8976,-77.0365&timestamp=1527811200&key={YourKeyHere}

Result:

{
   "dstOffset" : 0,
   "rawOffset" : -18000,
   "status" : "OK",
   "timeZoneId" : "America/Toronto",
   "timeZoneName" : "Eastern Standard Time"
}

The Offset will be -18000 seconds (-5 hours).


Determining when Daylight Savings is in effect

Below is a function I put together so I could "trust" the Daylight Savings (DST) values I was getting from a different API, however (as discussed by others) the rules have no pattern plus are constantly changing country by country, even town by town in some parts of the world, so this only will work in countries where:

  • DST begins on the Second Sunday of March every year
  • DST end on the First Sunday of November every year

The applicable countries are Bahamas, Bermuda, Canada, Cuba, Haiti, St. Pierre & United States. (Source: 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

And a couple examples of how I could use 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

* Note that function IsDST is incomplete: It does not take into account the hours just before/after IsDST takes actually effect at 2am. Specifically when, in spring, the clock jumps forward from the last instant of 01:59 standard time to 03:00 DST and that day has 23 hours, whereas in autumn the clock jumps backward from the last instant of 01:59 DST to 01:00 standard time, repeating that hour, and that day has 25 hours ...but, if someone wants to add that functionality to update the function, feel free! I was having trouble wrapping my head around that last part, and didn't immediately need that level of detail, but I'm sure others would appreciate it!


Finally one more alternative is an API that I use to for polling current/future/historical weather data for various purposes — and also happens to provide Timezone Offset — is DarkSky.

It queries by latitude/longitude and is free (up to 1000 calls/day) and provides "ultra-accurate weather data" (more-so in the USA, where it predicts weather down to the minute and to the square-yard! — but quite accurate I've seen for the unpredictable Canadian West Coast Canada!)

Response is in JSON only, and the very last line is Time Zone Offset versus UTC/GMT time.

DarkSky Sample Call:

https://api.darksky.net/forecast/85b57f827eb89bf903b3a796ef53733c/40.70893,-74.00662

It says it's supposed to rain for the next 60 hours at Stack Overflow's Head Office. ☂

...but I dunno, it looks like a pretty nice day so far! ☀

(flag)

Im afraid anything to do with timezones is never a simple task (ask any web designer and they will say it is a massive challenge)

there are 2 ways to solve your problem

1) The Easy way - Create a central list which all other workbooks are linked to. This can be saved on SharePoint or on a shared drive, then all you have to do is update this one table

2) The hard way - Use a website API to get the latest timezone data. https://www.amdoren.com/ is a good site, you can get a free API key by signing up. The only issue is you then have to parse the Json file from the website. This isn't easy but if you google "vba parse json" you will find some solutions (it generally requires importing some libraries and using other peoples code as a starting point)

Hope you find the right solution, and if you do might be worth sharing it as im sure there will be others with same issue.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!