Search code examples
pythondatetimegoogle-app-enginetimezoneutc

Convert naive datetime with known location to UTC datetime


Users of my app enter planned events providing

  • date
  • start time
  • end time
  • geographic location (on a map)

I'd like to convert the dates and times to UTC. My app is on GAE (Python), so tools like timezonefinder or pytzwhere are not working (modules have dependencies not supported on the GAE runtime).

Using an online API would be a solution. So far I checked the Google Timezone API. You provide it a geographic location and it will return the timezone information. To deal with DST however, you must provide it with a timestamp as well. Oddly enough, you must provide the UTC timestamp as input, and that's exactly what I want as output!

I can give it a timestamp based on my local datetime information (so without timezone correction) and it will return me the rawOffset and dstOffset that I need to convert my local datetime to UTC, but it may be incorrect for datetimes during some period around the DST transit ([-12h, +12 hours], I reckon, depending on the actual offset), because I didn't provide the correct UTC timestamp.

Is there an obvious (online) method for converting local datetime to UTC datetime based on geographic location?

One way to gain some accuracy that I thought of is to apply the rawOffset and dstOffset that I receive from the API, generate the UTC timestamp again and call the API once more with that timestamp. The period around DST transit where my results could be incorrect should now be limited to +/-1 hour. But that's over the top to my impression, also considering the quota on the API.


Solution

  • In order to convert local datetime info to UTC based on geographic location, you could just pass an arbitrary timestamp to the Google Time Zone API with the primary purpose of retrieving the timeZoneId for the location.

    Example Request:

    https://maps.googleapis.com/maps/api/timezone/json?location=39.6034810,-119.6822510&timestamp=0&key=YOUR_API_KEY
    

    Example Response:

    {
       "dstOffset" : 0,
       "rawOffset" : -28800,
       "status" : "OK",
       "timeZoneId" : "America/Los_Angeles",
       "timeZoneName" : "Pacific Standard Time"
    }
    

    Then you could use the timeZoneId and user entered date and time info along with pytz to create a python datetime object in the local time and also get the UTC timestamp I think you are looking for. This approach will handle daylight savings based on the user entered date. For example:

    from datetime import datetime
    from pytz import timezone, utc
    
    pacific = timezone('America/Los_Angeles')
    
    pdt = pacific.localize(datetime(2018, 5, 1, 8, 0, 0))
    pst = pacific.localize(datetime(2018, 12, 1, 8, 0, 0))
    pdt_utc = pdt.astimezone(utc)
    pst_utc = pst.astimezone(utc)
    
    # Pacific Daylight Time
    print(pdt)
    # 2018-05-01 08:00:00-07:00
    
    # Pacific Standard Time
    print(pst)
    # 2018-12-01 08:00:00-08:00
    
    # UTC
    print(pdt_utc)
    # 2018-05-01 15:00:00+00:00
    print(pst_utc)
    # 2018-12-01 16:00:00+00:00
    

    Important: I haven't tested this with all the possible return values from the API for timeZoneId to ensure that what is returned from the API will be correctly interpreted by pytz (it works with the example time zone "America/Los_Angeles" but you would need to test to be sure it was a robust solution for the geographies you are dealing with).