从Python / Django获取城市的时区

使用pytz ,我可以得到如下所示的时区列表:

 >>> from pytz import country_timezones >>> print(' '.join(country_timezones('ch'))) Europe/Zurich >>> print(' '.join(country_timezones('CH'))) Europe/Zurich 

鉴于我从用户那里得到了国家和城市两个字段,我怎样才能确定城市的时区?

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

您可能需要geopy ,如geopy ,可以使用各种networking服务将位置(例如城市名称)转换为其坐标(经度,纬度):

 from geopy import geocoders # pip install geopy g = geocoders.GoogleV3() place, (lat, lng) = g.geocode('Singapore') # -> (u'Singapore', (1.352083, 103.819836)) 

鉴于城市的经纬度,可以使用tz_world,efele.net/tz地图/世界TZ时区的shapefile来查找其时区,例如通过postgis时区db或pytzwhere

 import tzwhere w = tzwhere() print w.tzNameAt(1.352083, 103.819836) # -> Asia/Singapore 

也有networking服务,允许将(纬度,经度)转换为时区,例如askgeo , geonames ,请参阅从纬度经度查找时区 。

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

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

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

产量

 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 

这样做并不是一件容易的事,这是不幸的。 Geonameslogging每个城市的名单,以及它的时区名称。 这将是一个神select,但你将不得不parsing和build立自己的数据库,所以你可以随时轻松find一个国家/城市对的时区。

我想你将需要手动search你想要的城市的时区数据库:

 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) 

(这只是一个快捷的解决scheme,例如,它不会尝试仅匹配时区的城市部分 – 尝试searchEurope ,匹配子string,不search不区分大小写的内容等)

我最终用一些Google API调用解决了这个问题,并通过JSONparsing。 我能够做到这一点没有API密钥,因为我永远不会达到他们的使用限制。

https://gist.github.com/willcharlton/b055885e249a902402fc

我希望这有帮助。

这里提出了很多可能的解决scheme,而且它们都有点繁琐。

为了让这个问题的下一个人更快捷,我从Will Charlton那里拿了一个,做了一个快速的Python库: https : //pypi.python.org/pypi/whenareyou

 from whenareyou import whenareyou tz = whenareyou('Hamburg') tz.localize(datetime(2002, 10, 27, 6, 0, 0)) 

Get datetime.datetime(2002, 10, 27, 6, 0, tzinfo=<DstTzInfo 'Europe/Berlin' CET+1:00:00 STD>)

这会得到一个pytz对象(在这个例子中是tz ),所以你可以用pythonicly。

  • 它使用谷歌API
  • 夏时制计算pytz,每个城市只有一个电话,rest发生在离线
  • LRUcaching请求,所以你不应该很容易地达到API限制
  • 还应该使用任何地址或任何谷歌地图了解

@ robertklep的方法可能有效。

但是,这里有另一种使用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