Как разобрать даты со строкой часового пояса -0400 в Python?
У меня есть строка даты в форме '2009/05/13 19:19:30 -0400'. Похоже, что предыдущие версии Python, возможно, поддерживали тег формата %z в strptime для спецификации конечного часового пояса, но 2.6.x, кажется, удалил это.
Как правильно разобрать эту строку в объект datetime?
6 ответов:
вы можете использовать функцию синтаксического анализа из 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))таким образом вы получаете объект datetime, который затем можно использовать.
Как ответил, dateutil2.0 написан для Python 3.0 и не работает с Python 2.x. для Python 2.необходимо использовать X dateutil1.5.
%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)
вот исправление
"%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, что позволит делать арифметику даты, не беспокоясь о часовых поясах.
проблема с использованием 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) \ .astimezone(timezone('US/Eastern')) == load_datetime(value, format)
один лайнер для старых питонов там. Вы можете умножить 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)
Если вы находитесь на 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также будет принимать входные данные, такие как" вчера "или" в прошлом году": -)
Comments