在 Python 中使用时区缩写名称解析日期/时间字符串?
Posted
技术标签:
【中文标题】在 Python 中使用时区缩写名称解析日期/时间字符串?【英文标题】:Parsing date/time string with timezone abbreviated name in Python? 【发布时间】:2010-12-14 18:48:12 【问题描述】:我正在尝试在 Python 中解析像 "Sat, 11/01/09 8:00PM EST"
这样的时间戳字符串,但我无法找到可以处理缩写时区的解决方案。
我正在使用dateutil
的parse()
函数,但它不解析时区。有没有简单的方法可以做到这一点?
【问题讨论】:
python bug tracker 出现问题:bugs.python.org/issue22377 【参考方案1】:dateutil
的parser.parse()
接受tzinfos
类型的字典作为关键字参数'EST': -5*3600
(即,以秒为单位将区域名称与GMT 偏移量匹配)。所以假设我们有这个,我们可以这样做:
>>> import dateutil.parser as dp
>>> s = 'Sat, 11/01/09 8:00PM'
>>> for tz_code in ('PST','PDT','MST','MDT','CST','CDT','EST','EDT'):
>>> dt = s+' '+tz_code
>>> print dt, '=', dp.parse(dt, tzinfos=tzd)
Sat, 11/01/09 8:00PM PST = 2009-11-01 20:00:00-08:00
Sat, 11/01/09 8:00PM PDT = 2009-11-01 20:00:00-07:00
Sat, 11/01/09 8:00PM MST = 2009-11-01 20:00:00-07:00
Sat, 11/01/09 8:00PM MDT = 2009-11-01 20:00:00-06:00
Sat, 11/01/09 8:00PM CST = 2009-11-01 20:00:00-06:00
Sat, 11/01/09 8:00PM CDT = 2009-11-01 20:00:00-05:00
Sat, 11/01/09 8:00PM EST = 2009-11-01 20:00:00-05:00
Sat, 11/01/09 8:00PM EDT = 2009-11-01 20:00:00-04:00
关于tzinfos
的内容,这是我的填充方式:
tz_str = '''-12 Y
-11 X NUT SST
-10 W CKT HAST HST TAHT TKT
-9 V AKST GAMT GIT HADT HNY
-8 U AKDT CIST HAY HNP PST PT
-7 T HAP HNR MST PDT
-6 S CST EAST GALT HAR HNC MDT
-5 R CDT COT EASST ECT EST ET HAC HNE PET
-4 Q AST BOT CLT COST EDT FKT GYT HAE HNA PYT
-3 P ADT ART BRT CLST FKST GFT HAA PMST PYST SRT UYT WGT
-2 O BRST FNT PMDT UYST WGST
-1 N AZOT CVT EGT
0 Z EGST GMT UTC WET WT
1 A CET DFT WAT WEDT WEST
2 B CAT CEDT CEST EET SAST WAST
3 C EAT EEDT EEST IDT MSK
4 D AMT AZT GET GST KUYT MSD MUT RET SAMT SCT
5 E AMST AQTT AZST HMT MAWT MVT PKT TFT TJT TMT UZT YEKT
6 F ALMT BIOT BTT IOT KGT NOVT OMST YEKST
7 G CXT DAVT HOVT ICT KRAT NOVST OMSST THA WIB
8 H ACT AWST BDT BNT CAST HKT IRKT KRAST MYT PHT SGT ULAT WITA WST
9 I AWDT IRKST JST KST PWT TLT WDT WIT YAKT
10 K AEST ChST PGT VLAT YAKST YAPT
11 L AEDT LHDT MAGT NCT PONT SBT VLAST VUT
12 M ANAST ANAT FJT GILT MAGST MHT NZST PETST PETT TVT WFT
13 FJST NZDT
11.5 NFT
10.5 ACDT LHST
9.5 ACST
6.5 CCT MMT
5.75 NPT
5.5 SLT
4.5 AFT IRDT
3.5 IRST
-2.5 HAT NDT
-3.5 HNT NST NT
-4.5 HLV VET
-9.5 MART MIT'''
tzd =
for tz_descr in map(str.split, tz_str.split('\n')):
tz_offset = int(float(tz_descr[0]) * 3600)
for tz_code in tz_descr[1:]:
tzd[tz_code] = tz_offset
ps。每个@Hank Gay 时区命名没有明确定义。为了形成我的桌子,我使用了 http://www.timeanddate.com/library/abbreviations/timezones/ 和 http://en.wikipedia.org/wiki/List_of_time_zone_abbreviations 。我查看了每个冲突,并解决了晦涩和流行名称与流行名称(更常用的名称)之间的冲突。有一个 - IST - 没有那么明确(它可能意味着 印度标准时间、伊朗标准时间、爱尔兰标准时间时间 或以色列标准时间),所以我将其排除在表之外 - 您可能需要根据您的位置选择要添加的内容。哦 - 我用他们荒谬的“看看我,我是第一个庆祝新年”的 GMT+13 和 GMT+14 时区忽略了基里巴斯***。
【讨论】:
我无法让ChST 工作。小写 h 似乎会引起问题。我不得不在时区列表中使用大写 CHST 并执行dp.parse(dt, tzinfos=tzd)
字典不正确,例如,2012/12 的 MSK 有 4 小时的偏移量,但往年只有 3 小时
注意:MSK
将在 2014 年 10 月 26 日再次距 UTC 3 小时,即,鉴于'MSK'
,如果您不知道日期,则无法返回正确的 UTC 偏移量。 'EST'
is worse, it may correspond to several UTC offsets at the same time
这就是我要找的。span>
IST 更普遍地用作印度标准时间 (UTC +5:30)【参考方案2】:
这可能行不通,因为这些缩写不是唯一的。有关详细信息,请参阅this page。如果您使用一组已知的输入,您可能最终只需要自己手动处理它。
【讨论】:
如果我们将其限制在美国的时区会变得更容易吗?在该事件中是否有一组“标准”缩写? 不要忘记“美国时区”包括 AKST、AKDT、HAST 和 HADT。如果您只是指大陆 48 个州,那么您只有 8 个 3 个字母的时区需要处理(4 个时区、标准时间和夏令时)。 显然一些地方使用 HST 和 HDT 作为 HAST 和 HADT 的等价物 =\ 到目前为止,最简单的方法(尽管通常不是最实用的)是调整提供数据的任何程序,使其全部以 UTC 格式发送,或者失败,使用 UTC 的偏移量,或者失败来自 zoneinfo 数据库的完整有效时区。 @HankGay 当然这并不总是在开发者的控制之下。【参考方案3】:你可以试试 pytz 模块:http://pytz.sourceforge.net/
pytz 将 Olson tz 数据库引入 Python。该库允许准确 和跨平台时区 使用 Python 2.3 或 更高。也解决了问题 白天结束时的模棱两可的时间 节省,您可以阅读更多信息 在 Python 库参考中 (datetime.tzinfo)。
几乎所有的奥尔森时区都是 支持。
【讨论】:
我很好奇,如何用上述 pytz 解析“Sat, 11/01/09/09 8:00PM EST”? 老实说,这是无法解决的,因为缩写不是一对一的。好消息是 pytz 已经提供了映射(一对多),程序员可以选择所需的映射。 @NasBanov:'EST' 不明确,但you could use pytz to enumerate all possible interpretations。【参考方案4】:dateutil 中的 parse() 函数无法处理时区。我一直在使用的是 %Z 格式化程序和 time.strptime() 函数。我不知道它如何处理时区的歧义,但它似乎可以区分 CDT 和 CST,这正是我所需要的。
背景:我将备份图像存储在名称为使用当地时间的时间戳的目录中,因为我家里没有 GMT 时钟。所以我使用 time.strptime(d, r"%Y-%m-%dT%H:%M:%S_%Z") 将目录名称解析回实际时间进行年龄分析。
【讨论】:
据我了解,strptime 通过仅接受当前时区设置中给出的时间来处理歧义。【参考方案5】:我使用pytz
生成了一个TZINFOS
映射:
from datetime import datetime as dt
import pytz
from dateutil.tz import gettz
from pytz import utc
from dateutil import parser
def gen_tzinfos():
for zone in pytz.common_timezones:
try:
tzdate = pytz.timezone(zone).localize(dt.utcnow(), is_dst=None)
except pytz.NonExistentTimeError:
pass
else:
tzinfo = gettz(zone)
if tzinfo:
yield tzdate.tzname(), tzinfo
TZINFOS
用法
>>> TZINFOS = dict(gen_tzinfos())
>>> TZINFOS
'+02': tzfile('/usr/share/zoneinfo/Antarctica/Troll'),
'+03': tzfile('/usr/share/zoneinfo/Europe/Volgograd'),
'+04': tzfile('Europe/Ulyanovsk'),
'+05': tzfile('/usr/share/zoneinfo/Indian/Kerguelen'),
...
'WGST': tzfile('/usr/share/zoneinfo/America/Godthab'),
'WIB': tzfile('/usr/share/zoneinfo/Asia/Pontianak'),
'WIT': tzfile('/usr/share/zoneinfo/Asia/Jayapura'),
'WITA': tzfile('/usr/share/zoneinfo/Asia/Makassar'),
'WSDT': tzfile('/usr/share/zoneinfo/Pacific/Apia'),
'XJT': tzfile('/usr/share/zoneinfo/Asia/Urumqi')
parser
用法
>>> date_str = 'Sat, 11/01/09 8:00PM EST'
>>> tzdate = parser.parse(date_str, tzinfos=TZINFOS)
>>> tzdate.astimezone(utc)
datetime.datetime(2009, 11, 2, 1, 0, tzinfo=<UTC>)
需要 UTC 转换,因为每个缩写都有许多可用的时区。由于TZINFOS
是dict
,因此每个缩写只有最后一个时区。而且您可能无法获得您所期望的预转换。
>>> tzdate
datetime.datetime(2009, 11, 1, 20, 0, tzinfo=tzfile('/usr/share/zoneinfo/America/Port-au-Prince'))
【讨论】:
【参考方案6】:我意识到dateparser
可以解决这个问题。 https://pypi.org/project/dateparser/
用法:
import dateparser
def time_gmt_format(str_datetime):
# from string like "29/05/2020, 08:18 WIB" to GMT yyyymmddhhmmss
date_time_obj = dateparser.parse(str_datetime, date_formats=['%d/%m/%Y, %H:%M %Z'],
settings='TO_TIMEZONE': 'GMT') # convert to GMT datetime object
return date_time_obj.strftime('%Y%m%d%H%M%S') # Output: 20200529011800
此库支持的其他时区:https://github.com/scrapinghub/dateparser/blob/e11a18a4d183a14211b28f5927ce01b220335881/dateparser/timezones.py
【讨论】:
以上是关于在 Python 中使用时区缩写名称解析日期/时间字符串?的主要内容,如果未能解决你的问题,请参考以下文章