33👍
pytz
is a wrapper around IANA Time Zone Database (Olson database). It does not contain data to map an arbitrary city in the world to the timezone it is in.
You might need a geocoder such as geopy
that can translate a place (e.g., a city name) to its coordinates (latitude, longitude) using various web-services:
from geopy import geocoders # pip install geopy
g = geocoders.GoogleV3()
place, (lat, lng) = g.geocode('Singapore')
# -> (u'Singapore', (1.352083, 103.819836))
Given city’s latitude, longitude, it is possible to find its timezone using tz_world, an efele.net/tz map / a shapefile of the TZ timezones of the world e.g., via postgis timezone db or pytzwhere
:
import tzwhere
w = tzwhere()
print w.tzNameAt(1.352083, 103.819836)
# -> Asia/Singapore
There are also web-services that allow to convert (latitude, longitude) into a timezone e.g., askgeo, geonames, see Timezone lookup from latitude longitude.
As @dashesy pointed out in the comment, geopy
also can find timezone (since 1.2):
timezone = g.timezone((lat, lng)) # return pytz timezone object
# -> <DstTzInfo 'Asia/Singapore' LMT+6:55:00 STD>
GeoNames also provides offline data that allows to get city’s timezone directly from its name e.g.:
#!/usr/bin/env python
import os
from collections import defaultdict
from datetime import datetime
from urllib import urlretrieve
from urlparse import urljoin
from zipfile import ZipFile
import pytz # pip install pytz
geonames_url = 'http://download.geonames.org/export/dump/'
basename = 'cities15000' # all cities with a population > 15000 or capitals
filename = basename + '.zip'
# get file
if not os.path.exists(filename):
urlretrieve(urljoin(geonames_url, filename), filename)
# parse it
city2tz = defaultdict(set)
with ZipFile(filename) as zf, zf.open(basename + '.txt') as file:
for line in file:
fields = line.split(b'\t')
if fields: # geoname table http://download.geonames.org/export/dump/
name, asciiname, alternatenames = fields[1:4]
timezone = fields[-2].decode('utf-8').strip()
if timezone:
for city in [name, asciiname] + alternatenames.split(b','):
city = city.decode('utf-8').strip()
if city:
city2tz[city].add(timezone)
print("Number of available city names (with aliases): %d" % len(city2tz))
#
n = sum((len(timezones) > 1) for city, timezones in city2tz.iteritems())
print("")
print("Find number of ambigious city names\n "
"(that have more than one associated timezone): %d" % n)
#
fmt = '%Y-%m-%d %H:%M:%S %Z%z'
city = "Zurich"
for tzname in city2tz[city]:
now = datetime.now(pytz.timezone(tzname))
print("")
print("%s is in %s timezone" % (city, tzname))
print("Current time in %s is %s" % (city, now.strftime(fmt)))
Output
Number of available city names (with aliases): 112682
Find number of ambigious city names
(that have more than one associated timezone): 2318
Zurich is in Europe/Zurich timezone
Current time in Zurich is 2013-05-13 11:36:33 CEST+0200
3👍
there have been a lot of possible solutions proposed here and they’re all a bit tedious to set up.
To make things quicker for the next person with this problem, I took the one from Will Charlton and made a quick python library out of it: https://pypi.python.org/pypi/whenareyou
from whenareyou import whenareyou
tz = whenareyou('Hamburg')
tz.localize(datetime(2002, 10, 27, 6, 0, 0))
Gets you datetime.datetime(2002, 10, 27, 6, 0, tzinfo=<DstTzInfo 'Europe/Berlin' CET+1:00:00 STD>)
.
This gets you a pytz object (tz
in the example) so you can use it pythonicly.
- It uses the google API
- Leaves daylight savings calculation to pytz, only one call per city, rest happens offline
- LRU caches the requests so you shouldn’t hit the API limit easily
- Should also work with any address or anything google maps understands
- [Django]-ImportError: Failed to import test module:
- [Django]-Django: list all reverse relations of a model
- [Django]-Django: Open uploaded file while still in memory; In the Form Clean method?
3👍
The idea is to find lat/long coordinates for given city (or state) with one of geopy‘s geocoders, and get the appropriate time zone from the geocoder. Ex:
from datetime import datetime, timezone
from geopy import geocoders
# get the location by using one of the geocoders.
# GeoNames has a free option.
gn = geopy.geocoders.GeoNames(username='your-account-name')
loc = gn.geocode("California, USA")
# some geocoders can obtain the time zone directly.
# note: the geopy.timezone object contains a pytz timezone.
loc_tz = gn.reverse_timezone(loc.point)
# EXAMPLE: localize a datetime object
dt_UTC = datetime(2020, 11, 27, 12, 0, 0, tzinfo=timezone.utc)
dt_tz = dt_UTC.astimezone(loc_tz.pytz_timezone)
print(dt_tz, repr(dt_tz))
# 2020-11-27 04:00:00-08:00
# datetime.datetime(2020, 11, 27, 4, 0, tzinfo=<DstTzInfo 'America/Los_Angeles' PST-1 day, 16:00:00 STD>)
If the geocoder doesn’t yield a time zone, you can use timezonefinder to attribute a time zone to given lat/long coordinates.
- [Django]-How to get getting base_url in django template
- [Django]-Problems extend change_form.html in django admin
- [Django]-Django – How to pass several arguments to the url template tag
2👍
I think you’re going to need to manually search the timezone database for the city you’re looking for:
from pytz import country_timezones, timezone
def find_city(query):
for country, cities in country_timezones.items():
for city in cities:
if query in city:
yield timezone(city)
for tz in find_city('Zurich'):
print(tz)
(that’s just a quick-and-dirty solution, it for instance doesn’t try to match only the city-part of a timezone – try searching for Europe
, it does substring matches, doesn’t search case-insensitive, etc.)
- [Django]-How to get username from Django Rest Framework JWT token
- [Django]-Django – Annotate multiple fields from a Subquery
- [Django]-Function decorators with parameters on a class based view in Django
1👍
There is not trivial way of doing this, which is unfortunate.
Geonames records a list of every city, along with its time zone name.
This would be a god pick, but you will have to parse and build your own database around this, so you can easily find at any moment the time zone from a country/city pair.
- [Django]-Passing variable urlname to url tag in django template
- [Django]-Naming convention for Django URL, templates, models and views
- [Django]-In django, how do I sort a model on a field and then get the last item?
1👍
I ended up solving this with a couple Google API calls using requests
and parsing through the JSON. I was able to do it without API keys because I’m never going to hit their usage limits.
https://gist.github.com/willcharlton/b055885e249a902402fc
I hope this helps.
- [Django]-How to server HTTP/2 Protocol with django
- [Django]-Django apps aren't loaded yet when using asgi
- [Django]-How can I access environment variables directly in a Django template?
0👍
this isnt upt to date. The best answer I found so far is
from geopy.geocoders import Nominatim
from timezonefinder import TimezoneFinder
geolocator = Nominatim(user_agent="anyName")
tf = TimezoneFinder()
coords = geolocator.gecode("Dallas, Texas")
tf = TimezoneFinder()
timezone = tf.timezone_at(lng=coords.longitude, lat=coords.latitude)
more details here
- [Django]-Django {% if forloop.first %} question
- [Django]-How can I serialize a queryset from an unrelated model as a nested serializer?
- [Django]-How can I handle Exceptions raised by dango-social-auth?
-1👍
@robertklep’s approach probably works.
But here’s another possible approach using astral
– https://pypi.python.org/pypi/astral/0.5
>>> import datetime
>>> from astral import Astral
>>> city_name = 'London' # assuming we retrieve this from user input
>>> a = Astral()
>>> a.solar_depression = 'civil'
>>> city = a[city_name] # creates the city object given the city name above
>>> print('Information for %s/%s\n' % (city_name, city.country))
Information for London/England
>>> timezone = city.timezone
>>> print('Timezone: %s' % timezone)
Timezone: Europe/London
- [Django]-Using django-admin on windows powershell
- [Django]-Remove pk field from django serialized objects
- [Django]-Warning: Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'