Estou lidando com datas em Python e preciso convertê-las para carimbos de tempo UTC para serem usadas dentro do Javascript. O seguinte código não funciona:
>>> d = datetime.date(2011,01,01)
>>> datetime.datetime.utcfromtimestamp(time.mktime(d.timetuple()))
datetime.datetime(2010, 12, 31, 23, 0)
A conversão do objeto de data primeiro para data também não ajuda. Eu tentei o exemplo neste link de, mas:
from pytz import utc, timezone
from datetime import datetime
from time import mktime
input_date = datetime(year=2011, month=1, day=15)
e agora também não:
mktime(utc.localize(input_date).utctimetuple())
ou
mktime(timezone('US/Eastern').localize(input_date).utctimetuple())
funciona mesmo.
Pergunta geral: como posso ter uma data convertida em segundos desde a época, de acordo com o UTC?
Se d = data(2011, 1, 1)
estiver em UTC:
>>> from datetime import datetime, date
>>> import calendar
>>> timestamp1 = calendar.timegm(d.timetuple())
>>> datetime.utcfromtimestamp(timestamp1)
datetime.datetime(2011, 1, 1, 0, 0)
Se o d
estiver no fuso horário local:
>>> import time
>>> timestamp2 = time.mktime(d.timetuple()) # DO NOT USE IT WITH UTC DATE
>>> datetime.fromtimestamp(timestamp2)
datetime.datetime(2011, 1, 1, 0, 0)
O "timestamp1" e o "timestamp2" podem diferir se a meia-noite no fuso horário local não for a mesma hora que a meia-noite no UTC.
mktime()
pode retornar um resultado errado se d
corresponder a uma hora local ambígua (por exemplo, durante a transição DST) ou se d
for uma data passada(futura) quando o offset utc pode ter sido diferente e o C mktime()
não tem acesso ao banco de dados tz na plataforma em questão. Você poderia utilizar o módulo pytz
(por exemplo, via tzlocal.get_localzone()
) para ter acesso ao banco de dados tz em todas as plataformas. Além disso, utcfromtimestamp()
pode falhar e mktime()
pode retornar um timestamp não-POSIX se "right"
timezone for utilizado.
Para converter o objeto datetime.date
que representa data em UTC sem 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
Para converter o objeto datetime.datetime' (não
datetime.date') que já representa a hora em UTC para o carimbo de tempo POSIX correspondente (um `float').
from datetime import timezone
timestamp = dt.replace(tzinfo=timezone.utc).timestamp()
Nota: É necessário fornecer timezone.utc
explicitamente, caso contrário, .timestamp()
assumir que o seu objeto de data ingênuo está no fuso horário local.
A partir dos documentos para datetime.utcfromtimestamp()
:
Não há nenhum método para obter o carimbo da hora a partir de uma instância de data e hora, mas o carimbo temporal POSIX correspondente a uma instância de data/hora dt pode ser facilmente calculado da seguinte forma. Para um dt. ingénuo:
timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)
E para um dt consciente:
timestamp = (dt - datetime(1970,1,1, tzinfo=timezone.utc)) / timedelta(seconds=1)
Leitura interessante: Epoch time vs. time of day sobre a diferença entre Que horas são? e Quantos segundos se passaram?
Veja também: datatime precisa de um "epoch" método
Para adaptar o código acima para Python 2:
timestamp = (dt - datetime(1970, 1, 1)).total_seconds()
onde timeedelta.total_seconds()
é equivalente a (td.microsegundos + (td.segundos + td.dias * 24 * 3600) * 10**6) / 10**6
calculado com a verdadeira divisão activada.
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)
Cuidado com questões de ponto flutuante.
2012-01-08 15:34:10.022403
1326036850.02
datetime
ciente para o carimbo de tempo POSIXassert dt.tzinfo is not None and dt.utcoffset() is not None
timestamp = dt.timestamp() # Python 3.3+
Em 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)
Em 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()
Assunção 1: Você'está a tentar converter uma data para um carimbo da hora, no entanto como uma data cobre um período de 24 horas, existe't um único carimbo da hora que representa essa data. I'irá assumir que você quer representar o carimbo da hora dessa data à meia-noite (00:00:00.000).
Assunção 2: A data apresentada não está associada a um fuso horário específico, no entanto, você deseja determinar o offset a partir de um fuso horário específico (UTC). Sem saber o fuso horário em que a data está, é'não é possível calcular um carimbo de hora para um fuso horário específico. I'assumirá que você quer tratar a data como se ela estivesse no fuso horário do sistema local.
Primeiro, você pode converter a instância de data em um tuple representando os vários componentes de tempo utilizando o timetuple()
membro:
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)
Você pode então converter isso em um carimbo de tempo utilizando time.mktime
:
ts = time.mktime(dtt) # 1293868800.0
Você pode verificar este método testando-o com a própria hora de época (1970-01-01), neste caso a função deve retornar a compensação de fuso horário para o fuso local naquela 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 horas, o que seria correto para o fuso horário do Pacífico (onde I'm at).
Um tempo completo contém:
[+HHHMM ou -HHHMM]
Por exemplo:
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
é um número de ponto flutuante expresso em segundos desde a época, em **UTC***.
Editar:
$ 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