/ / Datetime localização com python / django - python, django, datetime, feedparser

Localização de data e hora com python / django - python, django, datetime, feedparser

Eu estou tentando analisar um feed RSS. As entradas no feed têm elementos de data como:

<dc:date>2016-09-21T16:00:00+02:00</dc:date>

Usando o feedparser, tento fazer:

published_time = datetime.fromtimestamp(mktime(entry.published_parsed))

Mas o problema é que pareço estar recebendo o horário errado armazenado no banco de dados. Nesse caso específico, o datetime é armazenado como:

2016-09-21 13:00:00

... quando eu esperaria 14:00 - o horário UTC correto.

Eu assumo que o problema está nas configurações do django, onde temos:

TIME_ZONE = "Europe/Berlin"

Porque quando eu mudo para:

TIME_ZONE = "UTC"

... o datatime é armazenado como horário UTC correto:

2016-09-21 14:00:00

Existe alguma maneira de manter as configurações do django como estão, mas para analisar e armazenar este datetime corretamente, sem que a configuração do fuso horário do django o afete?

EDITAR: Talvez seja mais claro assim ...

print entry.published_parsed
published_time = datetime.fromtimestamp(mktime(entry.published_parsed))
print published_time
localized_time = pytz.timezone(settings.TIME_ZONE).localize(published_time, is_dst=None)
print localized_time

time.struct_time(tm_year=2016, tm_mon=9, tm_mday=21, tm_hour=14, tm_min=0, tm_sec=0, tm_wday=2, tm_yday=265, tm_isdst=0)
2016-09-21 15:00:00
2016-09-21 15:00:00+02:00

Respostas:

2 para resposta № 1

feedparser "s entry.published_parsed é sempre uma tupla de tempo utc, seja qual for a string de tempo de entrada. Para obter reconhecimento de fuso horário datetime objeto:

from datetime import datetime

utc_time = datetime(*entry.published_parsed[:6], tzinfo=utc)

Onde utc é um objeto tzinfo como datetime.timezone.utc, pytz.utcou apenas o seu tzinfo personalizado (para versões mais antigas do python).

Você não deve passar o tempo para mktime() que espera um horário local. Mesmo erro: Tenha um datetime correto com fuso horário correto.

Certificar-se de que USE_TZ=True para que o django use objetos datetime conscientes em todos os lugares. Dado um objeto datetime com reconhecimento de fuso horário, o django deve salvá-lo em db corretamente TIME_ZONE ou timezone.get_current_timezone() estamos.


1 para resposta № 2

Você já tentou usar datetime.utcfromtimestamp() ao invés de datetime.fromtimestamp()?

Como uma solução secundária, você pode obter os dados não analisados ​​(acredito que estejam disponíveis como entry.published?) e apenas use o python-dateutil para analisar a string e convertê-la em pytz.utc fuso horário como este.

>>> import pytz
>>> from dateutil import parser
>>> dt = parser.parse("2016-09-21T16:00:00+02:00")
>>> dt
datetime.datetime(2016, 9, 21, 16, 0, tzinfo=tzoffset(None, 7200))
>>> dt.astimezone(pytz.utc)
datetime.datetime(2016, 9, 21, 14, 0, tzinfo=<UTC>)

1 para resposta № 3

Usar

published_time = pytz.utc.localize(datetime.utcfromtimestamp(calendar.timegm(parsed_entry.published_parsed)))

O Feedparser pode analisar uma grande variedade de formatos de data, você pode encontrá-los Aqui.

Como você pode ver em feedparser/feedparser/datetimes/__init__.py, a função interna do Feedparser _parse_date faz o seguinte:

Analisa vários formatos de data em uma 9-tupla no GMT

Isso significa que parsed_entry.published_parsed você tem um time.struct_time objeto no fuso horário GMT.

Quando você converte para um datetime objeto usando

published_time = datetime.fromtimestamp(mktime(parsed_entry.published_parsed))

o problema é que mktime assume que a tupla passada está em horário local, que não é, é "GMT / UTC! Diferente do que você não" corretamente localizar o datetime objeto no final da conversão.

Você precisa substituir essa conversão pelo seguinte, lembrando que o Feedparser retorna um GMT struct_timee localize isso com o fuso horário que você gosta (UTC para simplificar).

  • Você usa calendar.timegm, que dá o número de segundos entre a época e a data passada como um parâmetro, assumindo que o objeto passado está em UTC / GMT (sabemos que é do Feedparser)
  • Você usa utcfromtimestamp para obter um ingênuo datetime objeto (que sabemos representa um datetime no UTC, mas o Python não faz isso no momento)
  • Com pytz.utc.localize você localiza corretamente no UTC o datetime objeto.

Exemplo:

import calendar
from datetime import datetime
import pytz
localized_dt = pytz.utc.localize(datetime.utcfromtimestamp(calendar.timegm(parsed_entry.published_parsed)))

Contanto que você seja consistente, não importa se você usa fromtimestamp ou utcfromtimestamp. Se você usar fromtimestamp você precisa dizer ao Python que o datetime O objeto que você criou tem o fuso horário local. Supondo que você esteja na Europa / Berlim, isso também é bom:

pytz.timezone("Europe/Berlin").localize(datetime.fromtimestamp(calendar.timegm(parsed_entry.published_parsed)))

Estavam parsed_entry.published_parsed também no fuso horário local, mktime deve ser usado no lugar de calendar.timegm.

Como alternativa, você pode analisar a sequência de dados que recebe do Feedparser parsed_entry["published"]

from dateutil import parser
localized_dt = parser.parse(parsed_entry["published"])

Você pode verificar se os seguintes retornos True:

parser.parse(parsed_entry["published"]) == pytz.utc.localize(datetime.utcfromtimestamp(calendar.timegm(parsed_entry.published_parsed)))

O Django TIME_ZONE A configuração não importa, pois é usada apenas para fins de visualização ou para converter automaticamente tempos de dados ingênuos.

Quando USE_TZ é True, este é o fuso horário padrão que o Django utilizará para exibir os datetimes nos templates e para interpretar os datetimes inseridos nos formulários.

O importante é sempre usar tempos de dados adequadamente localizados, independentemente do fuso horário usado. Desde que não estejam em formato ingênuo, serão manipulados adequadamente pelo Django.