如何用Python中的-0400时区字符串解析日期?

fie*_*lds 74 python timezone datetime

我有一个'2009/05/13 19:19:30 -0400'形式的日期字符串.对于尾随时区规范,似乎以前版本的Python可能支持strptime中的%z格式标记,但2.6.x似乎已经删除了它.

将此字符串解析为日期时间对象的正确方法是什么?

txw*_*ger 105

您可以使用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))
Run Code Online (Sandbox Code Playgroud)

这样您就可以获得可以使用的日期时间对象.

正如所回答的那样,dateutil2.0是为Python 3.0编写的,不适用于Python 2.x. 对于Python 2.x,需要使用dateutil1.5.

  • 这对我来说很好(`dateutil` 2.1)和Python`2.7.2`; Python 3不是必需的.请注意,如果从pip安装,则包名称为`python-dateutil`. (12认同)

jfs*_*jfs 39

%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)))
Run Code Online (Sandbox Code Playgroud)

在早期版本:

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
Run Code Online (Sandbox Code Playgroud)

哪个FixedOffset是基于docs代码示例的类:

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)
Run Code Online (Sandbox Code Playgroud)


Uri*_*ren 21

以下是"%z"Python 2.7及更早版本的问题修复

而不是使用:

datetime.strptime(t,'%Y-%m-%dT%H:%M %z')
Run Code Online (Sandbox Code Playgroud)

使用timedeltato帐户作为时区,如下所示:

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
Run Code Online (Sandbox Code Playgroud)

请注意,日期将转换为GMT,这将允许进行日期算术而不必担心时区.


say*_*yap 7

使用dateutil的问题在于,序列化和反序列化都不能使用相同的格式字符串,因为dateutil具有有限的格式化选项(仅限dayfirstyearfirst).

在我的应用程序中,我将格式字符串存储在.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) \
    .astimezone(timezone('US/Eastern')) == load_datetime(value, format)
Run Code Online (Sandbox Code Playgroud)


Eri*_*lin 5

那里有一艘老蟒蛇的班轮。您可以根据 +/- 符号将 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)
Run Code Online (Sandbox Code Playgroud)