O que eu preciso fazer
Eu tenho um objeto de data e hora sem reconhecimento de fuso horário, ao qual preciso adicionar um fuso horário para poder compará-lo com outros objetos de data e hora com reconhecimento de fuso horário. Não quero converter todo o meu aplicativo em fuso horário sem conhecer este caso legado.
O que eu tentei
Primeiro, para demonstrar o problema:
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime
>>> import pytz
>>> unaware = datetime.datetime(2011,8,15,8,15,12,0)
>>> unaware
datetime.datetime(2011, 8, 15, 8, 15, 12)
>>> aware = datetime.datetime(2011,8,15,8,15,12,0,pytz.UTC)
>>> aware
datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>)
>>> aware == unaware
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes
Primeiro, tentei o astimezone:
>>> unaware.astimezone(pytz.UTC)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: astimezone() cannot be applied to a naive datetime
>>>
Não é de surpreender que isso tenha falhado, pois está realmente tentando fazer uma conversão. Substituir parecia uma escolha melhor (como em Python: como obter um valor de datetime.today () que é "consciente do fuso horário"? ):
>>> unaware.replace(tzinfo=pytz.UTC)
datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>)
>>> unaware == aware
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes
>>>
Mas, como você pode ver, substituir parece definir o tzinfo, mas não conscientiza o objeto. Estou me preparando para voltar a medicar a string de entrada para ter um fuso horário antes de analisá-la (estou usando o dateutil para análise, se isso importa), mas isso parece incrivelmente desagradável.
Além disso, eu tentei isso no python 2.6 e python 2.7, com os mesmos resultados.
Contexto
Estou escrevendo um analisador para alguns arquivos de dados. Há um formato antigo que preciso oferecer suporte onde a sequência de datas não possui um indicador de fuso horário. Eu já corrigi a fonte de dados, mas ainda preciso oferecer suporte ao formato de dados herdado. Uma conversão única dos dados herdados não é uma opção por vários motivos de negócios da BS. Embora, em geral, eu não goste da ideia de codificar um fuso horário padrão, neste caso, parece a melhor opção. Sei com confiança razoável que todos os dados herdados em questão estão no UTC, portanto, estou preparado para aceitar o risco de não cumprir isso neste caso.
unaware.replace()
retornariaNone
se estivesse modificando ounaware
objeto no local. O REPL mostra que.replace()
retorna um novodatetime
objeto aqui.import datetime; datetime.datetime.now(datetime.timezone.utc)
tz
argumento arg para ser mais legível:datetime.datetime.now(tz=datetime.timezone.utc)
Respostas:
Em geral, para fazer um fuso horário-aware datetime ingênuo, use o método Localize :
Para o fuso horário UTC, não é realmente necessário usar,
localize
pois não há cálculo de horário de verão para lidar com:trabalho. (
.replace
retorna uma nova data e hora; não modificaunaware
.)fonte
aware = datetime(..., tz)
use em.localize()
vez disso.tz.localize(..., is_dst=None)
afirma que não é.Todos esses exemplos usam um módulo externo, mas você pode obter o mesmo resultado usando apenas o módulo datetime, como também apresentado nesta resposta do SO :
Menos dependências e sem problemas de pytz.
NOTA: Se você deseja usá-lo com python3 e python2, também pode usá-lo para a importação de fuso horário (codificado permanentemente para UTC):
fonte
pytz
problemas, fico feliz por ter rolado um pouco! Não queria enfrentar compytz
os meus servidores remotos na verdade :)from datetime import timezone
funciona em py3, mas não py2.7.dt.replace(tzinfo=timezone.utc)
retorna um novo datetime, que não é modificadodt
no local. (Vou editar para mostrar isso).tz = pytz.timezone('America/Chicago')
Eu usei de dt_aware para dt_unaware
e dt_unware para dt_aware
mas responder antes também é uma boa solução.
fonte
localtz.localize(dt_unware, is_dst=None)
para levantar uma exceção sedt_unware
representa não-existente ou hora local ambígua (nota: não houvesse tal questão na revisão anterior de sua resposta, ondelocaltz
foi UTC porque UTC não tem transições DSTEu uso esta declaração no Django para converter um tempo inconsciente em um ciente:
fonte
Eu concordo com as respostas anteriores, e tudo bem se você estiver ok para começar no UTC. Mas acho que também é um cenário comum para as pessoas trabalharem com um valor ciente de tz que possui uma data e hora que possui um fuso horário local não UTC.
Se você fosse apenas usar o nome, provavelmente seria inferido que replace () será aplicável e produziria o objeto com reconhecimento de data e hora correto. Este não é o caso.
a substituição (tzinfo = ...) parece ser aleatória em seu comportamento . Portanto, é inútil. Não use isso!
localizar é a função correta a ser usada. Exemplo:
Ou um exemplo mais completo:
fornece um valor de data e hora com fuso horário da hora local atual:
fonte
replace(tzinfo=...)
em um fuso horário diferente do UTC estraga sua data e hora. Eu peguei em-07:53
vez de-08:00
por exemplo. Veja stackoverflow.com/a/13994611/1224827replace(tzinfo=...)
comportamento inesperado?Use
dateutil.tz.tzlocal()
para obter o fuso horário no seu usodatetime.datetime.now()
edatetime.datetime.astimezone()
:Observe que
datetime.astimezone
primeiro odatetime
objeto será convertido para UTC e depois no fuso horário, o mesmo que chamardatetime.replace
com as informações originais do fuso horárioNone
.fonte
.replace(tzinfo=dateutil.tz.UTC)
.replace(tzinfo=datetime.timezone.utc)
Isso codifica as respostas de @ Sérgio e @ unutbu . Ele "funcionará" apenas com um
pytz.timezone
objeto ou uma string de fuso horário da IANA .Parece o que
datetime.localize()
(ou.inform()
ou.awarify()
) deve fazer, aceitar objetos de strings e fuso horário para o argumento tz e usar como padrão UTC se nenhum fuso horário for especificado.fonte
O Python 3.9 adiciona o
zoneinfo
módulo e agora apenas a biblioteca padrão é necessária!Anexe um fuso horário:
Anexe o fuso horário local do sistema:
Posteriormente, é convertido corretamente em outros fusos horários:
Lista na Wikipedia de fusos horários disponíveis
Há um backport para permitir o uso no Python 3.6 a 3.8 :
Então:
fonte
pip install tzdata
No formato da resposta de unutbu; Eu criei um módulo utilitário que lida com coisas assim, com sintaxe mais intuitiva. Pode ser instalado com pip.
fonte
para aqueles que só querem informar um fuso horário sobre o horário
fonte
bastante novo para Python e eu encontrei o mesmo problema. Acho esta solução bastante simples e, para mim, funciona bem (Python 3.6):
fonte
Alterando entre fusos horários
fonte