/ / Localisation de datetime avec python / django - python, django, datetime, feedparser

Localisation de date / heure avec python / django - python, django, datetime, feedparser

J'essaie d'analyser un flux RSS. Les entrées du flux comportent des éléments de date tels que:

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

En utilisant feedparser, j'essaie de faire:

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

Mais le problème est que je semble avoir la mauvaise heure stockée dans la base de données. Dans ce cas particulier, la date / heure est stockée sous la forme:

2016-09-21 13:00:00

... quand je m'attendais à 14h00 - l'heure UTC correcte.

Je suppose que le problème est dans nos paramètres de Django, où nous avons:

TIME_ZONE = "Europe/Berlin"

Parce que quand je passe à:

TIME_ZONE = "UTC"

... le datatime est stocké en tant qu'heure UTC correcte:

2016-09-21 14:00:00

Existe-t-il un moyen de conserver les paramètres django en l'état, mais d'analyser et de stocker cette date-heure correctement, sans que le paramètre fuseau horaire django l'affecte?

MODIFIER: Peut-être que c'est plus clair comme ça ...

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

Réponses:

2 pour la réponse № 1

feedparser "s entry.published_parsed est toujours un tuple de temps, quelle que soit la chaîne de temps saisie. Pour connaître le fuseau horaire datetime objet:

from datetime import datetime

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

utc est un objet tzinfo tel que datetime.timezone.utc, pytz.utcou juste votre tzinfo personnalisé (pour les anciennes versions de python).

Vous ne devriez pas passer trop de temps à mktime() qui attend une heure locale. Même erreur: Avoir une date / heure correcte avec un fuseau horaire correct.

Assure-toi USE_TZ=True de sorte que django utilise des objets datetime conscients partout. Django doit le sauvegarder correctement dans la base de données, quel que soit votre choix. TIME_ZONE ou timezone.get_current_timezone() sont.


1 pour la réponse № 2

Avez-vous essayé d'utiliser datetime.utcfromtimestamp() au lieu de datetime.fromtimestamp()?

En tant que solution secondaire, vous pouvez obtenir les données non analysées (je crois qu’elles sont disponibles sous forme de fichier). entry.published?) et utilisez simplement python-dateutil pour analyser la chaîne, puis convertissez-la en pytz.utc fuseau horaire comme ça.

>>> 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 pour la réponse № 3

Utilisation

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

Feedparser peut analyser une large gamme de formats de date, vous pouvez les trouver ici.

Comme vous pouvez le voir dans feedparser/feedparser/datetimes/__init__.py, la fonction intégrée de Feedparser _parse_date fait ce qui suit:

Analyse une variété de formats de date dans un tuple GMT

Cela signifie que dans parsed_entry.published_parsed tu as un time.struct_time objet dans le fuseau horaire GMT.

Lorsque vous le convertissez en un datetime objet utilisant

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

le problème est que mktime suppose que le tuple passé est en heure locale, ce qui n’est pas, c’est GMT / UTC! En dehors de cela, vous ne localisez pas correctement la datetime objet à la fin de la conversion.

Vous devez remplacer cette conversion par la suivante, en gardant à l'esprit que Feedparser renvoie un GMT struct_timeet localisez-le avec le fuseau horaire de votre choix (UTC par souci de simplicité).

  • Tu utilises calendar.timegm, qui donne le nombre de secondes entre epoch et la date passée en tant que paramètre, en supposant que l'objet transmis est en UTC / GMT (nous le savons d'après Feedparser)
  • Tu utilises utcfromtimestamp obtenir un naïf datetime objet (que nous savons représenter une date-heure en UTC, mais Python ne le fait pas pour le moment)
  • Avec pytz.utc.localize vous localisez correctement en UTC la datetime objet.

Exemple:

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

Tant que vous êtes cohérent, peu importe si vous utilisez fromtimestamp ou utcfromtimestamp. Si tu utilises fromtimestamp vous devez dire à Python que le datetime l'objet que vous avez créé a le fuseau horaire local. Si vous êtes en Europe / Berlin, c’est bien aussi:

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

Étaient parsed_entry.published_parsed aussi dans le fuseau horaire local, mktime doit être utilisé à la place de calendar.timegm.

Comme alternative, vous pouvez analyser vous-même la chaîne de données fournie par Feedparser parsed_entry["published"]

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

Vous pouvez vérifier que les retours suivants True:

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

Le Django TIME_ZONE le paramètre n’a pas vraiment d’importance, car il est utilisé uniquement à des fins de visualisation ou pour convertir automatiquement les dates / heures naïves.

Lorsque USE_TZ a la valeur True, il s'agit du fuseau horaire par défaut que Django utilisera pour afficher les dates / heures dans les modèles et interpréter les dates / heures entrées dans les formulaires.

L'important est de toujours utiliser des dates / heures correctement localisées, peu importe le fuseau horaire utilisé. Tant qu'ils ne sont pas au format naïf, ils seront correctement gérés par Django.