如何在 Python 中解析带有 -0400 时区字符串的日期?
- 2024-12-31 08:37:00
- admin 原创
- 113
问题描述:
我有一个格式为“2009/05/13 19:19:30 -0400”的日期字符串。似乎以前的 Python 版本可能支持 strptime 中的 %z 格式标签来指定尾随时区,但 2.6.x 似乎已将其删除。
将此字符串解析为日期时间对象的正确方法是什么?
解决方案 1:
您可以使用 dateutil 中的解析函数:
>>> from dateutil.parser import parse
>>> d = parse('2009/05/13 19:19:30 -0400')
>>> d
datetime.datetime(2009, 5, 13, 19, 19, 30, tzinfo=tzoffset(None, -14400))
这样,您就获得了一个可以使用的日期时间对象。
正如回答的那样,dateutil2.0 是为 Python 3.0 编写的,不适用于 Python 2.x。对于 Python 2.x,需要使用 dateutil1.5。
解决方案 2:
%z
在 Python 3.2+ 中受支持:
>>> from datetime import datetime
>>> datetime.strptime('2009/05/13 19:19:30 -0400', '%Y/%m/%d %H:%M:%S %z')
datetime.datetime(2009, 5, 13, 19, 19, 30,
tzinfo=datetime.timezone(datetime.timedelta(-1, 72000)))
在早期版本中:
from datetime import datetime
date_str = '2009/05/13 19:19:30 -0400'
naive_date_str, _, offset_str = date_str.rpartition(' ')
naive_dt = datetime.strptime(naive_date_str, '%Y/%m/%d %H:%M:%S')
offset = int(offset_str[-4:-2])*60 + int(offset_str[-2:])
if offset_str[0] == "-":
offset = -offset
dt = naive_dt.replace(tzinfo=FixedOffset(offset))
print(repr(dt))
# -> datetime.datetime(2009, 5, 13, 19, 19, 30, tzinfo=FixedOffset(-240))
print(dt)
# -> 2009-05-13 19:19:30-04:00
其中是基于文档中的代码示例FixedOffset
的类:
from datetime import timedelta, tzinfo
class FixedOffset(tzinfo):
"""Fixed offset in minutes: `time = utc_time + utc_offset`."""
def __init__(self, offset):
self.__offset = timedelta(minutes=offset)
hours, minutes = divmod(offset, 60)
#NOTE: the last part is to remind about deprecated POSIX GMT+h timezones
# that have the opposite sign in the name;
# the corresponding numeric value is not used e.g., no minutes
self.__name = '<%+03d%02d>%+d' % (hours, minutes, -hours)
def utcoffset(self, dt=None):
return self.__offset
def tzname(self, dt=None):
return self.__name
def dst(self, dt=None):
return timedelta(0)
def __repr__(self):
return 'FixedOffset(%d)' % (self.utcoffset().total_seconds() / 60)
解决方案 3:
"%z"
以下是针对 Python 2.7 及更早版本的问题的修复
而不是使用:
datetime.strptime(t,'%Y-%m-%dT%H:%M %z')
使用timedelta
来考虑时区,如下所示:
from datetime import datetime,timedelta
def dt_parse(t):
ret = datetime.strptime(t[0:16],'%Y-%m-%dT%H:%M')
if t[18]=='+':
ret-=timedelta(hours=int(t[19:22]),minutes=int(t[23:]))
elif t[18]=='-':
ret+=timedelta(hours=int(t[19:22]),minutes=int(t[23:]))
return ret
请注意,日期将被转换为GMT
,这样就可以进行日期算术而不必担心时区。
解决方案 4:
使用 dateutil 的问题在于,序列化和反序列化不能使用相同的格式字符串,因为 dateutil 的格式选项有限(只有dayfirst
和yearfirst
)。
在我的应用程序中,我将格式字符串存储在 .INI 文件中,并且每个部署都可以有自己的格式。因此,我真的不喜欢 dateutil 方法。
以下是使用 pytz 的替代方法:
from datetime import datetime, timedelta
from pytz import timezone, utc
from pytz.tzinfo import StaticTzInfo
class OffsetTime(StaticTzInfo):
def __init__(self, offset):
"""A dumb timezone based on offset such as +0530, -0600, etc.
"""
hours = int(offset[:3])
minutes = int(offset[0] + offset[3:])
self._utcoffset = timedelta(hours=hours, minutes=minutes)
def load_datetime(value, format):
if format.endswith('%z'):
format = format[:-2]
offset = value[-5:]
value = value[:-5]
return OffsetTime(offset).localize(datetime.strptime(value, format))
return datetime.strptime(value, format)
def dump_datetime(value, format):
return value.strftime(format)
value = '2009/05/13 19:19:30 -0400'
format = '%Y/%m/%d %H:%M:%S %z'
assert dump_datetime(load_datetime(value, format), format) == value
assert datetime(2009, 5, 13, 23, 19, 30, tzinfo=utc) \n .astimezone(timezone('US/Eastern')) == load_datetime(value, format)
解决方案 5:
适用于旧 Python 的一行代码。您可以根据 +/- 符号将 timedelta 乘以 1/-1,如下所示:
datetime.strptime(s[:19], '%Y-%m-%dT%H:%M:%S') + timedelta(hours=int(s[20:22]), minutes=int(s[23:])) * (-1 if s[19] == '+' else 1)
解决方案 6:
如果您使用的是 Linux,那么您可以使用外部date
命令来 dwim:
import commands, datetime
def parsedate(text):
output=commands.getoutput('date -d "%s" +%%s' % text )
try:
stamp=eval(output)
except:
print output
raise
return datetime.datetime.frometimestamp(stamp)
这当然比 dateutil 的可移植性更差,但稍微灵活一些,因为date
它还可以接受“昨天”或“去年”这样的输入:-)
相关推荐
热门文章
项目管理软件有哪些?
热门标签
云禅道AD