У меня есть дата формы, указанной RFC 2822 - скажем Fri, 15 May 2009 17:58:28 +0000
, как строка. Есть ли быстрый и/или стандартный способ получить его как объект datetime
в Python 2.5? Я попытался создать строку формата strptime, но спецификатор часового пояса +0000 смущает парсер.
Как анализировать дату/время RFC 2822 в дату и время Python?
Ответ 1
Проблема в том, что parsedate будет игнорировать смещение.
Сделайте это вместо:
from email.utils import parsedate_tz
print parsedate_tz('Fri, 15 May 2009 17:58:28 +0700')
Ответ 2
from email.utils import parsedate
print parsedate('Fri, 15 May 2009 17:58:28 +0000')
Ответ 3
В email.util. Он анализирует все допустимые даты RFC 2822 и некоторые специальные случаи.
Ответ 4
Я хотел бы остановиться на предыдущих ответах. email.utils.parsedate
и email.utils.parsedate_tz
оба возвращаемых кортежа, так как OP нуждается в объекте datetime.datetime
, я добавляю эти примеры для полноты:
from email.utils import parsedate
from datetime import datetime
import time
t = parsedate('Sun, 14 Jul 2013 20:14:30 -0000')
d1 = datetime.fromtimestamp(time.mktime(t))
Или:
d2 = datetime.datetime(*t[:6])
Обратите внимание, что d1
и d2
являются наивными объектами datetime, нет информации о часовом поясе. Если вам нужны осведомленные объекты datetime, проверьте аргумент tzinfo
datetime()
.
В качестве альтернативы вы можете использовать модуль dateutil
Ответ 5
Похоже, что Python 3.3 в будущем имеет новый метод parsedate_to_datetime
в email.utils, который выполняет следующие шаги:
email.utils.parsedate_to_datetime (дата)
Обратный формат format_datetime(). Выполняет ту же функцию, что и parsedate(), но успех возвращает дату и время. Если входная дата имеет часовой пояс -0000, datetime будет наивным datetime, и если дата соответствует в RFC он будет представлять время в UTC, но без указания фактический часовой пояс для сообщения, из которого приходит дата. Если дата ввода имеет любое другое допустимое смещение часового пояса, дата-время будет знающее время datetime с соответствующим tzinfo часового пояса.
Новое в версии 3.3.
http://python.readthedocs.org/en/latest/library/email.util.html#email.utils.parsedate_to_datetime
Ответ 6
email.utils.parsedate_tz(date)
- это функция, которую следует использовать. Ниже приведены некоторые варианты.
Строка даты/времени электронной почты (RFC 5322, RFC 2822, RFC 1123) к временной отметке unix в полях float:
import email.utils
import calendar
def email_time_to_timestamp(s):
tt = email.utils.parsedate_tz(s)
if tt is None: return None
return calendar.timegm(tt) - tt[9]
import time
print(time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(email_time_to_timestamp("Wed, 04 Jan 2017 09:55:45 -0800"))))
# 2017-01-04T17:55:45Z
Убедитесь, что не использовать mktime
(который интерпретирует time_struct на ваших компьютерах по местному времени, не UTC); используйте timegm
или mktime_tz
вместо ( но будьте осторожны в отношении mktime_tz
в следующем абзаце).
Если вы уверены, что у вас есть версия python 2.7.4, 3.2.4, 3.3 или новее, вы можете использовать email.utils.mktime_tz(tt)
вместо calendar.timegm(tt) - tt[9]
. До этого mktime_tz
давал неверные времена при вызове во время локальных часовых поясов переход на летнее время (ошибка 14653).
Благодаря @j-f-sebastian для оговорки о mktime и mktime_tz.
Строка даты/времени электронной почты (RFC 5322, RFC 2822, RFC 1123) к знанию datetime
на python 3.3:
В python 3.3 и выше используйте email.utils.parsedate_to_datetime
, который возвращает знающий datetime
с исходным смещением зоны:
import email.utils
email.utils.parsedate_to_datetime(s)
print(email.utils.parsedate_to_datetime("Wed, 04 Jan 2017 09:55:45 -0800").isoformat())
# 2017-01-04T09:55:45-08:00
Предостережение: это будет бросать ValueError
, если время падает на секунду прыжка, например. email.utils.parsedate_to_datetime("Sat, 31 Dec 2016 15:59:60 -0800")
.
Строка даты/времени электронной почты (RFC 5322, RFC 2822, RFC 1123) в "осведомленный" datetime
в зоне UTC:
Это просто преобразуется в метку времени, а затем в UTC datetime
:
import email.utils
import calendar
import datetime
def email_time_to_utc_datetime(s):
tt = email.utils.parsedate_tz(s)
if tt is None: return None
timestamp = calendar.timegm(tt) - tt[9]
return datetime.datetime.utcfromtimestamp(timestamp)
print(email_time_to_utc_datetime("Wed, 04 Jan 2017 09:55:45 -0800").isoformat())
# 2017-01-04T17:55:45
Строка даты/времени электронной почты (RFC 5322, RFC 2822, RFC 1123) в python "aware" datetime
с исходным смещением:
До python 3.2 python не пришел с реализациями tzinfo, поэтому здесь приведен пример с dateutil.tz.tzoffset
(pip install dateutil
):
import email.utils
import datetime
import dateutil.tz
def email_time_to_datetime(s):
tt = email.utils.parsedate_tz(s)
if tt is None: return None
tz = dateutil.tz.tzoffset("UTC%+02d%02d"%(tt[9]//60//60, tt[9]//60%60), tt[9])
return datetime.datetime(*tt[:5]+(min(tt[5], 59),), tzinfo=tz)
print(email_time_to_datetime("Wed, 04 Jan 2017 09:55:45 -0800").isoformat())
# 2017-01-04T09:55:45-08:00
Если вы используете python 3.2, вы можете использовать встроенную tzinfo
реализацию datetime.timezone
: tz = datetime.timezone(datetime.timedelta(seconds=tt[9]))
вместо третьего -party dateutil.tz.tzoffset
.
Благодаря @j-f-sebastian снова для заметки о том, как зажать второй шаг.