Как преобразовать дату / время RFC 2822 в дату и время Python? - PullRequest
23 голосов
/ 20 мая 2009

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

Ответы [ 6 ]

33 голосов
/ 11 августа 2009

Проблема в том, что parsedate будет игнорировать смещение.

Сделайте это вместо:

from email.utils import parsedate_tz
print parsedate_tz('Fri, 15 May 2009 17:58:28 +0700')
13 голосов
/ 17 июня 2013

Я хотел бы остановиться на предыдущих ответах. email.utils.parsedate и email.utils.parsedate_tz оба возвращают кортежи, так как для ОП требуется объект 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 оба являются наивными объектами даты и времени, информация о часовых поясах не сохраняется. Если вам нужны осведомленные объекты даты и времени, проверьте аргумент tzinfo datetime().

В качестве альтернативы вы можете использовать модуль dateutil

12 голосов
/ 20 мая 2009
from email.utils import parsedate
print parsedate('Fri, 15 May 2009 17:58:28 +0000')

Документация .

8 голосов
/ 20 мая 2009

В email.util есть функция синтаксического анализа. Он анализирует все действительные даты RFC 2822 и некоторые особые случаи.

5 голосов
/ 18 марта 2014

Похоже, что у Python 3.3 в будущем есть новый метод parsedate_to_datetime в email.utils, который выполняет промежуточные шаги:

email.utils.parsedate_to_datetime (date)

Инверсия format_datetime (). Выполняет ту же функцию, что и parsedate (), но на Успех возвращает дату и время. Если дата ввода имеет часовой пояс -0000, дата-время будет наивной датой-временем, и если дата соответствует для RFC это будет время в UTC, но без указания фактический часовой пояс источника сообщения, от которого исходит дата. Если дата ввода имеет любое другое допустимое смещение часового пояса, дата-время будет осведомленная дата и время с соответствующим часовым поясом tzinfo.

Новое в версии 3.3.

http://python.readthedocs.org/en/latest/library/email.util.html#email.utils.parsedate_to_datetime

4 голосов
/ 07 января 2017

email.utils.parsedate_tz(date) - используемая функция. Ниже приведены некоторые варианты.

Строка даты / времени электронной почты ( RFC 5322 , RFC 2822 , RFC 1123 ) для метки времени Unix в числах с плавающей запятой:

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 «в курсе» 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])) вместо стороннего dateutil.tz.tzoffset.

Еще раз спасибо @ j-f-sebastian за примечание о зажиме високосной секунды .

...