我有一个遗留应用程序,我将需要补充一些数据。当前,我们有一个数据库表,用于存储美国(及其地区)邮政编码,GMT偏移量以及一个标志,用于显示该邮政编码是否使用夏时制。这是从某个免费提供商处下载的,我现在找不到源。
现在,我需要用America/New York每个邮政编码的完整奥尔森名称(例如)来补充此表,因为这似乎是将存储在数据库中的给定日期/时间(对于该购买者而言本地的)转换为UTC aware datetime对象的唯一好方法。
America/New York
UTC aware datetime
看一下桌子:
zip state city lat lon gmt dst 00605 PR AGUADILLA 18.4372 -67.1593 -4 f 02830 RI HARRISVILLE 41.9782 -71.7679 -5 t 99503 AK ANCHORAGE 61.1895 -149.874 -9 t
在另一个相关的表格中Purchases,我有一postres timestamp without tz列,当前包含类似的内容2014-05-27T15:54:26,它表示在该邮政编码上本地购买商品的时间。(忽略将这些本地化的时间戳保存到数据库时剥离时区信息的愚蠢性)
Purchases
postres
timestamp without tz
2014-05-27T15:54:26
最大的问题是:
如何UTC time从该timestamp字符串为zipcode表格中的每个邮政编码创建规范化?这将假定时间戳记是在zipcode表中每个示例行的本地写入到DB的。
UTC time
timestamp
zipcode
例如,手动查找示例表中每个项目的Olson时区名称,我得出以下结果:
>>> timestring = '2014-05-27T15:54:26' >>> dt_naive = datetime.strptime(timestring, '%Y-%m-%dT%H:%M:%S') >>> # First example - Puerto Rico (no DST since 1945) >>> print pytz.utc.normalize(pytz.timezone('America/Puerto_Rico').localize(dt_naive)) 2014-05-27 19:54:26+00:00 # Second example - Road Island (At that timestamp, UTC Offset was same as PR because of DST) >>> print pytz.utc.normalize(pytz.timezone('US/Eastern').localize(dt_naive)) >>> 2014-05-27 19:54:26+00:00 # Third Example - Anchorage, AK (AKDT at timestamp) >>> print pytz.utc.normalize(pytz.timezone('America/Anchorage').localize(dt_naive)) 2014-05-27 23:54:26+00:00
我看过几种出售邮政编码数据库的商业产品,这些数据库可以给我一个邮政编码->时区查询。但是,他们似乎只给我给定时区的“ EST”。因此,我认为我可以将美国时区(包括地区)的可能时区列表映射到每个时区的奥尔森名称。可能看起来像这样:
zipcode_olson_lookup = { ('PR', 'f', 'AST'): 'America/Puerto_Rico', ('AK', 'f', 'AKDT',): 'America/Anchorage', ('AK', 't', 'AKT',): 'America/Anchorage', ... }
任何建议都非常欢迎!
UTC本身的偏移量可能是不明确的(它可能对应于在某个时间段内可能具有不同规则的多个时区):
#!/usr/bin/env python from datetime import datetime, timedelta import pytz # $ pip install pytz input_utc_offset = timedelta(hours=-4) timezone_ids = set() now = datetime.now(pytz.utc) #XXX: use date that corresponds to input_utc_offset instead! for tz in map(pytz.timezone, pytz.all_timezones_set): dt = now.astimezone(tz) tzinfos = getattr(tz, '_tzinfos', [(dt.tzname(), dt.dst(), dt.utcoffset())]) if any(utc_offset == input_utc_offset for utc_offset, _, _ in tzinfos): # match timezones that have/had/will have the same utc offset timezone_ids.add(tz.zone) print(timezone_ids)
{'America/Anguilla', 'America/Antigua', 'America/Argentina/Buenos_Aires', ..., 'Cuba', 'EST5EDT', 'Jamaica', 'US/East-Indiana', 'US/Eastern', 'US/Michigan'}
您甚至不能使用限制列表,pytz.country_timezones['us']因为它会排除您的示例之一:'America/Puerto_Rico'。
pytz.country_timezones['us']
'America/Puerto_Rico'
如果您知道坐标(纬度,经度);您可以从shape文件中获取时区ID :您可以使用本地数据库或网络服务:
#!/usr/bin/env python from geopy import geocoders # pip install "geopy[timezone]" g = geocoders.GoogleV3() for coords in [(18.4372, -67.159), (41.9782, -71.7679), (61.1895, -149.874)]: print(g.timezone(coords).zone)
America/Puerto_Rico America/New_York America/Anchorage
注意:某些当地时间可能是模棱两可的,例如,在DST转换结束时时间回落。在这种情况下,您可以传递is_dst=None给.localize()方法来引发异常。
is_dst=None
.localize()
tz数据库的不同版本在某些日期的某些时区可能具有不同的utc偏移,即,仅存储UTC时间和时区ID(使用哪种版本取决于您的应用程序)是不够的。