2013-03-16 23 views
16

Il mio problema: ho bisogno di convertire una tupla dell'ora UTC in un timestamp UTC. Ma ho delle confusioni.Python: Converti time-tuple UTC in formato ora UTC

Prima un po 'Info:

  • time.mktime(tuple): questa funzione restituisce sempre il timestamp in ora locale.

    Questa è la funzione inversa di localtime(). Il suo argomento è struct_time o full-9-tuple che esprime l'ora in ora locale, non in UTC.

  • calendar.timegm(tuple): questo restituisce il timestamp UTC dal tupla volta fornito

    prende una tupla come quella restituita dalla funzione gmtime() del modulo time, e restituisce il corrispondente Valore di timestamp Unix. In realtà, time.gmtime() e timegm() sono ogni altri inverse

Ora facciamo un test: Perché ci sono

>>> from datetime import datetime 
>>> import time 
>>> import calendar as cal 

>>> utc_now = datetime.utcnow() 
>>> now = datetime.now() 
>>> utc_now 
datetime.datetime(2013, 3, 16, 9, 17, 22, 489225) 
>>> now 
datetime.datetime(2013, 3, 16, 5, 17, 29, 736903) 

>>> time.mktime(datetime.timetuple(utc_now)), time.mktime(datetime.timetuple(now)) 
(1363439842.0, 1363425449.0) 
>>> cal.timegm(datetime.timetuple(utc_now)), cal.timegm(datetime.timetuple(now)) 
(1363425442, 1363411049) 

quattro valori differenti? E quale è giusto quando voglio convertire una tupla dell'ora UTC in un timestamp UTC?

UPDATTE


Penso di aver trovato risposte alle mie confusioni, quindi lasciatemi spiegare.

In primo luogo, abbiamo bisogno di sapere qualcosa di importante:

Ci sono due tipi di data e ora: oggetti “ingenuo” e “consapevole”.

Un oggetto a conoscenza ha una conoscenza sufficiente degli aggiustamenti temporali algoritmici e politici applicabili, come le informazioni sul fuso orario e sull'ora legale, per localizzarsi rispetto ad altri oggetti consapevoli. Un oggetto consapevole viene utilizzato per rappresentare un momento specifico nel tempo che non è aperto all'interpretazione [1].

Un oggetto ingenuo non contiene informazioni sufficienti per posizionarsi in modo univoco rispetto ad altri oggetti di data/ora. Se un oggetto naive rappresenta il Coordinated Universal Time (UTC), l'ora locale o il tempo in un altro fuso orario è puramente fino al programma, proprio come è al programma se un numero specifico rappresenta metri, miglia o massa. Gli oggetti ingenui sono facili da capire e da lavorare, al costo di ignorare alcuni aspetti della realtà.

Quello che otteniamo da datetime.utcnow() o datetime.now() sono oggetti "ingenuo".Ciò significa che l'oggetto datetime restituito non dice in alcun modo l'ora locale o l'ora UTC, ma rappresenta "un po 'di tempo". Incapsula semplicemente le informazioni sull'ora & (anno, mese, giorno, ora, minuti, secondi, ecc.). È TUA responsabilità associarlo con la nozione di locale o UTC.

Quindi, ricorda che un oggetto datetime ingenuo rappresenta solo "un po 'di tempo". La funzione datetime.now() restituisce un "un po 'di tempo" che è uguale all'ora corrente e la funzione datetime.utcnow() restituisce "un po' di tempo" che è l'ora corrente in Greenwich England (che è ciò che UTC è).

Il "un po 'di tempo" è solo un valore per l'ora &. E nota che in diversi luoghi sulla terra, il "qualche tempo" si verifica in tempi diversi. Ad esempio, se un valore "un po 'di tempo" è 1 gennaio, 10:30, allora sarà l'ora corrente a Greenwich in Inghilterra circa 5 ore PRIMA che diventi l'ora corrente a New York.

Quindi possiamo vedere che ci sono due cose: un generico valore "un po 'di tempo", e la nozione che quel "qualche tempo" diventa ora corrente in luoghi diversi in "tempi" differenti. (nessun gioco di parole qui, continua a leggere)

Ora, prima definiamo cos'è l'epoca. Sappiamo che "un po 'di tempo" è solo un valore generico di tempo. Quindi, l'epoca è un "qualche tempo" che si è verificato a Greenwich, in Inghilterra, dove i valori dei parametri sono: January 1 1970, 00:00:00.

Un "timestamp" è no. di secondi trascorsi dall'epica. Ciò significa che il timestamp era 0 quando l'ora era Jan 1, 1970, 00:00:00 a Greenwich in Inghilterra. Ma il timestamp era di ca. (5 * 60 * 60) quando il tempo era Jan 1, 1970, 00:00:00 a New York.

>>> tt = datetime.timetuple(datetime(1970, 1, 1, 0, 0, 0)) 
>>> cal.timegm(tt) 
0 

Quindi, possiamo vedere che lo stesso valore "qualche tempo" di Jan 1, 1970, 00:00:00 ha diversi timestamp quando cambiamo posizioni. Quindi quando parli di timestamp, devi anche dire "a quale posizione" si riferisce il timestamp, e quanto a est oa ovest questa località è collegata a Greenwich England. Quella posizione è espressa come "fuso orario".

Ora, ogni sistema (computer) ha un fuso orario configurato e tutti i timestamp relativi a tale fuso orario diventano effettivamente "locali". L'UTC è il riferimento globale.

Quindi, diciamo che hanno un valore X per "qualche tempo", che converte in:

  • Y timestamp in ora locale
  • Z timestamp UTC

allora questo significa che Y no. di secondi dovrà trascorrere "un po 'di tempo" per diventare l'ora corrente nella tua posizione e il numero Z non dovrà passare per l'ora corrente a Greenwich in Inghilterra per diventare "un po' di tempo".

Ora, finalmente, torniamo alle nostre funzioni mktime e timegm. Questi prendono una tupla del tempo, che è solo un'altra rappresentazione per "qualche tempo". Ricorda che li stiamo passando in un tempo ingenuo che non ha alcuna nozione di locale o UTC.

Diciamo che X è una tupla del tempo che rappresenta un ingenuo "un po 'di tempo".Quindi

  • mktime(X) restituirà il n. di secondi che devono trascorrere affinché l'ora corrente locale diventi tale "un po 'di tempo" e
  • timegm(X) restituirà il numero di secondi che dovranno essere spesi per rendere uguale l'ora corrente di Greenwich England a quella "a volte".

Nell'esempio precedente, now e utc_now rappresentano naive "tempo", e quando alimentiamo questi valori "Tempo" in mktime e timegm, semplicemente restituire il n. di secondi che devono passare per le posizioni corrispondenti (la tua posizione e Greenwich England) per avere il loro tempo corrente che è "qualche volta".


Infine, torna al mio problema: ho bisogno di convertire una tupla di tempo UTC in un timestamp UTC.

In primo luogo, non esiste il concetto di "tupla temporale UTC" - è solo "qualche volta". Se ho bisogno di convertirlo in UTC, ho semplicemente uso timegm:

cal.timegm(datetime.timetuple(utc_now)) 

che mi darà il timestamp per l'ora UTC corrente (vale a dire, l'attuale "qualche tempo" in Greenwich Inghilterra).

+1

molto informativo. Grazie. – smartnut007

+0

Epoca è 'Jan 1, 1970, 00: 00: 00' ** UTC + 0000 **. È "Dec 31, 1969, 19:00:00 EST-0500" a New York. Epoch è la stessa istanza temporale in tutto il mondo, a prescindere dall'orologio locale (l'orologio locale di New York mostra 7pm per l'epoca POSIX). Il timestamp non dipende dal fuso orario locale: è esattamente lo stesso in tutto il mondo in un dato momento. – jfs

+0

related: [Conversione datetime.date in data/ora UTC in Python] (http://stackoverflow.com/q/8777753/4279) – jfs

risposta

6

Esistono solo tre valori diversi. Questi due valori:

1363425449.0 (time.mktime(datetime.timetuple(now)) 
1363425442 (cal.timegm(datetime.timetuple(utc_now))) 

differiscono solo per 7 secondi, che è quello che in origine visto quando hai mollato le variabili:

>>> utc_now 
datetime.datetime(2013, 3, 16, 9, 17, 22, 489225) 
>>> now 
datetime.datetime(2013, 3, 16, 5, 17, 29, 736903) 

(Nota del 22 vs 29 nella parte secondi dell'uscita.)

Gli altri due valori sono semplicemente errate, perché si sta applicando il tipo sbagliato di argomenti - si sta chiamando time.mktime con valori UTC invece di valori locali, e si sta chiamando cal.timegm con i valori locali invece di valori UTC . La documentazione dice chiaramente cosa è previsto, quindi assicurati di utilizzare solo i valori appropriati. In pratica stai vedendo l'offset dell'ora locale (4 ore, a giudicare da quello) applicato quando non dovrebbe essere (in direzioni diverse a seconda di dove si trova l'errore).

Quando diagnostichi cose come questa, è utile usare epochconverter.com che ti darà l'attuale timestamp Unix, così puoi confrontarlo con il tuo output.

+0

La documentazione NON dice nulla se gli argomenti devono essere locali o UTC. E perché dici che gli altri due valori non sono corretti? – treecoder

+1

@good_computer: cosa intendi?La documentazione * che hai citato * per 'mktime' dice chiaramente che dovrebbe essere locale, e il documentat * che hai citato * per' timegm' dice che la tupla dovrebbe essere il tipo restituito da 'gmtime' (che è UTC). Se si passa in un valore UTC quando una funzione è in attesa di un'ora locale o viceversa, la funzione applicherà una conversione locale/UTC quando non si desidera o * non * si applica quando si * fa * lo voglio (È un peccato che l'API non sia in grado di rilevare ciò stesso, ma tale è la vita ... devi stare attento) –

+0

@good_computer: il tuo concetto "un po 'di tempo" è anche conosciuto come "data e ora locale" in molti framework - come 'LocalDateTime' in Joda Time. È una data/ora senza fuso orario associato. Quindi hai ancora un problema o sei in ordine? –