Created
December 6, 2016 19:33
-
-
Save mikofski/2ce34b7a8c09dce135b515fcfd426bc5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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