2012-11-06 10 views
25

Sto provando a scrivere un paio di funzioni, dt e ut, che convertono avanti e indietro tra un tempo normale di unix (secondi da 1970-01-01 00:00:00 UTC) e un oggetto datetime Python.Convertire un unixtime in un oggetto datetime e viceversa (coppia di funzioni di conversione del tempo inverse)

Se dt e ut erano inverse corretto allora questo codice sarebbe stampare la stessa data e ora due volte:

import time, datetime 

# Convert a unix time u to a datetime object d, and vice versa 
def dt(u): return datetime.datetime.fromtimestamp(u) 
def ut(d): return time.mktime(d.timetuple()) 

u = 1004260000 
print u, "-->", ut(dt(u)) 

Ahimè, la seconda timestamp è 3600 secondi (un'ora) in meno rispetto al primo. Penso che questo accada solo per un tempo molto particolare, forse durante quell'ora che l'ora legale salta sopra. Ma c'è un modo per scrivere dt e ut in modo che siano veri inversi l'uno dell'altro?

questione connessa: Making matplotlib's date2num and num2date perfect inverses

+0

btw, se la funzione non fa altro che chiama un'altra funzione con gli stessi argomenti allora potresti semplicemente assegnarlo: 'dt = datetime.datetime.utcfromtimestamp'. Le funzioni sono cittadini di prima classe in Python: puoi passarle come parametri a un'altra funzione, tornare dalle funzioni, ecc. – jfs

+0

Ah, bello, ottimo punto! È più efficiente farlo o solo una questione di succinto? Che ne dite di 'def f (x): return foo (x)' vs 'f = lambda x: foo (x)'? (Il mio ricordo è che quelli sono equivalenti, sia dal punto di vista funzionale che di efficienza.) – dreeves

+0

'f = g' significa che f, g sono due nomi che si riferiscono alla stessa funzione. 'def' e' lambda' creano una nuova funzione. – jfs

risposta

37

Lei ha ragione che questo comportamento è legato al l'ora legale. Il modo più semplice per evitare questo è quello di assicurarsi di utilizzare un fuso orario senza l'ora legale, l'UTC ha più senso qui.

datetime.datetime.utcfromtimestamp() e calendar.timegm() trattano con tempi UTC e sono inversi esatti.

import calendar, datetime 

# Convert a unix time u to a datetime object d, and vice versa 
def dt(u): return datetime.datetime.utcfromtimestamp(u) 
def ut(d): return calendar.timegm(d.timetuple()) 

Ecco un po 'di spiegazione dietro perché datetime.datetime.fromtimestamp() ha un problema con l'ora legale, dalla documentazione:

Ritorna la data e l'ora corrispondente al timestamp POSIX locali, quali è restituito da time.time(). Se l'argomento facoltativo tz è None o non specificato, il timestamp viene convertito nella data locale della piattaforma e l'ora e l'oggetto datetime restituito è naive.

La parte importante è che si ottiene un oggetto datetime.datetime ingenuo, il che significa che non v'è alcun fuso orario (o legale) le informazioni come parte dell'oggetto. Ciò significa che più i timestamp distinti possono mappare allo stesso datetime.datetime oggetto quando si utilizza fromtimestamp(), se vi capita di scegliere gli orari che cadono durante l'ora legale roll back:

>>> datetime.datetime.fromtimestamp(1004260000) 
datetime.datetime(2001, 10, 28, 1, 6, 40) 
>>> datetime.datetime.fromtimestamp(1004256400) 
datetime.datetime(2001, 10, 28, 1, 6, 40) 
+0

Perfetto; Grazie! (E ho confermato che funziona per me.) – dreeves

+0

['ut = lambda naive_utc_dt: (naive_utc_dt - datetime (1970,1,1)) .total_seconds()'] (http://stackoverflow.com/a/ 8778548/4279) – jfs

+0

@JFSebastian, vuoi aggiungerlo come risposta? Sembra che tu abbia ragione (anche se non ho verificato la tua versione) e la tua dovrebbe essere la risposta accettata qui. Odio portare i posteri fuori strada, con solo un link nei commenti che indicano un modo migliore! – dreeves

Problemi correlati