Skip to content

Commit

Permalink
Added guess_timezone_by_javascript() function
Browse files Browse the repository at this point in the history
Function is used to identify the timezone by the date string, returned
by JavaScript
  • Loading branch information
imankulov committed Feb 8, 2013
1 parent bd206f8 commit 5f618c1
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 0 deletions.
12 changes: 12 additions & 0 deletions timezones/test_timezones.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,17 @@ def test_guess_timezone():
assert tz_utils.guess_timezone_by_ip('127.0.0.1', only_name=True) == None


def test_guess_timezone_by_javascript():
asia_yekaterinburg = tz_utils.get_timezone('Asia/Yekaterinburg')
for i in xrange(2): # to ensure that cache breaks nothing
assert tz_utils.guess_timezone_by_javascript('Tue Feb 01 2005 00:00:00 GMT+0500 (YEKT)') == asia_yekaterinburg
assert tz_utils.guess_timezone_by_javascript('Mon Aug 01 2005 00:00:00 GMT+0600 (YEKST)') == asia_yekaterinburg
assert tz_utils.guess_timezone_by_javascript('Mon Aug 01 2005 00:00:00 GMT+0600 (OOOPS)') == None

assert tz_utils.guess_timezone_by_javascript('Tue Feb 01 2005 00:00:00 GMT+0500 (YEKT)', True) == 'Asia/Yekaterinburg'
assert tz_utils.guess_timezone_by_javascript('Mon Aug 01 2005 00:00:00 GMT+0600 (YEKST)', True) == 'Asia/Yekaterinburg'
assert tz_utils.guess_timezone_by_javascript('Mon Aug 01 2005 00:00:00 GMT+0600 (OOOPS)', True) == None


def test_get_timezonez():
assert len(list(zones.get_timezones(only_us=True))) == 8
66 changes: 66 additions & 0 deletions timezones/tz_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,72 @@ def guess_timezone_by_ip(ip, only_name=False):
return None


# the map tzname -> timezone string (YEKT -> "Asia/Yekaterinburg",
# YEKST -> "Asia/Yekaterinburg" and so on)
_tzname_cache = {}

def guess_timezone_by_javascript(date_string, only_name=False):
"""Given the `date_string` as returned by JavaScript, tries to return the
user browser timezone.
Example usage::
from timezones import tz_utils
assert tz_utils.guess_timezone_by_javascript('Tue Feb 01 2005 00:00:00 GMT+0500 (YEKT)', only_name=True) == 'Asia/Yekaterinburg'
You may get the javascript date representation as::
new Date().toString()
Implementation note: currently we ignore the tz offset component of the
date string object, and rely on the timezone name in parentheses only.
"""

def obj_or_name(obj):
""" helper function returning timezone object or its name only"""
if obj and only_name:
return obj.zone
return obj

if not date_string:
return None

chunks = date_string.split()
datetime_info = ' '.join(chunks[:5]) # "Tue Feb 01 2005 00:00:00"
timezone_info = chunks[5:] # ['GMT+0500', '(YEKT)']

if len(timezone_info) != 2:
return None

try:
dt = datetime.strptime(datetime_info, '%a %b %d %Y %H:%M:%S')
except ValueError: # unable to convert string to datetime object
return None

expected_tzname = timezone_info[1].strip('()')

if expected_tzname in _tzname_cache:
# check in cache first (cache stores srings or None`s)
timezone_name = _tzname_cache[expected_tzname]
if not timezone_name:
return None
timezone_obj = pytz.timezone(timezone_name)
return obj_or_name(timezone_obj)

for timezone in pytz.all_timezones:
timezone_obj = pytz.timezone(timezone)
tzname = timezone_obj.tzname(dt)
_tzname_cache[tzname] = timezone
if tzname == expected_tzname:
break
else:
_tzname_cache[expected_tzname] = None
return None

return obj_or_name(timezone_obj)



def get_timezone(tzname):
"""Get a timezone instance by name or return `None`.
Expand Down

0 comments on commit 5f618c1

Please sign in to comment.