Get Timezone from City in Python/Django

后端 未结 6 1488
独厮守ぢ
独厮守ぢ 2020-11-27 06:00

Using pytz, I am able to get a list of timezones like so:

>>> from pytz import country_timezones
>>> print(\' \'.join(country_         


        
相关标签:
6条回答
  • 2020-11-27 06:23

    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
    0 讨论(0)
  • 2020-11-27 06:27

    @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
    
    0 讨论(0)
  • 2020-11-27 06:37

    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
    
    0 讨论(0)
  • 2020-11-27 06:38

    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.

    0 讨论(0)
  • 2020-11-27 06:44

    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.)

    0 讨论(0)
  • 2020-11-27 06:45

    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.

    0 讨论(0)
提交回复
热议问题