Ho a che fare con le date in Python e ho bisogno di convertirle in timestamp UTC da usare all'interno di Javascript. Il seguente codice non funziona:
>>> d = datetime.date(2011,01,01)
>>> datetime.datetime.utcfromtimestamp(time.mktime(d.timetuple()))
datetime.datetime(2010, 12, 31, 23, 0)
Anche convertire l'oggetto data prima in datetime non aiuta. Ho provato l'esempio a questo link da, ma:
from pytz import utc, timezone
from datetime import datetime
from time import mktime
input_date = datetime(year=2011, month=1, day=15)
e ora o:
mktime(utc.localize(input_date).utctimetuple())
o
mktime(timezone('US/Eastern').localize(input_date).utctimetuple())
funziona.
Quindi domanda generale: come posso ottenere una data convertita in secondi dall'epoca secondo UTC?
Se d = date(2011, 1, 1)
è in UTC:
>>> from datetime import datetime, date
>>> import calendar
>>> timestamp1 = calendar.timegm(d.timetuple())
>>> datetime.utcfromtimestamp(timestamp1)
datetime.datetime(2011, 1, 1, 0, 0)
Se d
è nel fuso orario locale:
>>> import time
>>> timestamp2 = time.mktime(d.timetuple()) # DO NOT USE IT WITH UTC DATE
>>> datetime.fromtimestamp(timestamp2)
datetime.datetime(2011, 1, 1, 0, 0)
timestamp1
e timestamp2
possono differire se la mezzanotte nel fuso orario locale non è la stessa istanza temporale della mezzanotte in UTC.
mktime()
può restituire un risultato sbagliato se d
corrisponde a un tempo locale ambiguo (ad esempio, durante la transizione DST) o se d
è una data passata (futura) quando l'offset utc potrebbe essere stato diverso e il C mktime()
non ha accesso al database tz sulla piattaforma data. Potreste usare il modulo pytz
(ad esempio, tramite tzlocal.get_localzone()
) per avere accesso al database tz su tutte le piattaforme. Inoltre, utcfromtimestamp()
può fallire e mktime()
può restituire un timestamp non-POSIX se viene usato il "right"
timezone.
Per convertire l'oggetto datetime.date
che rappresenta la data in UTC senza calendar.timegm()
:
DAY = 24*60*60 # POSIX day in seconds (exact value)
timestamp = (utc_date.toordinal() - date(1970, 1, 1).toordinal()) * DAY
timestamp = (utc_date - date(1970, 1, 1)).days * DAY
Per convertire l'oggetto datetime.datetime
(non datetime.date
) che rappresenta già il tempo in UTC nel corrispondente timestamp POSIX (un float
).
from datetime import timezone
timestamp = dt.replace(tzinfo=timezone.utc).timestamp()
Nota: è necessario fornire esplicitamente timezone.utc
altrimenti .timestamp()
assume che il tuo oggetto naive datetime sia nel fuso orario locale.
Dalla documentazione per datetime.utcfromtimestamp()
:
Non c'è un metodo per ottenere il timestamp da un'istanza datetime, ma il timestamp POSIX corrispondente a un'istanza datetime dt può essere facilmente calcolato come segue. Per un dt ingenuo:
timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)
E per un dt consapevole:
timestamp = (dt - datetime(1970,1,1, tzinfo=timezone.utc)) / timedelta(seconds=1)
Lettura interessante: Epoch time vs. time of day sulla differenza tra What time is it? e How many seconds have elapsed?
Vedi anche: datetime ha bisogno di un metodo "epoch"
Per adattare il codice di cui sopra per Python 2:
timestamp = (dt - datetime(1970, 1, 1)).total_seconds()
dove timedelta.total_seconds()
è equivalente a (td.microsecondi + (td.secondi + td.giorni * 24 * 3600) * 10**6) / 10**6
calcolato con la divisione vera abilitata.
from __future__ import division
from datetime import datetime, timedelta
def totimestamp(dt, epoch=datetime(1970,1,1)):
td = dt - epoch
# return td.total_seconds()
return (td.microseconds + (td.seconds + td.days * 86400) * 10**6) / 10**6
now = datetime.utcnow()
print now
print totimestamp(now)
Attenzione ai problemi di virgola mobile.
2012-01-08 15:34:10.022403
1326036850.02
datetime
consapevole in un timestamp POSIXassert dt.tzinfo is not None and dt.utcoffset() is not None
timestamp = dt.timestamp() # Python 3.3+
Su Python 3:
from datetime import datetime, timedelta, timezone
epoch = datetime(1970, 1, 1, tzinfo=timezone.utc)
timestamp = (dt - epoch) / timedelta(seconds=1)
integer_timestamp = (dt - epoch) // timedelta(seconds=1)
Su Python 2:
# utc time = local time - utc offset
utc_naive = dt.replace(tzinfo=None) - dt.utcoffset()
timestamp = (utc_naive - datetime(1970, 1, 1)).total_seconds()
Ipotesi 1:** Stai cercando di convertire una data in un timestamp, tuttavia, poiché una data copre un periodo di 24 ore, non esiste un unico timestamp che rappresenti quella data. Presumo che tu voglia rappresentare il timestamp di quella data a mezzanotte (00:00:00.000).
Assunzione 2: La data che presenti non è associata a un particolare fuso orario, tuttavia vuoi determinare l'offset da un particolare fuso orario (UTC). Senza conoscere il fuso orario in cui si trova la data, non è possibile calcolare un timestamp per un fuso orario specifico. Presumo che tu voglia trattare la data come se fosse nel fuso orario del sistema locale.
Per prima cosa, potete convertire l'istanza della data in una tupla che rappresenta i vari componenti del tempo usando il membro timetuple()
:
dtt = d.timetuple() # time.struct_time(tm_year=2011, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=5, tm_yday=1, tm_isdst=-1)
Potete poi convertirla in un timestamp usando time.mktime
:
ts = time.mktime(dtt) # 1293868800.0
Puoi verificare questo metodo testandolo con il tempo epocale stesso (1970-01-01), nel qual caso la funzione dovrebbe restituire l'offset del fuso orario locale in quella data:
d = datetime.date(1970,1,1)
dtt = d.timetuple() # time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=-1)
ts = time.mktime(dtt) # 28800.0
28800.0` è 8 ore, che sarebbe corretto per il fuso orario del Pacifico (dove mi trovo io).
Una stringa temporale completa contiene:
[+HHMM o -HHMM]
Per esempio:
1970-01-01 06:00:00 +0500
== 1970-01-01 01:00:00 +0000
== UNIX timestamp:3600
$ python3
>>> from datetime import datetime
>>> from calendar import timegm
>>> tm = '1970-01-01 06:00:00 +0500'
>>> fmt = '%Y-%m-%d %H:%M:%S %z'
>>> timegm(datetime.strptime(tm, fmt).utctimetuple())
3600
Nota:
UNIX timestamp
è un numero in virgola mobile espresso in secondi dall'epoca, in UTC.
Modifica:
$ python3
>>> from datetime import datetime, timezone, timedelta
>>> from calendar import timegm
>>> dt = datetime(1970, 1, 1, 6, 0)
>>> tz = timezone(timedelta(hours=5))
>>> timegm(dt.replace(tzinfo=tz).utctimetuple())
3600