Skip to content

Instantly share code, notes, and snippets.

@mikofski
Created December 6, 2016 19:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikofski/2ce34b7a8c09dce135b515fcfd426bc5 to your computer and use it in GitHub Desktop.
Save mikofski/2ce34b7a8c09dce135b515fcfd426bc5 to your computer and use it in GitHub Desktop.
from tzwhere import tzwhere
from datetime import datetime
import pytz
# timezone lookup, force nearest tz for coords outside of polygons
WHERETZ = tzwhere.tzwhere(shapely=True, forceTZ=True)
# daylight savings time (DST) in northern hemisphere starts in March and ends
# in November and the opposite in southern hemisphere
JAN1 = datetime(2016, 1, 1) # date with standard time in northern hemisphere
JUN1 = datetime(2016, 6, 1) # date with standard time in southern hemisphere
# notes and links on Python datetime tzinfo dst:
# http://stackoverflow.com/questions/17173298/is-a-specific-timezone-using-dst-right-now
# http://stackoverflow.com/questions/19774709/use-python-to-find-out-if-a-timezone-currently-in-daylight-savings-time
# methods for determining DST vs. STD
# tz.localize(JAN1).timetuple().tm_isdst -> boolean, True if DST, False if STD
# tz.localize(JAN1).dst() -> timedelta, 0 if STD
# tz.dst(JAN1) -> timedelta, 0 if STD
def tz_latlon(lat, lon):
"""
Timezone from latitude and longitude.
:param lat: latitude [deg]
:type lat: float
:param lon: longitude [deg]
:type lon: float
:return: timezone
:rtype: float
"""
# get name of time zone using tzwhere, force to nearest tz
tz_name = WHERETZ.tzNameAt(lat, lon, forceTZ=True)
# check if coordinates are over international waters
if not tz_name or tz_name in ('uninhabited', 'unknown'):
# coordinates over international waters only depend on longitude
return lon // 15.0
else:
tz_info = pytz.timezone(tz_name) # get tzinfo
# get the daylight savings time timedelta
tz_date = JAN1 # standard time in northern hemisphere
if tz_info.dst(tz_date):
# if DST timedelta is not zero, then it must be southern hemisphere
tz_date = JUN1 # a standard time in southern hemisphere
tz_str = tz_info.localize(tz_date).strftime('%z') # output timezone from ISO
# convert ISO timezone string to float, including partial timezones
return float(tz_str[:3]) + float(tz_str[3:]) / 60.0, tz_info
if __name__ == "__main__":
# test tz_latlon at San Francisco (GMT+8.0)
gmt, tz_info = tz_latlon(37.7, -122.4)
assert gmt == -8.0
assert tz_info.zone == 'America/Los_Angeles'
assert tz_info.utcoffset(JAN1).total_seconds()/3600.0 == -8.0
assert tz_info.utcoffset(JUN1).total_seconds()/3600.0 == -7.0
# New_Delhi, India (GMT-5.5)
gmt, tz_info = tz_latlon(28.6, 77.1)
assert gmt == 5.5
assert tz_info.zone == 'Asia/Kolkata'
assert tz_info.utcoffset(JAN1).total_seconds()/3600.0 == 5.5
assert tz_info.utcoffset(JUN1).total_seconds()/3600.0 == 5.5
# also works with integers (EG: Santa Cruz, CA)
gmt, tz_info = tz_latlon(37, -122)
assert gmt == -8.0
assert tz_info.zone == 'America/Los_Angeles'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment