"Python" programoje dirbu su datomis ir turiu jas konvertuoti į UTC laiko žymes, kad būtų galima naudoti Javascript'e. Toliau pateiktas kodas neveikia:
>>> d = datetime.date(2011,01,01)
>>> datetime.datetime.utcfromtimestamp(time.mktime(d.timetuple()))
datetime.datetime(2010, 12, 31, 23, 0)
Datos objekto konvertavimas iš pradžių į datetime taip pat nepadeda. Išbandžiau pavyzdį, pateiktą šioje nuoroda, bet:
from pytz import utc, timezone
from datetime import datetime
from time import mktime
input_date = datetime(year=2011, month=1, day=15)
ir dabar arba:
mktime(utc.localize(input_date).utctimetuple())
arba
mktime(timezone('US/Eastern').localize(input_date).utctimetuple())
veikia.
Taigi bendras klausimas: kaip gauti datą, konvertuotą į sekundes nuo epochos pagal UTC?
Jei d = data(2011, 1, 1)
yra UTC:
>>> from datetime import datetime, date
>>> import calendar
>>> timestamp1 = calendar.timegm(d.timetuple())
>>> datetime.utcfromtimestamp(timestamp1)
datetime.datetime(2011, 1, 1, 0, 0)
Jei d
yra vietinėje laiko juostoje:
>>> 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
ir Timestamp2
gali skirtis, jei vidurnaktis vietinėje laiko juostoje nėra tas pats laiko atvejis kaip vidurnaktis UTC.
mktime()
gali grąžinti neteisingą rezultatą, jei d
atitinka dviprasmišką vietinį laiką (pvz., pereinamuoju laikotarpiu) arba jei d
yra praeities (ateities) data, kai utc poslinkis galėjo būti kitoks ir C mktime()
neturi prieigos prie tz duomenų bazės tam tikroje platformoje. Galite naudoti pytz
modulį (pvz., per tzlocal.get_localzone()
), kad gautumėte prieigą prie tz duomenų bazės visose platformose. Be to, utcfromtimestamp()
gali nepavykti, o mktime()
gali grąžinti ne POSIX laiko žymą, jei naudojama "right"
laiko juosta.
Konvertuoti datetime.date
objektą, kuris rodo datą UTC, nenaudojant 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
Norint konvertuoti datetime.datetime
(ne datetime.date
) objektą, kuris jau atspindi laiką UTC, į atitinkamą POSIX laiko žymą (float
).
from datetime import timezone
timestamp = dt.replace(tzinfo=timezone.utc).timestamp()
Pastaba: Būtina aiškiai nurodyti timezone.utc
, nes priešingu atveju .timestamp()
laikys, kad jūsų naivus datatime objektas yra vietinėje laiko juostoje.
Iš `datetime.utcfromtimestamp()
dokumentų:
Nėra metodo, kaip gauti laiko žymą iš datetime egzemplioriaus,
tačiau POSIX laiko žymą, atitinkančią datos laiko instanciją dt, galima lengvai apskaičiuoti taip. Naiviam dt:
timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)
O žinančiam dt:
timestamp = (dt - datetime(1970,1,1, tzinfo=timezone.utc)) / timedelta(seconds=1)
Įdomu skaityti: (http://www.ucolick.org/~sla/leapsecs/epochtime.html) apie skirtumą tarp Koks dabar laikas? ir *Kiek sekundžių jau praėjo?
Taip pat žr: datetime reikia "epoch" metodo
Pirmiau pateikto kodo pritaikymas "Python 2":
timestamp = (dt - datetime(1970, 1, 1)).total_seconds()
kur `timedelta.total_seconds()
atitinka (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
, apskaičiuotam su įjungtu tikruoju dalijimu.
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)
Saugokitės slankiojo kablelio problemų.
2012-01-08 15:34:10.022403
1326036850.02
datetime
objektą į POSIX laiko žymąassert dt.tzinfo is not None and dt.utcoffset() is not None
timestamp = dt.timestamp() # Python 3.3+
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)
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()
1-oji prielaida: Bandote konvertuoti datą į laiko žymą, tačiau kadangi data apima 24 valandų laikotarpį, nėra vienos laiko žymos, kuri atspindėtų tą datą. Darysiu prielaidą, kad norite atvaizduoti tos datos vidurnaktį (00:00:00:00.000).
Antroji prielaida: Jūsų pateikta data nėra susijusi su konkrečia laiko juosta, tačiau norite nustatyti poslinkį nuo konkrečios laiko juostos (UTC). Nežinant laiko juostos, kurioje yra data, neįmanoma apskaičiuoti konkrečios laiko juostos laiko žymos. Darysiu prielaidą, kad norite datą traktuoti taip, tarsi ji būtų vietinėje sistemos laiko juostoje.
Pirmiausia, naudodami narį timetuple()
, galite konvertuoti datos egzempliorių į tuple, atspindintį įvairias laiko sudedamąsias dalis:
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)
Tada galite paversti ją laiko žyma, naudodami time.mktime
:
ts = time.mktime(dtt) # 1293868800.0
Šį metodą galite patikrinti išbandydami jį su pačiu epochos laiku (1970-01-01) - tokiu atveju funkcija turėtų grąžinti tos datos vietinės laiko juostos poslinkį:
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
yra 8 valandos, o tai būtų teisinga Ramiojo vandenyno laiko zonai (kur aš esu).
Visą laiko eilutę sudaro:
[+HHMM arba -HHMM]
Pavyzdžiui:
1970-01-01-01 06:00:00 +0500
== 1970-01-01-01 01:00:00 +0000
== UNIX laiko žyma: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
Pastaba:
UNIX timestamp
yra slankiojo kablelio skaičius, išreiškiamas sekundėmis nuo epochos, UTC.
redaguoti:
$ 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