在Python/Django中从City获取时区

sup*_*er9 15 python django

使用pytz,我能够获得如下所示的时区列表:

>>> from pytz import country_timezones
>>> print(' '.join(country_timezones('ch')))
Europe/Zurich
>>> print(' '.join(country_timezones('CH')))
Europe/Zurich
Run Code Online (Sandbox Code Playgroud)

鉴于我从用户那里获得了Country和City字段,我该如何确定城市的时区?

jfs*_*jfs 25

pytz是IANA时区数据库(Olson数据库)的包装器.它不包含将世界上任意城市映射到其所在时区的数据.

您可能需要一个地理编码器,例如geopy可以使用各种Web服务将地点(例如,城市名称)转换为其坐标(纬度,经度):

from geopy import geocoders # pip install geopy

g = geocoders.GoogleV3()
place, (lat, lng) = g.geocode('Singapore')
# -> (u'Singapore', (1.352083, 103.819836))
Run Code Online (Sandbox Code Playgroud)

给定城市的纬度,经度,可以使用tz_world,efele.net/tz地图/世界TZ时区的形状文件找到它的时区,例如,通过postgis timezone dbpytzwhere:

import tzwhere

w = tzwhere()
print w.tzNameAt(1.352083, 103.819836)
# -> Asia/Singapore
Run Code Online (Sandbox Code Playgroud)

还有一些网络服务允许将(纬度,经度)转换为时区,例如,askgeo,geonames,从纬度经度查看时区查找.

正如@dashesy在评论中指出的那样,geopy也可以找到时区(从1.2开始):

timezone = g.timezone((lat, lng)) # return pytz timezone object
# -> <DstTzInfo 'Asia/Singapore' LMT+6:55:00 STD>
Run Code Online (Sandbox Code Playgroud)

GeoNames还提供离线数据,允许直接从其名称获取城市的时区,例如:

#!/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)))
Run Code Online (Sandbox Code Playgroud)

产量

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
Run Code Online (Sandbox Code Playgroud)

  • 我想现在已经过去了一段时间,现在看来`geopy`本身可以找到时区:`g.timezone(g.geocode('Singapore').point)` (6认同)

rob*_*lep 2

我认为您需要手动搜索您要查找的城市的时区数据库:\n

\n\n
from pytz import country_timezones, timezone\n\ndef find_city(query):\n    for country, cities in country_timezones.items():\n        for city in cities:\n            if query in city:\n                yield timezone(city)\n\nfor tz in find_city('Zurich'):\n    print(tz)\n
Run Code Online (Sandbox Code Playgroud)\n\n

(这只是一个快速而肮脏的解决方案,例如,它不会尝试仅匹配时区 \xe2\x80\x93 的城市部分,尝试搜索Europe,它会进行子字符串匹配,不会搜索不区分大小写的, ETC。)

\n

  • 它不适用于大多数城市。城市数量远大于时区数量。 (2认同)