2009-05-19 13 views
21

Ho una data del modulo specificato da RFC 2822, ad esempio Fri, 15 May 2009 17:58:28 +0000, come stringa. C'è un modo rapido e/o standard per ottenerlo come un oggetto datetime in Python 2.5? Ho provato a produrre una stringa di formato strptime, ma l'identificatore del fuso orario +0000 confonde il parser.Come analizzare una data/ora RFC 2822 in un datetime Python?

risposta

27

Il problema è che parsedate ignorerà l'offset.

fare questo, invece:

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

C'è una funzione analizzata in email.util. Analizza tutte le date RFC 2822 valide e alcuni casi speciali.

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

Documentation.

+0

+1 Non sapevo su questa funzione, davvero pulito. –

+0

Grazie; questo fa il trucco. :) – millenomi

7

mi piacerebbe approfondire risposte precedenti. email.utils.parsedate e email.utils.parsedate_tz entrambi restituiscono tuple, dal momento che l'OP ha bisogno di un oggetto datetime.datetime, sto aggiungendo questi esempi per completezza:

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

Oppure:

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

noti che d1 e d2 sono entrambi gli oggetti datetime naive , non ci sono informazioni sul fuso orario memorizzate. Se sono necessari oggetti datetime aggiornati, controllare lo tzinfodatetime() arg.

In alternativa è possibile utilizzare il modulo dateutil

4

Sembra che Python 3.3 per il futuro ha un nuovo metodo di parsedate_to_datetime in email.Utils che si prende cura dei passaggi intermedi:

email.Utils. parsedate_to_datetime (data)

L'inverso di format_datetime(). Esegue la stessa funzione di parsedate(), ma su il successo restituisce un datetime. Se la data di input ha un fuso orario di -0000, il datetime sarà un datetime ingenuo e se la data è conforme a per le RFC rappresenterà un orario in UTC ma senza indicazione di il fuso orario sorgente effettivo del messaggio la data viene da. Se la data di input ha un altro offset di fuso orario valido, il datetime sarà un datetime consapevole con il corrispondente fuso orario tzinfo.

Novità nella versione 3.3.

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

1

email.utils.parsedate_tz(date) è la funzione da utilizzare. Di seguito sono riportate alcune varianti.

Email stringa di data/ora (RFC 5322, RFC 2822, RFC 1123) per unix timestamp in secondi 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 

Assicurati di non utilizzaremktime (che interpreta il time_struct in tempo locale del computer, non UTC); utilizzare invece timegm o mktime_tz (ma fare attenzione all'evidenziazione per mktime_tz nel paragrafo successivo).

Se si è sicuri di disporre di python versione 2.7.4, 3.2.4, 3.3 o successiva, è possibile utilizzare email.utils.mktime_tz(tt) anziché calendar.timegm(tt) - tt[9]. Prima di questo, mktime_tz indicava orari non corretti quando veniva invocato durante la transizione all'ora legale in autunno (bug 14653).

Grazie a @ j-f-sebastian per caveats about mktime and mktime_tz.

data Email/string tempo (RFC 5322, RFC 2822, RFC 1123) per “consapevole” datetime su Python 3.3:

su Python 3.3 e superiori, utilizzare email.utils.parsedate_to_datetime, che restituisce un consapevole datetime con la zona originale 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 

Caveat: questo getterà ValueError se il tempo cade in un secondo intercalare esempio email.utils.parsedate_to_datetime("Sat, 31 Dec 2016 15:59:60 -0800").

data Email/string tempo (RFC 5322, RFC 2822, RFC 1123) per “consapevole” datetime in orario UTC:

Questo converte solo per timestamp e poi 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 

data Email/stringa di tempo (RFC 5322, RFC 2822, RFC 1123) a python "aware" datetime con offset originale:

Prima di Python 3.2, Python non è venuto con tzinfo implementazioni, ecco un esempio utilizzando 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 

Se si sta utilizzando Python 3.2, è possibile utilizzare la funzione interna tzinfo implementazione datetime.timezone: tz = datetime.timezone(datetime.timedelta(seconds=tt[9])) invece di la terza parte dateutil.tz.tzoffset.

Grazie a @ j-f-sebastian di nuovo for note on clamping the leap second.

Problemi correlati