在Python/Django中从城市获取时区

hgb9j2n6  于 2023-08-08  发布在  Go
关注(0)|答案(8)|浏览(104)

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

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

字符串
既然我从用户那里得到了Country和City字段,我该如何确定城市的时区呢?

esyap4oy

esyap4oy1#

pytz是IANA时区数据库(Olson数据库)的 Package 器。它不包含将世界上任意一个城市Map到它所在时区的数据。
您可能需要一个地理编码器,如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, an efele.net/tz map / a shapefile of the TZ timezones of the world找到其时区,例如,通过postgis timezone dbpytzwhere

import tzwhere

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


也有允许将(纬度,经度)转换成时区的Web服务,例如askgeo,地理名,参见Timezone lookup from latitude longitude
正如@dashesy在评论中指出的,geopy也可以找到时区(从1.2开始):

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


GeoNames also provides offline data,允许直接从城市名称获取城市时区,例如:

#!/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

sg3maiej

sg3maiej2#

这里已经提出了许多可能的解决方案,它们都有点繁琐。
为了让下一个遇到这个问题的人更快地处理这个问题,我从Will查尔顿那里取了一个快速的Python库:https://pypi.python.org/pypi/whenareyou

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

字符串
得到datetime.datetime(2002, 10, 27, 6, 0, tzinfo=<DstTzInfo 'Europe/Berlin' CET+1:00:00 STD>)
这就得到了一个pytz对象(示例中的tz),这样你就可以用pythonically来使用它了。

  • 它使用Google API
  • 把夏令时的计算留给pytz,每个城市只有一个电话,其余的发生离线
  • LRU缓存请求,因此您不应该轻易达到API限制
  • 也应该与任何地址或任何谷歌Map理解
km0tfn4u

km0tfn4u3#

这个想法是用geopy的一个地理编码器找到给定城市(或州)的纬度/经度坐标,并从地理编码器中获得适当的时区。例如:

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将时区归属于给定的纬度/经度坐标。

ufj5ltwl

ufj5ltwl4#

我想你需要手动搜索时区数据库中的城市:

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它只是一个快速和肮脏的解决方案,例如它不会尝试只匹配时区的城市部分-尝试搜索Europe,它会匹配子字符串,不搜索大小写不敏感等。

iovurdzv

iovurdzv5#

没有一种微不足道的方法来做到这一点,这是不幸的。Geonames记录了每个城市的列表,沿着它的时区名称。这将是一个上帝的选择,但你将不得不围绕它解析和建立自己的数据库,所以你可以很容易地在任何时候从国家/城市对找到时区。

goqiplq2

goqiplq26#

最后,我使用requests和通过JSON进行解析的Google API调用解决了这个问题。我能够在没有API密钥的情况下做到这一点,因为我永远不会达到它们的使用限制。
https://gist.github.com/willcharlton/b055885e249a902402fc
希望这能帮上忙。

1tu0hz3e

1tu0hz3e7#

这个不是最新的。目前为止我找到的最好答案是

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=坐标.经度,lat=坐标.纬度)更多详细信息here

h22fl7wq

h22fl7wq8#

@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

字符串

相关问题