使用pytz
,我能够获得时区列表,如下所示:
>>> from pytz import country_timezones
>>> print(' '.join(country_timezones('ch')))
Europe/Zurich
>>> print(' '.join(country_timezones('CH')))
Europe/Zurich
假设我从用户处获得国家和城市字段,我该如何确定城市的时区?
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))
给定城市的纬度,经度,可以使用tz_world找到它的时区,这是一个efele.net/tz地图/世界TZ时区的shapefile,例如,通过postgis timezone db或pytzwhere
:
import tzwhere
w = tzwhere()
print w.tzNameAt(1.352083, 103.819836)
# -> Asia/Singapore
也有允许将(纬度,经度)转换为时区的web服务,例如askgeo, geonames,参见从纬度经度查找时区。
正如@dashesy在评论中指出的,geopy
也可以找到时区(从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 namesn "
"(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
这里已经提出了很多可能的解决方案,但它们都有点繁琐。
为了让下一个有这个问题的人更快,我从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 you datetime.datetime(2002, 10, 27, 6, 0, tzinfo=<DstTzInfo 'Europe/Berlin' CET+1:00:00 STD>)
.
这将为您提供一个pytz对象(在示例中为tz
),以便您可以以python方式使用它。
- 使用google API
- 将夏令时计算留给pytz,每个城市只有一个电话,其余时间离线进行
- LRU缓存请求,所以你不应该轻易达到API限制
- 也应该与任何地址或任何谷歌地图理解
这个想法是使用地理编码器之一查找给定城市(或州)的纬度/长坐标,并从地理编码器获得适当的时区。例:
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>)
如果地理编码器没有产生时区,您可以使用timezonefinder将时区属性赋予给定的晚/长坐标。
我认为你需要手动搜索时区数据库为您正在寻找的城市:
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)
(这只是一个快速而肮脏的解决方案,例如,它不会尝试只匹配时区的城市部分—尝试搜索Europe
,它会进行子字符串匹配,不搜索不区分大小写,等等)
没有简单的方法可以做到这一点,这是不幸的。Geonames记录了每个城市的列表及其时区名称。这将是一个不错的选择,但您将不得不解析并围绕此构建自己的数据库,因此您可以随时轻松地从国家/城市对中找到时区。
我最终通过使用requests
和解析JSON的几个Google API调用解决了这个问题。我能够做到没有API密钥,因为我永远不会达到他们的使用限制。
这不是最新的。到目前为止我找到的最好的答案是
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= cods。经度,纬度= coords.latitude)更多细节请点击
@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/%sn' % (city_name, city.country))
Information for London/England
>>> timezone = city.timezone
>>> print('Timezone: %s' % timezone)
Timezone: Europe/London