Jeg arbeider med datoer i Python, og jeg må konvertere dem til UTC-tidsstempler som skal brukes inne i Javascript. Følgende kode fungerer ikke:
>>> d = datetime.date(2011,01,01)
>>> datetime.datetime.utcfromtimestamp(time.mktime(d.timetuple()))
datetime.datetime(2010, 12, 31, 23, 0)
Det hjelper heller ikke å konvertere date-objektet først til datetime. Jeg prøvde eksemplet på dette link fra, men:
from pytz import utc, timezone
from datetime import datetime
from time import mktime
input_date = datetime(year=2011, month=1, day=15)
og nå heller ikke:
mktime(utc.localize(input_date).utctimetuple())
eller
mktime(timezone('US/Eastern').localize(input_date).utctimetuple())
fungerer.
Så generelt spørsmål: hvordan kan jeg få en dato konvertert til sekunder siden epoke i henhold til UTC?
Hvis d = date(2011, 1, 1)
er i UTC:
>>> from datetime import datetime, date
>>> import calendar
>>> timestamp1 = calendar.timegm(d.timetuple())
>>> datetime.utcfromtimestamp(timestamp1)
datetime.datetime(2011, 1, 1, 0, 0)
Hvis d
er i lokal tidssone:
>>> 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
og timestamp2
kan avvike hvis midnatt i lokal tidssone ikke er samme tidsinstans som midnatt i UTC.
mktime()
kan returnere et feil resultat hvis d
tilsvarer en tvetydig lokal tid (f.eks. ved overgang til sommertid) eller hvis d
er en tidligere(fremtidig) dato når utc-offset kan ha vært annerledes og C mktime()
ikke har tilgang til tz-databasen på den gitte plattformen. Du kan bruke modulen pytz
(f.eks. via tzlocal.get_localzone()
) for å få tilgang til tz-databasen på alle plattformer. Også utcfromtimestamp()
kan feile og mktime()
kan returnere ikke-POSIX-tidsstempel hvis "right"
tidssone brukes.
For å konvertere datetime.date
-objekt som representerer dato i UTC uten 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
For å konvertere datetime.datetime
-objektet (ikke datetime.date
) som allerede representerer tid i UTC til det tilsvarende POSIX-tidsstempelet (en float
).
Python 3.3+ ### Python 3.3
from datetime import timezone
timestamp = dt.replace(tzinfo=timezone.utc).timestamp()
Merk: Det er nødvendig å angi timezone.utc
eksplisitt, ellers antar .timestamp()
at det naive datetime-objektet er i lokal tidssone.
Fra dokumentasjonen for datetime.utcfromtimestamp()
:
Det finnes ingen metode for å hente tidsstempelet fra en datetime-instans, men POSIX-tidsstempel som svarer til en datetime-instans dt, kan enkelt beregnes som følger. For en naiv dt:
timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)
Og for en bevisst dt:
timestamp = (dt - datetime(1970,1,1, tzinfo=timezone.utc)) / timedelta(seconds=1)
Interessant lesning: Epoch time vs. time of day om forskjellen mellom Hva er klokka? og Hvor mange sekunder har gått?
Se også: datetime trenger en "epoch" metode
For å tilpasse koden ovenfor for Python 2:
timestamp = (dt - datetime(1970, 1, 1)).total_seconds()
der timedelta.total_seconds()
tilsvarer (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
beregnet med sann divisjon aktivert.
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)
Se opp for problemer med flyttall.
2012-01-08 15:34:10.022403
1326036850.02
datetime
-objekt til POSIX-tidsstempelassert dt.tzinfo is not None and dt.utcoffset() is not None
timestamp = dt.timestamp() # Python 3.3+
På 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)
På 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()
Forutsetning 1: Du prøver å konvertere en dato til et tidsstempel, men siden en dato dekker en periode på 24 timer, finnes det ikke et enkelt tidsstempel som representerer den datoen. Jeg antar at du vil representere tidsstempelet for den datoen ved midnatt (00:00:00.000).
Forutsetning 2:** Datoen du presenterer er ikke knyttet til en bestemt tidssone, men du ønsker å bestemme forskyvningen fra en bestemt tidssone (UTC). Uten å vite hvilken tidssone datoen er i, er det ikke mulig å beregne et tidsstempel for en bestemt tidssone. Jeg antar at du vil behandle datoen som om den er i det lokale systemets tidssone.
Først kan du konvertere datoforekomsten til en tupel som representerer de ulike tidskomponentene ved hjelp av timetuple()
-elementet:
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)
Du kan deretter konvertere det til et tidsstempel ved hjelp av time.mktime
:
ts = time.mktime(dtt) # 1293868800.0
Du kan verifisere denne metoden ved å teste den med selve epoketiden (1970-01-01), i hvilket tilfelle funksjonen skal returnere tidssoneforskyvningen for den lokale tidssonen på den datoen:
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
er 8 timer, noe som vil være riktig for tidssonen i Stillehavet (der jeg befinner meg).
En komplett tidsstreng inneholder:
[+HHMM eller -HHMM]
.For eksempel
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
Note:
UNIX timestamp
er et flyttall uttrykt i sekunder siden epoken, i UTC.
Rediger:
$ 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