Come convertire la stringa di ora locale in UTC?


308

Come faccio a convertire una stringa datetime in ora locale in una stringa in ora UTC ?

Sono sicuro di averlo già fatto in precedenza, ma non riesco a trovarlo e SO si spera che possa aiutare me (e altri) a farlo in futuro.

Precisazione : Per esempio, se ho 2008-09-17 14:02:00nel mio fuso orario locale ( +10), mi piacerebbe per generare una stringa con l'equivalente UTCtempo: 2008-09-17 04:02:00.

Inoltre, da http://lucumr.pocoo.org/2011/7/15/eppur-si-muove/ , in generale ciò non è possibile in quanto con l'ora legale e altri problemi non esiste una conversione univoca dall'ora locale a Ora UTC.


1
Tieni presente che il metodo mktime () accetta un "orario locale" come input che potrebbe non essere quello che ti aspetti, l'ho usato e ha rovinato tutto. Dai un'occhiata a questo link
Haifeng Zhang,

Risposte:


288

Innanzitutto, analizzare la stringa in un oggetto datetime ingenuo. Questa è un'istanza datetime.datetimesenza informazioni sul fuso orario allegate. Consultare la documentazione per datetime.strptimeinformazioni sull'analisi della stringa della data.

Utilizzare il pytzmodulo, che viene fornito con un elenco completo di fusi orari + UTC. Scopri qual è il fuso orario locale, costruisci un oggetto fuso orario da esso e manipolalo e collegalo al datetime ingenuo.

Infine, usa il datetime.astimezone()metodo per convertire il datetime in UTC.

Codice sorgente, utilizzando il fuso orario locale "America / Los_Angeles", per la stringa "2001-2-3 10:11:12":

import pytz, datetime
local = pytz.timezone ("America/Los_Angeles")
naive = datetime.datetime.strptime ("2001-2-3 10:11:12", "%Y-%m-%d %H:%M:%S")
local_dt = local.localize(naive, is_dst=None)
utc_dt = local_dt.astimezone(pytz.utc)

Da lì, è possibile utilizzare il strftime()metodo per formattare il datetime UTC secondo necessità:

utc_dt.strftime ("%Y-%m-%d %H:%M:%S")

7
Modifica la tua risposta con il seguente codice: [code] local.localize (naive) [/ code] Vedi il documento: link Sfortunatamente l'utilizzo dell'argomento tzinfo dei costruttori di datetime standard '' non funziona '' con pytz per molti fusi orari. >>> datetime (2002, 10, 27, 12, 0, 0, tzinfo = amsterdam) .strftime (fmt) '2002-10-27 12:00:00 AMT + 0020'
Sam Stoelinga

2
Apparentemente il passaggio "capire qual è il fuso orario locale" si rivela più difficile di quanto sembri (praticamente impossibile).
Jason R. Coombs,

2
Usa local.localize come suggerito da @SamStoelinga, altrimenti non prenderai in considerazione l'ora legale.
Emil Stenström,

Questa risposta mi è stata molto utile, ma vorrei sottolineare una trappola che ho riscontrato. Se si fornisce l'ora ma non la data, è possibile ottenere risultati imprevisti. Quindi assicurati di fornire un timestamp completo.
Steven Mercatante,


145

La funzione utcnow () del modulo datetime può essere utilizzata per ottenere l'ora UTC corrente.

>>> import datetime
>>> utc_datetime = datetime.datetime.utcnow()
>>> utc_datetime.strftime("%Y-%m-%d %H:%M:%S")
'2010-02-01 06:59:19'

Come dice il link sopra citato da Tom: http://lucumr.pocoo.org/2011/7/15/eppur-si-muove/ dice:

UTC è un fuso orario senza ora legale e ancora un fuso orario senza modifiche alla configurazione in passato.

Misura e memorizza sempre l'ora in UTC .

Se è necessario registrare dove è stato impiegato il tempo, archiviarlo separatamente. Non memorizzare l'ora locale + le informazioni sul fuso orario!

NOTA - Se uno qualsiasi dei tuoi dati si trova in una regione che utilizza l'ora legale, usa pytze dai un'occhiata alla risposta di John Millikin.

Se si desidera ottenere l'ora UTC da una determinata stringa e si è abbastanza fortunati da trovarsi in una regione del mondo che non utilizza l'ora legale o si hanno dati che sono solo sfalsati dall'ora UTC senza che l'ora legale sia applicata:

-> utilizzando l'ora locale come base per il valore di offset:

>>> # Obtain the UTC Offset for the current system:
>>> UTC_OFFSET_TIMEDELTA = datetime.datetime.utcnow() - datetime.datetime.now()
>>> local_datetime = datetime.datetime.strptime("2008-09-17 14:04:00", "%Y-%m-%d %H:%M:%S")
>>> result_utc_datetime = local_datetime + UTC_OFFSET_TIMEDELTA
>>> result_utc_datetime.strftime("%Y-%m-%d %H:%M:%S")
'2008-09-17 04:04:00'

-> Oppure, da un offset noto, utilizzando datetime.timedelta ():

>>> UTC_OFFSET = 10
>>> result_utc_datetime = local_datetime - datetime.timedelta(hours=UTC_OFFSET)
>>> result_utc_datetime.strftime("%Y-%m-%d %H:%M:%S")
'2008-09-17 04:04:00'

AGGIORNARE:

Da Python 3.2 datetime.timezone è disponibile. È possibile generare un oggetto datetime sensibile al fuso orario con il comando seguente:

import datetime

timezone_aware_dt = datetime.datetime.now(datetime.timezone.utc)

Se sei pronto ad accettare conversioni di fuso orario, leggi questo:

https://medium.com/@eleroy/10-things-you-need-to-know-about-date-and-time-in-python-with-datetime-pytz-dateutil-timedelta-309bfbafb3f7


14
Questo converte solo l'ora corrente, ho bisogno di prendere un determinato momento (come una stringa) e convertire in UTC.
Tom,

Non penso che dovrebbe importare qui, se usi valori offset standard. local_time = utc_time + utc_offset AND utc_time = local_time - utc_offset.
Monaco

5
Funziona solo con l'ora corrente perché i timestamp passati e futuri potrebbero avere un offset UTC diverso a causa dell'ora legale.
Alex B,

buon punto ... se hai a che fare con l'ora legale dovresti probabilmente usare pytz come menzionato da John Millikin.
Monaco

1
C'è un delta sporadico tra le chiamate a utcnow () e now (). Questa è una riga di codice pericolosa che potrebbe portare a strani errori in seguito, come tzinfo.utcoffset() must return a whole number of minutese così via.
Pavel Vlasov,

62

Grazie @rofly, la conversione completa da stringa a stringa è la seguente:

time.strftime("%Y-%m-%d %H:%M:%S", 
              time.gmtime(time.mktime(time.strptime("2008-09-17 14:04:00", 
                                                    "%Y-%m-%d %H:%M:%S"))))

Il mio riepilogo delle funzioni time/ calendar:

time.strptime
stringa -> tupla (nessun fuso orario applicato, quindi corrisponde a stringa)

time.mktime
tupla dell'ora locale -> secondi dall'epoca (sempre ora locale)

time.gmtime
secondi dall'epoca -> tupla in UTC

e

calendar.timegm
tupla in UTC -> secondi dall'epoca

time.localtime
secondi dall'epoca -> tupla nel fuso orario locale


4
(always local time)sembra essere sbagliato: l'input di mktime () è l'ora locale, l'output è di secondi dall'epoca ( 1970-01-01 00:00:00 +0000 (UTC)) che non dipende dal fuso orario.
jfs

3
Inoltre, vi è il 50% di probabilità che fallisca durante la transizione DST. Vedi Problemi con Localtime
jfs

38

Ecco un riepilogo delle comuni conversioni temporali di Python.

Alcuni metodi rilasciano frazioni di secondi e sono contrassegnati con (s) . È ts = (d - epoch) / unitinvece possibile utilizzare una formula esplicita come (grazie a jfs).

  • struct_time (UTC) → POSIX (s) :
    calendar.timegm(struct_time)
  • Datetime naïve (locale) → POSIX (s) :
    calendar.timegm(stz.localize(dt, is_dst=None).utctimetuple())
    (eccezione durante le transizioni DST, vedi commento da jfs)
  • Datetime naïve (UTC) → POSIX (s) :
    calendar.timegm(dt.utctimetuple())
  • Datetime consapevoli → POSIX (s) :
    calendar.timegm(dt.utctimetuple())
  • POSIX → struct_time (UTC, s ):
    time.gmtime(t)
    (vedi commento da jfs)
  • Datetime naïve (locale) → struct_time (UTC, s ):
    stz.localize(dt, is_dst=None).utctimetuple()
    (eccezione durante le transizioni DST, vedi commento da jfs)
  • Datetime naïve (UTC) → struct_time (UTC, s ):
    dt.utctimetuple()
  • Datetime consapevole → struct_time (UTC, s ):
    dt.utctimetuple()
  • POSIX → Datetime naïve (locale):
    datetime.fromtimestamp(t, None)
    (potrebbe non riuscire in determinate condizioni, vedere il commento da jfs in basso)
  • struct_time (UTC) → Naïve datetime (local, s ):
    datetime.datetime(struct_time[:6], tzinfo=UTC).astimezone(tz).replace(tzinfo=None)
    (non può rappresentare secondi bisestili, vedi commento da jfs)
  • Datetime naïve (UTC) → Datetime naïve (locale):
    dt.replace(tzinfo=UTC).astimezone(tz).replace(tzinfo=None)
  • Datetime consapevole → Datetime naïve (locale):
    dt.astimezone(tz).replace(tzinfo=None)
  • POSIX → Naïve datetime (UTC):
    datetime.utcfromtimestamp(t)
  • struct_time (UTC) → Naïve datetime (UTC, s ):
    datetime.datetime(*struct_time[:6])
    (non può rappresentare secondi bisestili, vedi commento da jfs)
  • Naïve datetime (local) → Naïve datetime (UTC):
    stz.localize(dt, is_dst=None).astimezone(UTC).replace(tzinfo=None)
    (eccezione durante le transizioni DST, vedi commento da jfs)
  • Datetime consapevole → Datetime naïve (UTC):
    dt.astimezone(UTC).replace(tzinfo=None)
  • POSIX → Aetime datetime:
    datetime.fromtimestamp(t, tz)
    (potrebbe non riuscire per i fusi orari non pytz)
  • struct_time (UTC) → Datetime (s) consapevole :
    datetime.datetime(struct_time[:6], tzinfo=UTC).astimezone(tz)
    (non può rappresentare secondi bisestili, vedi commento da jfs)
  • Datetime naïve (locale) → Datetime consapevole:
    stz.localize(dt, is_dst=None)
    (eccezione durante le transizioni DST, vedi commento da jfs)
  • Datetime naïve (UTC) → Datetime consapevole:
    dt.replace(tzinfo=UTC)

Fonte: taaviburns.ca


1
(1) fromtimestamp(t, None)potrebbe non funzionare se il fuso orario locale aveva un offset utc diverso su t e la libreria C non ha accesso al database tz sulla piattaforma data. È possibile utilizzare tzlocal.get_localzone()per fornire tzdata in modo portatile. (2) fromtimestamp(t, tz)potrebbe non funzionare con fusi orari non pytz. (3) datetime(*struct_time[:6])ti manca *. (4) timegm(), utctimetuple(), struct_timesoluzioni basate goccia frazioni di secondo. È possibile utilizzare una formula esplicita come: ts = (d - epoch) / unitinvece.
jfs,

1
(5) stz.localize(dt, is_dst=None)solleva un'eccezione per orari locali ambigui o inesistenti, ad esempio durante le transizioni di ora legale. Per evitare l'eccezione, utilizzare stz.normalize(stz.localize(dt))ciò può restituire risultati imprecisi. (6) datetime () non può rappresentare un secondo bisestile. Converti struct_timein "secondi dall'epoca" come soluzione alternativa prima. (7) a time.gmtime(t)differenza di quanto calendar.timegm()potrebbe aspettarsi un input non POSIX se si utilizza il fuso orario "giusto". Utilizzare invece la formula esplicita se l'input è POSIX:gmtime = lambda t: datetime(1970,1,1, tzinfo=utc) + timedelta(seconds=t)
jfs

vorrei che fosse in una tabella, più facile da leggere (è nel link)
MichaelChirico

1
@MichaelChirico, questa risposta afferma che "Non (e non) permetteremo i <table>tag. Ci dispiace. Questo è intenzionale e di progettazione. Se hai bisogno di una" tabella "veloce e sporca, usa <pre>e layout ASCII." Non credo che una tabella ASCII sarebbe più leggibile dell'elenco sopra.
Akaihola,

bene questo è sfortunato. hai comunque il mio voto ... forse fai riferimento alla tabella nel link all'interno della tua risposta?
MichaelChirico,

25
def local_to_utc(t):
    secs = time.mktime(t)
    return time.gmtime(secs)

def utc_to_local(t):
    secs = calendar.timegm(t)
    return time.localtime(secs)

Fonte: http://feihonghsu.blogspot.com/2008/02/converting-from-local-time-to-utc.html

Esempio di utilizzo da bd808 : se l'origine è un datetime.datetimeoggetto t, chiama come:

local_to_utc(t.timetuple())

5
Se l'origine è un oggetto datetime.datetime t, chiama come: local_to_utc (t.timetuple ())
bd808

2
.timetuple()la chiamata si imposta tm_isdstsu -1; c'è una probabilità del 50% di mktime()fallire durante la transizione dell'ora legale.
jfs

1
La soluzione di Chuck perde informazioni in millisecondi.
Luca,

21

Sto avendo fortuna con dateutil (che è ampiamente raccomandato su SO per altre domande correlate):

from datetime import *
from dateutil import *
from dateutil.tz import *

# METHOD 1: Hardcode zones:
utc_zone = tz.gettz('UTC')
local_zone = tz.gettz('America/Chicago')
# METHOD 2: Auto-detect zones:
utc_zone = tz.tzutc()
local_zone = tz.tzlocal()

# Convert time string to datetime
local_time = datetime.strptime("2008-09-17 14:02:00", '%Y-%m-%d %H:%M:%S')

# Tell the datetime object that it's in local time zone since 
# datetime objects are 'naive' by default
local_time = local_time.replace(tzinfo=local_zone)
# Convert time to UTC
utc_time = local_time.astimezone(utc_zone)
# Generate UTC time string
utc_string = utc_time.strftime('%Y-%m-%d %H:%M:%S')

(Il codice è stato derivato da questa risposta per convertire la stringa datetime UTC in datetime locale )


dateutilpuò fallire per le date passate se il fuso orario locale aveva un offset utc diverso da quello (non correlato alle transizioni dell'ora legale) su sistemi in cui l'implementazione non utilizza un database di fuso orario storico (in particolare Windows). pytz+ tzlocalpotrebbe essere usato invece.
jfs,

@ JFSebastian- Non ne avevo sentito parlare- dove possiamo ottenere maggiori informazioni?
Yarin,

prendi la macchina Windows, imposta qualsiasi fuso orario che ha avuto un diverso offset utc in passato, ad esempio Europa / Mosca. Confronta i risultati con pytz . Inoltre, potresti provare questo errore che fallisce anche su Ubuntu anche se in questo caso non sono sicuro del corretto utilizzo dell'API.
jfs,

Qual è l'output? Si prega di inviare l'output.
not2qubit

18

Un altro esempio con pytz, ma include localize (), che mi ha salvato la giornata.

import pytz, datetime
utc = pytz.utc
fmt = '%Y-%m-%d %H:%M:%S'
amsterdam = pytz.timezone('Europe/Amsterdam')

dt = datetime.datetime.strptime("2012-04-06 10:00:00", fmt)
am_dt = amsterdam.localize(dt)
print am_dt.astimezone(utc).strftime(fmt)
'2012-04-06 08:00:00'


7
import time

import datetime

def Local2UTC(LocalTime):

    EpochSecond = time.mktime(LocalTime.timetuple())
    utcTime = datetime.datetime.utcfromtimestamp(EpochSecond)

    return utcTime

>>> LocalTime = datetime.datetime.now()

>>> UTCTime = Local2UTC(LocalTime)

>>> LocalTime.ctime()

'Thu Feb  3 22:33:46 2011'

>>> UTCTime.ctime()

'Fri Feb  4 05:33:46 2011'

mktime(dt.timetuple())può fallire durante la transizione DST . C'è LocalTimezonenei documenti (funziona per la definizione del fuso orario più recente ma può fallire per le date passate (non correlata
jfs

5

se preferisci datetime.datetime:

dt = datetime.strptime("2008-09-17 14:04:00","%Y-%m-%d %H:%M:%S")
utc_struct_time = time.gmtime(time.mktime(dt.timetuple()))
utc_dt = datetime.fromtimestamp(time.mktime(utc_struct_time))
print dt.strftime("%Y-%m-%d %H:%M:%S")

1
Certo, ma non riesco a capire perché lo preferiresti. Richiede un'importazione extra e 3 chiamate di funzione in più rispetto alla mia versione ...
Tom

% Z e% z stampa spazi bianchi fermi.
Pavel Vlasov,

2
non è corretto Non riesce se il fuso orario locale non è UTC. mktime()si aspetta l'ora locale come input. fromtimestamp()ritorna l'ora locale, non utc. Se lo risolvi, vedi questi problemi aggiuntivi (come dateutil, la soluzione solo stdlib potrebbe non riuscire)
jfs

5

Semplice

L'ho fatto così:

>>> utc_delta = datetime.utcnow()-datetime.now()
>>> utc_time = datetime(2008, 9, 17, 14, 2, 0) + utc_delta
>>> print(utc_time)
2008-09-17 19:01:59.999996

Implementazione operata

Se vuoi essere sofisticato, puoi trasformarlo in un funzione:

class to_utc():
    utc_delta = datetime.utcnow() - datetime.now()

    def __call__(cls, t):
        return t + cls.utc_delta

Risultato:

>>> utc_converter = to_utc()
>>> print(utc_converter(datetime(2008, 9, 17, 14, 2, 0)))
2008-09-17 19:01:59.999996

5
questo non funziona per l'ora legale, ad es. se è attualmente in estate e la data che stai convertendo è in inverno. e la domanda riguardava la conversione delle date memorizzate come stringhe ...
Tom

1
FYI. Il problema più grande con questo metodo (oltre all'ora legale) sono i pochi millisecondi in cui il delta sarà spento. Tutti i miei inviti di calendario vengono visualizzati come disattivati ​​di 1 minuto.
Nostalg.io,

4

Puoi farlo con:

>>> from time import strftime, gmtime, localtime
>>> strftime('%H:%M:%S', gmtime()) #UTC time
>>> strftime('%H:%M:%S', localtime()) # localtime

3

Che ne dite di -

time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(seconds))

se secondi sono Noneallora converte l'ora locale in ora UTC altrimenti converte l'ora passata in UTC.


2

Per spostarsi nell'ora legale, ecc.

Nessuna delle risposte sopra mi ha particolarmente aiutato. Il codice seguente funziona per GMT.

def get_utc_from_local(date_time, local_tz=None):
    assert date_time.__class__.__name__ == 'datetime'
    if local_tz is None:
        local_tz = pytz.timezone(settings.TIME_ZONE) # Django eg, "Europe/London"
    local_time = local_tz.normalize(local_tz.localize(date_time))
    return local_time.astimezone(pytz.utc)

import pytz
from datetime import datetime

summer_11_am = datetime(2011, 7, 1, 11)
get_utc_from_local(summer_11_am)
>>>datetime.datetime(2011, 7, 1, 10, 0, tzinfo=<UTC>)

winter_11_am = datetime(2011, 11, 11, 11)
get_utc_from_local(winter_11_am)
>>>datetime.datetime(2011, 11, 11, 11, 0, tzinfo=<UTC>)

2

Utilizzando http://crsmithdev.com/arrow/

arrowObj = arrow.Arrow.strptime('2017-02-20 10:00:00', '%Y-%m-%d %H:%M:%S' , 'US/Eastern')

arrowObj.to('UTC') or arrowObj.to('local') 

Questa libreria semplifica la vita :)


arrow is awesome: arrow.get (datetime.now (), 'local'). to ('utc'). naive
SteveJ

1

Ho trovato la risposta migliore su un'altra domanda qui . Utilizza solo librerie integrate in Python e non richiede di inserire il fuso orario locale (un requisito nel mio caso)

import time
import calendar

local_time = time.strptime("2018-12-13T09:32:00.000", "%Y-%m-%dT%H:%M:%S.%f")
local_seconds = time.mktime(local_time)
utc_time = time.gmtime(local_seconds)

Sto ripubblicando la risposta qui poiché questa domanda viene visualizzata in Google anziché nella domanda collegata a seconda delle parole chiave di ricerca.


1

Ho questo codice in uno dei miei progetti:

from datetime import datetime
## datetime.timezone works in newer versions of python
try:
    from datetime import timezone
    utc_tz = timezone.utc
except:
    import pytz
    utc_tz = pytz.utc

def _to_utc_date_string(ts):
    # type (Union[date,datetime]]) -> str
    """coerce datetimes to UTC (assume localtime if nothing is given)"""
    if (isinstance(ts, datetime)):
        try:
            ## in python 3.6 and higher, ts.astimezone() will assume a
            ## naive timestamp is localtime (and so do we)
            ts = ts.astimezone(utc_tz)
        except:
            ## in python 2.7 and 3.5, ts.astimezone() will fail on
            ## naive timestamps, but we'd like to assume they are
            ## localtime
            import tzlocal
            ts = tzlocal.get_localzone().localize(ts).astimezone(utc_tz)
    return ts.strftime("%Y%m%dT%H%M%SZ")

0

In python3:

pip install python-dateutil

from dateutil.parser import tz

mydt.astimezone(tz.gettz('UTC')).replace(tzinfo=None) 

questo sembra non funzionare, genera un'eccezione ValueError: ValueError: astimezone () non può essere applicato a un datetime ingenuo
Stormsson,

Dovrebbe essere: from dateutil import tz
Javier

-3

Che ne dite di -

time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(seconds))

se secondi sono Noneallora converte l'ora locale in ora UTC altrimenti converte l'ora passata in UTC.


1
Questo non aiuta, la domanda era convertire una determinata stringa di ora locale in una stringa di utc.
Tom,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.