Converter data e hora python em época com strftime

209

Eu tenho um horário no UTC no qual desejo o número de segundos desde a época.

Estou usando o strftime para convertê-lo para o número de segundos. Tomando 1 de abril de 2012 como exemplo.

>>>datetime.datetime(2012,04,01,0,0).strftime('%s')
'1333234800'

Em 1º de abril de 2012, o UTC da época é 1333238400, mas isso retorna 1333234800, que é diferente em 1 hora.

Parece que o strftime está levando em consideração o horário do meu sistema e aplica uma mudança de fuso horário em algum lugar. Eu pensei que o horário era puramente ingênuo?

Como posso contornar isso? Se possível, evite importar outras bibliotecas, a menos que seja padrão. (Tenho preocupações de portabilidade).

Noel
fonte
11
Eu sou o único a notar que você usa literais octais nos números?
Fish Monitor
3
O Python mais recente 3.3 ou superior temdatetime.datetime.timestamp(datetime.datetime.utcnow())
MarkHu

Respostas:

389

Se você deseja converter um datetime de python em segundos desde a época, você pode fazê-lo explicitamente:

>>> (datetime.datetime(2012,04,01,0,0) - datetime.datetime(1970,1,1)).total_seconds()
1333238400.0

No Python 3.3 ou superior, você pode usar timestamp():

>>> datetime.datetime(2012,4,1,0,0).timestamp()
1333234800.0

Por que você não deve usar datetime.strftime('%s')

Na verdade, o Python não suporta% s como argumento para strftime (se você verificar em http://docs.python.org/library/datetime.html#strftime-and-strptime-behavior não está na lista), o único A razão pela qual está funcionando é porque o Python está passando as informações para o strftime do seu sistema, que usa o fuso horário local.

>>> datetime.datetime(2012,04,01,0,0).strftime('%s')
'1333234800'
jleahy
fonte
7
Eu tenho enlouquecido tentando descobrir por que vejo muito o strftime ("% s"), mas isso não está nos documentos. Obrigado por nada disso!
Jonathan Vanasco 02/07
54
não use .strftime("%s"): não é suportado, não é portátil, pode produzir silenciosamente um resultado errado para um objeto de data e hora consciente, falha se a entrada estiver no UTC (como na pergunta), mas o fuso horário local não for UTC
jfs
2
@earthmeLon Seu bracketing está errado. Timedeltas (feitas subtraindo duas datas) têm total_seconds, mas as datas não.
Jleahy
2
Isto não está funcionando para mim:AttributeError: 'datetime.timedelta' object has no attribute 'total_seconds'
Michael
3
@ Michael Essa função é nova no Python 2.7, você deve estar usando uma versão mais antiga. Para versões anteriores à 2.7, você pode fazer td.seconds + td.days*24*3600. Isso descarta a parte de microssegundos.
jleahy
100

Eu tive problemas sérios com fusos horários e tal. A maneira como o Python lida com tudo o que acontece é bastante confuso (para mim). As coisas parecem estar funcionando bem usando o módulo de calendário (consulte os links 1 , 2 , 3 e 4 ).

>>> import datetime
>>> import calendar
>>> aprilFirst=datetime.datetime(2012, 04, 01, 0, 0)
>>> calendar.timegm(aprilFirst.timetuple())
1333238400
BorrajaX
fonte
7
+1 porque é a única resposta que funciona para a entrada na pergunta.
JFS
isso é portátil?
benjaminz
1
Isso deve ser marcado como a resposta correta, pois responde à preocupação em questão. parabéns vnice
Leo Prince
2
Isso 'funciona', mas observe a pergunta: "Eu tenho um horário no UTC" Este método sempre usará o fuso horário local do sistema. Não há como especificar um fuso horário. Se aprilFirstneste exemplo fosse uma instância 'consciente' e usasse um fuso horário diferente do fuso horário do sistema, o resultado não seria correto (o fuso horário é perdido na timetuple()chamada). Para obter a resposta certa para um período de tempo "consciente", você pode usar o awaredt.timestamp()recente Python 3. Para o Python 2, é mais difícil; Uma maneira é usar a arrowbiblioteca. arrow.get(awaredt).timestampvai acertar.
Adam Williamson
1
Bom ponto, @AdamWilliamson, mas o código no exemplo não está localizando o datetimeobjeto, então presumi que o "eu tenho um horário no UTC" significava que o OP tinha um datetimeobjeto inconsciente que se supunha estar no UTC para o qual ele queria obter um epoch(se por datetimeacaso estiver ciente de TZ, isso pode realmente mudar as coisas). Além disso, mantenha em mente que esta resposta é quase 8 anos de idade e um monte de coisas aconteceram desde ( arrowfoi lançado em 2013, por exemplo)
BorrajaX
35
import time
from datetime import datetime
now = datetime.now()

time.mktime(now.timetuple())
srossross
fonte
1
é uma maneira incorreta de escrever time.time()( mktime()pode falhar durante as transições de horário de verão enquanto time.time()continua a funcionar). E não responde à pergunta, a menos que o fuso horário local seja UTC (a entrada na pergunta está em UTC). Mesmo que a entrada represente um horário local, mktime()também poderá falhar em datas passadas / futuras se não usar o banco de dados tz e se o fuso horário local puder ter desvios de utc diferentes ao longo dos anos, por exemplo, Europa / Moscou em 2010-2015 - - use a hora UTC (como na pergunta) ou os objetos de data e hora com reconhecimento de fuso horário.
jfs
aqui estão mais problemas com a conversão de um horário local (como retornado por .now()) para carimbo de data / hora da época (retornado por mktime()) . Se você ler; você entende porque UTC entrada (usado na pergunta) é (muito) mais preferível do que um objeto datetime ingênuo representando hora local
JFS
14
import time
from datetime import datetime
now = datetime.now()

# same as above except keeps microseconds
time.mktime(now.timetuple()) + now.microsecond * 1e-6

(Desculpe, não me deixe comentar sobre a resposta existente)

Charles Plager
fonte
Isso porque o time.mktime não leva em consideração a parte do microssegundo, certo?
Eduardo
1
Corrigir. A estrutura da tupla de tempo (com base no suporte C) não tem espaço para microssegundos; portanto, precisamos pegar as informações do objeto datetime e adicioná-las no final.
Charles Plager
Nas minhas máquinas, isso funciona corretamente, mesmo que meu fuso horário seja ET.
Charles Plager
1
Isso fornecerá diferentes carimbos de data e hora em diferentes sistemas, com base na hora local do sistema.
Yousaf
6

se você só precisa de um carimbo de data / hora no horário unix / época, esta linha funciona:

created_timestamp = int((datetime.datetime.now() - datetime.datetime(1970,1,1)).total_seconds())
>>> created_timestamp
1522942073L

e depende apenas de datetime trabalhos em python2 e python3

Marc Maxmeister
fonte
2

Isso funciona no Python 2 e 3:

>>> import time
>>> import calendar
>>> calendar.timegm(time.gmtime())
1504917998

Apenas seguindo os documentos oficiais ... https://docs.python.org/2/library/time.html#module-time

Luis Pollo
fonte
1) Isso pressupõe que você deseja converter agora, não um objeto de data e hora aleatório. 2) Você não precisa de calendário. time.mktime (randomDateTime.timetuple ()) + randomDateTime.microsecond * 1e-6
Charles Plager
@CharlesPlager time.mktime está incorreto; ele interpreta o argumento no fuso horário local, enquanto o OP deseja que o horário seja interpretado no UTC (como calendar.timegm).
stewbasic
Essa é a resposta mais precisa para mim, se você deseja converter seu tempo no GMT e deseja mantê-lo dessa maneira na conversão para o carimbo de data / hora da época.
Yousaf
Apenas seguindo sua resposta, calendar.timegm (datetime.strptime ("2019-05-03T05: 40: 09.770494 + 00: 00" [: 16], '% Y-% m-% dT% H:% M'). scheduleuple ()) Eu tenho carimbo de data / hora no utc e não importa em que sistema você execute, ele me fornece o carimbo de data e hora correto, o truque é usar strptime.timetumple #
Yousaf
2

Para uma solução explícita e independente do fuso horário, use a biblioteca pytz.

import datetime
import pytz

pytz.utc.localize(datetime.datetime(2012,4,1,0,0), is_dst=False).timestamp()

Saída (flutuante): 1333238400.0

Moobie
fonte
vi uma resposta semelhante em stackoverflow.com/a/21145908/4355695 , mas essa como uma linha é ótima para o meu caso de uso em que os dados recebidos estão no UTC e apenas .timestamp () estava assumindo que estava na hora local .
9609 Nikhil VJ #
Isso funciona para datas inferiores a 1970. Obrigado. A resposta aceita não funciona para datas inferiores a 1970. (Python 3.7.3 Anaconda3 de 64 bits)
canbax
-1

No Python 3.7

Retorne um datetime correspondente a um date_string em um dos formatos emitidos por date.isoformat () e datetime.isoformat (). Especificamente, essa função suporta seqüências de caracteres no (s) formato (s) AAAA-MM-DD [* HH [: MM [: SS [.fff [fff]]]] [+ HH: MM [: SS [.ffffff]]]] , onde * pode corresponder a qualquer caractere único.

https://docs.python.org/3/library/datetime.html#datetime.datetime.fromisoformat

Super Nova
fonte
1
Esteja ciente de que isso foi introduzido no Python 3.7.
21419 Keithpjolley