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 № 1feedparser "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)
où utc
est un objet tzinfo tel que datetime.timezone.utc
, pytz.utc
ou 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_time
et 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ïfdatetime
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 ladatetime
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.