2009-09-04 14 views
33

Sto avendo alcuni problemi strani con la funzione .localize() di pytz. A volte non apportare modifiche al datetime localizzata:pytz localize vs datetime replace

comportamento .localize:

>>> tz 
<DstTzInfo 'Africa/Abidjan' LMT-1 day, 23:44:00 STD> 
>>> d 
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421) 

>>> tz.localize(d) 
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421, 
        tzinfo=<DstTzInfo 'Africa/Abidjan' GMT0:00:00 STD>) 
>>> tz.normalize(tz.localize(d)) 
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421, 
        tzinfo=<DstTzInfo 'Africa/Abidjan' GMT0:00:00 STD>) 

Come si può vedere, il tempo non è stato modificato in seguito a localizzare/normalizzare le operazioni. Tuttavia, se viene utilizzato .Rimontare:

>>> d.replace(tzinfo=tz) 
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421, 
        tzinfo=<DstTzInfo 'Africa/Abidjan' LMT-1 day, 23:44:00 STD>) 
>>> tz.normalize(d.replace(tzinfo=tz)) 
datetime.datetime(2009, 9, 2, 15, 1, 42, 91421, 
        tzinfo=<DstTzInfo 'Africa/Abidjan' GMT0:00:00 STD>) 

che sembra fare aggiustamenti in datetime.

La domanda è - che è corretta e perché altro è sbagliato?

+0

correlati: [Conversione Fuso orario utilizzando pytz] (http://stackoverflow.com/q/27531718/4279) – jfs

risposta

27

localize presuppone solo che l'ingenuo datetime che si passa sia "giusto" (tranne che per non conoscere il fuso orario!) E quindi basta impostare il fuso orario, senza altre regolazioni.

È possibile (ed è consigliabile ...) lavorare internamente in UTC (piuttosto che con datetimes ingenui) e utilizzare replace quando è necessario eseguire I/O di datetimes in modo localizzato (normalize gestirà l'ora legale e simili).

+1

quote Alex per il suggerimento di utilizzare UTC e localizzare/delocalizzare durante le operazioni di I/O. Posso suggerire che non è consigliabile ma fortemente raccomandato (leggi obbligati)! – DrFalk3n

+2

L'OP ha chiesto la differenza tra 'localize' e' replace'. Non sostituisce anche solo il fuso orario, senza altre regolazioni? Se è così, perché ci sono differenze tra i due risultati? –

+5

@MichaelWaterfall: 'pytz.timezone()' può corrispondere a diversi oggetti tzinfo (stesso luogo, offset UTC diversi, abbreviazioni del fuso orario). 'tz.localize (d)' cerca di trovare il tzinfo corretto per l'ora locale 'd' data (qualche ora locale è ambigua o non esiste). 'replace()' imposta semplicemente qualsiasi informazione (casuale) che il fuso orario di pytz fornisce di default senza riguardo per la data specificata (LMT nelle versioni recenti). 'tz.normalize()' può regolare il tempo se 'd' è un tempo locale inesistente, ad esempio, il tempo durante la transizione dell'ora legale in primavera (emisfero settentrionale) altrimenti non fa nulla in questo caso. – jfs

4

Questa classe DstTzInfo viene utilizzata per fusi orari in cui l'offset rispetto all'ora UTC cambia in determinati momenti. Ad esempio (come probabilmente saprai), molte località passano a "ora legale" all'inizio dell'estate, quindi tornano a "ora solare" alla fine dell'estate. Ogni istanza di DstTzInfo rappresenta solo uno di questi fusi orari, ma i metodi "localizza" e "normalizza" consentono di ottenere l'istanza corretta.

Per Abidjan, v'è sempre e solo stata una transizione (secondo pytz), e che sia in 1912

>>> tz = pytz.timezone('Africa/Abidjan') 
>>> tz._utc_transition_times 
[datetime.datetime(1, 1, 1, 0, 0), datetime.datetime(1912, 1, 1, 0, 16, 8)] 

Scopo tz usciamo pytz rappresenta il fuso orario pre-1912

>>> tz 
<DstTzInfo 'Africa/Abidjan' LMT-1 day, 23:44:00 STD> 

Ora guardando al vostro due esempi, vedere che quando si chiama tz.localize (d) si fa NON ottenere questo pre-1912 fuso orario aggiunto al vostro oggetto datetime naive. Si presuppone che l'oggetto datetime assegnato corrisponda all'ora locale nel fuso orario corretto per l'ora locale, che è il fuso orario successivo al 1912.

Tuttavia nel secondo esempio che utilizza d.replace (tzinfo = tz), il tuo oggetto datetime deve rappresentare l'ora nel fuso orario precedente al 1912. Questo probabilmente non è quello che intendevi. Quindi quando chiamate dt.normalize lo converte nel fuso orario corretto per quel valore datetime, ovvero il fuso orario successivo al 1912.

6

Mi rendo conto che sono un po 'in ritardo su questo ... ma ecco quello che ho trovato a lavorare bene. Work in UTC come Alex ha dichiarato:

tz = pytz.timezone('Africa/Abidjan') 
now = datetime.datetime.utcnow() 

Poi da localizzare:

tzoffset = tz.utcoffset(now) 
mynow = now+tzoffset 

E questo metodo consente di gestire DST perfettamente

+1

non è corretto se il metodo '.utcoffset()' si aspetta data/ora nel fuso orario locale diverso da utc. Per ottenere l'ora corrente nel fuso orario locale: 'now = datetime.now (tz)'. Per convertire il tempo di utc nel fuso orario locale: 'dt = utc_dt.replace (tzinfo = pytz.utc) .astimezone (tz)' (non è necessario '.localize()', '.normalize()' qui). – jfs

+0

Può anche non essere corretto se l'offset attraversa un limite DST – paolov

1

localize è la funzione corretta da utilizzare per la creazione di oggetti datetime consapevole con un valore di data/ora fisso iniziale. L'oggetto di conoscenza datetime risultante avrà il valore datetime originale. Un modello di utilizzo molto comune a mio avviso e uno che forse pytz può documentare meglio.

replace(tzinfo = ...) è sfortunatamente chiamato. È una funzione casuale nel suo comportamento. Consiglierei di evitare l'uso di questa funzione per impostare i fusi orari a meno che non ti piaccia il dolore autoinflitto. Ho già sofferto abbastanza da usare questa funzione.