Подтвердить что ты не робот

Как анализировать дату/время RFC 2822 в дату и время Python?

У меня есть дата формы, указанной RFC 2822 - скажем Fri, 15 May 2009 17:58:28 +0000, как строка. Есть ли быстрый и/или стандартный способ получить его как объект datetime в Python 2.5? Я попытался создать строку формата strptime, но спецификатор часового пояса +0000 смущает парсер.

4b9b3361

Ответ 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 снова для заметки о том, как зажать второй шаг.