2009-12-21 11 views
13

C'è un modo semplice per convertire un orario RFC 3339 in un normale timestamp Python?Convertire un tempo RFC 3339 in un timestamp standard di Python

Ho uno script che sta leggendo un feed ATOM e mi piacerebbe essere in grado di confrontare il timestamp di un elemento nel feed ATOM al momento della modifica di un file.

Ho notato dal ATOM spec, che le date di ATOM includono una differenza di fuso orario (Z<a number>), ma, nel mio caso, non c'è niente dopo la Z quindi credo che possiamo supporre GMT.

Suppongo di poter analizzare il tempo con una regex di qualche tipo ma speravo che Python avesse un modo integrato per farlo che non sono stato in grado di trovare.

+2

Se andate a leggere le specifiche RFC 3339, si vedrà che i valori di offset solo tempo valido zona sono: (0) una "Z" nuda, che significa che la marca temporale è UTC; o (1) un offset del modulo "[+ -] \ d \ d: \ d \ d" come "+02: 00" o "-08: 00". Si noti che un offset di "+00: 00" significherebbe la stessa cosa di "Z". Per maggiori dettagli, leggi la specifica RFC 3339: http://tools.ietf.org/html/rfc3339 – steveha

+0

Bug Python: [issue15873: datetime: aggiungi la capacità di analizzare date e ore RFC 3339] (http: //bugs.python .org/issue15873) – jfs

+0

correlati: [Convertire timestamp con offset per datetime obj utilizzando strptime] (http://stackoverflow.com/q/12281975/4279) – jfs

risposta

9

No builtin, afaik.

feed.date.rfc3339 Questo è un modulo libreria Python con funzioni per la conversione di stringhe in formato timestamp RFC 3339 per valori float tempo Python, e viceversa. RFC 3339 è il formato di timestamp utilizzato dal formato di syndication del feed Atom.

È concesso in licenza BSD.

http://home.blarg.net/~steveha/pyfeed.html

(A cura in modo che sia chiaro che non ho scritto di esso. :-)

+0

PyFeed fa esattamente quello che mi serve, per gentile concessione della funzione tf_from_timestamp() in feed.date.rfc3339 –

+1

Inoltre, ho scritto le librerie PyFeed (e Xe), e mi trovo qui su StackOverflow, quindi se avessi qualche domanda al riguardo, sarei felice di risponderle. – steveha

+0

Si noti che PyFeed può essere utilizzato per analizzare un feed Atom. Utilizza xml.dom.minidom per eseguire l'analisi vera e propria, quindi decomprime la struttura ad albero XML in classi convenienti e convenienti. Hmm, dovrei mettere Xe e PyFeed su PyPI. – steveha

8

http://pypi.python.org/pypi/iso8601/ sembra essere in grado di analizzare ISO 8601, che RFC 3339 è un sottoinsieme di, forse questo potrebbe essere utile, ma di nuovo, non integrato.

+0

I tempi float e struct_time non sono consapevoli del fuso orario. Poiché RFC 3339 richiede fusi orari compatibili con UTC, che in Python significa oggetti 'datetime' non ingenui, questa è l'unica opzione sensata finora. – Tobu

21

non si include un esempio, ma se non si dispone di un Z-offset o fuso orario, e supponendo che non si vuole durate, ma solo il tempo di base, allora forse questo fa per voi:

import datetime as dt 
>>> dt.datetime.strptime('1985-04-12T23:20:50.52', '%Y-%m-%dT%H:%M:%S.%f') 
datetime.datetime(1985, 4, 12, 23, 20, 50, 520000) 

La funzione strptime() è stata aggiunta al modulo datetime in Python 2.5, quindi alcune persone non sanno ancora che è lì.

Edit: The time.strptime() la funzione esiste da un po ', però, e lavora circa lo stesso di dare un valore struct_time:

>>> ts = time.strptime('1985-04-12T23:20:50.52', '%Y-%m-%dT%H:%M:%S.%f') 
>>> ts 
time.struct_time(tm_year=1985, tm_mon=4, tm_mday=12, tm_hour=23, tm_min=20, tm_sec=50, tm_wday=4, tm_yday=102, tm_isdst=-1) 
>>> time.mktime(ts) 
482210450.0 
+7

+1 per una soluzione che utilizza la libreria standard! – jathanism

+8

Questo non funzionerà - I metodi che non sono a conoscenza del fuso orario non sono compatibili con RFC 3339. – Yarin

+0

Yarin, chiaramente, ma il tuo reclamo dovrebbe essere con l'uso della domanda originale di "RFC 3339" allora, come la mia risposta ha affrontato la sua domanda reale, dove nota che non ha un fuso orario ... –

5

feedparser.py fornisce robusta modo/estendibile per analizzare vari formati di data che si possono incontrare in atomo del mondo reale/RSS: biblioteca

>>> from feedparser import _parse_date as parse_date 
>>> parse_date('1985-04-12T23:20:50.52Z') 
time.struct_time(tm_year=1985, tm_mon=4, tm_mday=12, tm_hour=23, tm_min=20, 
       tm_sec=50, tm_wday=4, tm_yday=102, tm_isdst=1) 
+1

Questo sembra molto più bello dei" tempi fluttuanti "offerti da PyFeed. –

+2

cool-NR, se si ha un valore float temporale, è possibile chiamare 'time.gmtime()' e ottenere il valore 'struct_time'. Ed è molto più facile fare tempi relativi con un valore di tempo variabile; due giorni da oggi è semplicemente 'tf + 2 * seconds_per_day' (dove' seconds_per_day' è 24 * 60 * 60). 'Struct_time' di Python è ottimo per l'ispezione (quale giorno della settimana è?) Ma terribilmente scomodo per l'elaborazione. – steveha

+0

link non funzionante, dovrebbe essere http://code.google.com/p/feedparser/source/browse/trunk/feedparser/feedparser.py? – Yarin

0

È venuto attraverso il fantastico modulo dateutil.parser in un'altra domanda, e l'ho provato sul mio problema con RFC3339, e sembra che gestisca tutto ciò con cui lo lancio con maggiore sicurezza rispetto a qualsiasi altra risposta in questa domanda.

+1

L'unico problema è che analizza anche i valori * non-date * come "now" –

1

provare questo, tutto funziona bene per me

datetime_obj = datetime.strptime("2014-01-01T00:00:00Z", '%Y-%m-%dT%H:%M:%SZ') 

o

datetime_obj = datetime.strptime("Mon, 01 Jun 2015 16:41:40 GMT", '%a, %d %b %Y %H:%M:%S GMT') 
+2

ma non supporta l'offset utc numerico: '+ HHMM'. Il secondo esempio non è [rfc 3339] (https://tools.ietf.org/html/rfc3339#section-5.6); è [rfc 5322] (https://tools.ietf.org/html/rfc5322#section-3.3) – jfs

3

ho lottato con il formato RFC3339 datetime molto, ma ho trovato una soluzione adatta per convertire DATE_STRING < => datetime_object in entrambe le direzioni.

avete bisogno di due diversi moduli esterni, perché uno di loro è è in grado di fare la conversione in una sola direzione (purtroppo):

prima installare:

sudo pip install rfc3339 
sudo pip install iso8601 

quindi includere:

import datetime  # for general datetime object handling 
import rfc3339  # for date object -> date string 
import iso8601  # for date string -> date object 

Per non aver bisogno di ricordare quale modulo è per quale direzione, ho scritto due semplici funzioni di supporto:

def get_date_object(date_string): 
    return iso8601.parse_date(date_string) 

def get_date_string(date_object): 
    return rfc3339.rfc3339(date_object) 

che all'interno del codice è possibile usare facilmente come questo:

input_string = '1989-01-01T00:18:07-05:00' 
test_date = get_date_object(input_string) 
# >>> datetime.datetime(1989, 1, 1, 0, 18, 7, tzinfo=<FixedOffset '-05:00' datetime.timedelta(-1, 68400)>) 

test_string = get_date_string(test_date) 
# >>> '1989-01-01T00:18:07-05:00' 

test_string is input_string # >>> True 

Heureka! Ora si può facilmente (haha ​​) usare le stringhe di data e stringhe di data in un formato utilizzabile.

1

Utilizzando Python 3, è possibile utilizzare RegEx per interrompere il timestamp di RFC 3339 nei suoi componenti. Poi, crea direttamente l'oggetto datetime, senza moduli aggiuntivi necessari:

import re 
import datetime 

def parse_rfc3339(dt): 
    broken = re.search(r'([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(\.([0-9]+))?(Z|([+-][0-9]{2}):([0-9]{2}))', dt) 
    return(datetime.datetime(
     year = int(broken.group(1)), 
     month = int(broken.group(2)), 
     day = int(broken.group(3)), 
     hour = int(broken.group(4)), 
     minute = int(broken.group(5)), 
     second = int(broken.group(6)), 
     microsecond = int(broken.group(8) or "0"), 
     tzinfo = datetime.timezone(datetime.timedelta(
      hours = int(broken.group(10) or "0"), 
      minutes = int(broken.group(11) or "0"))))) 

Questo esempio theads fusi o microsecondi mancante come "0", ma potrebbe essere necessario ulteriore controllo degli errori. Cheers, Alex

+1

Presumibilmente, questo funzionerebbe anche in Python 2. – Flimm

2

Se stai usando Django, è possibile utilizzare di Django funzione parse_datetime:

>>> from django.utils.dateparse import parse_datetime 
>>> parse_datetime("2016-07-19T07:30:36+05:00") 
datetime.datetime(2016, 7, 19, 7, 30, 36, tzinfo=<django.utils.timezone.FixedOffset object at 0x101c0c1d0>)