2009-05-19 9 views
21

Tengo una fecha del formulario especificado por RFC 2822 - digamos Fri, 15 May 2009 17:58:28 +0000, como una cadena. ¿Existe una manera rápida y/o estándar de obtenerlo como un objeto datetime en Python 2.5? Traté de producir una cadena de formato strptime, pero el especificador de zona horaria +0000 confunde al analizador.Cómo analizar una fecha/hora de RFC 2822 en un horario de Python?

Respuesta

27

El problema es que parsedate ignorará el desplazamiento.

hacer esto en su lugar:

from email.utils import parsedate_tz 
print parsedate_tz('Fri, 15 May 2009 17:58:28 +0700') 
8

Hay una función de análisis en email.util. Analiza todas las fechas válidas de RFC 2822 y algunos casos especiales.

12
from email.utils import parsedate 
print parsedate('Fri, 15 May 2009 17:58:28 +0000') 

Documentation.

+0

+1 No sabía acerca de esta función, realmente ordenada. –

+0

Gracias; eso hace el truco :) – millenomi

7

me gustaría dar más detalles sobre las respuestas anteriores. email.utils.parsedate y email.utils.parsedate_tz ambos devuelven tuplas, ya que el OP necesita un objeto datetime.datetime, estoy añadiendo estos ejemplos de integridad:

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)) 

O:

d2 = datetime.datetime(*t[:6]) 

Tenga en cuenta que d1 y d2 son ambos objetos de fecha y hora ingenuas , no hay información de zona horaria almacenada. Si necesita objetos de fecha y hora conocidos, marque tzinfodatetime() arg.

otra posibilidad es utilizar el módulo dateutil

4

Parece que Python 3.3 en adelante tiene un nuevo método parsedate_to_datetime en email.utils que se encarga de los pasos intermedios:

email.utils. parsedate_to_datetime (date)

El inverso de format_datetime(). Realiza la misma función que parsedate(), pero en éxito devuelve una fecha y hora. Si la fecha de entrada tiene una zona horaria de -0000, , la fecha y hora será una fecha de inicio ingenua, y si la fecha es conforme a a las RFC representará una hora en UTC pero sin indicación de la zona horaria de origen real del mensaje la fecha viene de. Si la fecha de entrada tiene cualquier otro desfase de zona horaria válida, la fecha y hora será datetime con la correspondiente zona horaria tzinfo.

Nuevo en la versión 3.3.

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

1

email.utils.parsedate_tz(date) es la función de usar. Las siguientes son algunas variaciones.

correo electrónico cadena de fecha/hora (RFC 5322, RFC 2822, RFC 1123) de marca de tiempo Unix en el segundo flotador:

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 

Asegúrese de que no utilizamktime (que interpreta el time_struct en la hora local de su ordenador, no UTC); use timegm o mktime_tz en su lugar (pero tenga cuidado con la advertencia para mktime_tz en el párrafo siguiente).

Si está seguro de que tiene la versión de Python 2.7.4, 3.2.4, 3.3 o más reciente, puede usar email.utils.mktime_tz(tt) en lugar de calendar.timegm(tt) - tt[9]. Antes de eso, mktime_tz daba tiempos incorrectos cuando se invocaba durante la transición de ahorro de luz diurna de caída de la zona horaria local (bug 14653).

Gracias a @ j-f-sebastian por caveats about mktime and mktime_tz.

fecha Email/cadena de tiempo (RFC 5322, RFC 2822, RFC 1123) para “conscientes” datetime en Python 3.3:

En Python 3.3 y superiores, utilizar email.utils.parsedate_to_datetime, que devuelve una cuenta datetime con el original de la zona offset:

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 

Advertencia: esto arrojará ValueError si el tiempo cae en un segundo intercalar eg email.utils.parsedate_to_datetime("Sat, 31 Dec 2016 15:59:60 -0800").

fecha Email/cadena de tiempo (RFC 5322, RFC 2822, RFC 1123) para “conscientes” datetime en la zona UTC:

Esto se convierte en marca de tiempo y luego a 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 

fecha Email/cadena de tiempo (RFC 5322, RFC 2822, RFC 1123) a "consciente" de pitón datetime con desplazamiento original:

previa a Python 3.2, Python no vino con tzinfo implementaciones, así que aquí un ejemplo usando 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 

Si está utilizando Python 3.2, puede utilizar la orden interna tzinfo aplicación datetime.timezone: tz = datetime.timezone(datetime.timedelta(seconds=tt[9])) en lugar de el tercero dateutil.tz.tzoffset.

Gracias a @ j-f-sebastian otra vez for note on clamping the leap second.

Cuestiones relacionadas