J'ai un champ timestamptz
sensible au fuseau horaire dans PostgreSQL. Lorsque je tire des données de la table, je veux ensuite soustraire le temps présent afin de pouvoir obtenir son âge.
Le problème que je rencontre est que datetime.datetime.now()
et datetime.datetime.utcnow()
semblent tous deux renvoyer des horodatages sans fuseau horaire, ce qui me donne l'erreur suivante:
TypeError: can't subtract offset-naive and offset-aware datetimes
Y a-t-il un moyen d'éviter cela (de préférence sans utiliser un module tiers).
EDIT: Merci pour les suggestions, mais essayer d’ajuster le fuseau horaire semble me donner des erreurs .. donc je vais juste utiliser un timezamp de timezone non conscient dans PG et toujours insérer en utilisant:
NOW() AT TIME ZONE 'UTC'
Ainsi, tous mes horodatages sont au format UTC par défaut (même s’il est plus ennuyant de le faire).
avez-vous essayé de supprimer la conscience du fuseau horaire?
de http://pytz.sourceforge.net/
naive = dt.replace(tzinfo=None)
vous devrez peut-être ajouter une conversion de fuseau horaire.
edit: S'il vous plaît être conscient de l'âge de cette réponse. Une réponse Python 3 est présentée ci-dessous.
La solution correcte consiste à ajouter les informations de fuseau horaire, par exemple, pour obtenir l'heure actuelle en tant qu'objet date/heure conscient dans Python 3:
from datetime import datetime, timezone
now = datetime.now(timezone.utc)
Sur les anciennes versions Python, vous pouvez définir vous-même l'objet utc
tzinfo (exemple, à partir de docs datetime):
from datetime import tzinfo, timedelta, datetime
ZERO = timedelta(0)
class UTC(tzinfo):
def utcoffset(self, dt):
return ZERO
def tzname(self, dt):
return "UTC"
def dst(self, dt):
return ZERO
utc = UTC()
ensuite:
now = datetime.now(utc)
Je sais que certaines personnes utilisent Django spécifiquement comme interface permettant de résumer ce type d'interaction avec une base de données. Django fournit des utilitaires pouvant être utilisés à cette fin:
from Django.utils import timezone
now_aware = timezone.now()
Vous devez configurer une infrastructure de base Django paramètres, même si vous utilisez simplement ce type d'interface (dans les paramètres, vous devez inclure USE_TZ=True
pour obtenir une date/heure consciente).
En soi, cela n’est probablement pas suffisant pour vous motiver à utiliser Django comme interface, mais il existe de nombreux autres avantages. D'un autre côté, si vous avez trébuché ici parce que vous manipuliez votre application Django (comme je l'ai fait), alors peut-être que cela vous aidera ...
# First we obtain de timezone info o some datatime variable
tz_info = your_timezone_aware_variable.tzinfo
# Now we can subtract two variables using the same time zone info
# For instance
# Lets obtain the Now() datetime but for the tz_info we got before
diff = datetime.datetime.now(tz_info)-your_timezone_aware_variable
Conclusion: Vous devez gérer vos variables datetime avec les mêmes informations temporelles
Le module psycopg2 a ses propres définitions de fuseau horaire, alors j'ai fini par écrire mon propre wrapper autour de utcnow:
def pg_utcnow():
import psycopg2
return datetime.utcnow().replace(
tzinfo=psycopg2.tz.FixedOffsetTimezone(offset=0, name=None))
et utilisez simplement pg_utcnow
à chaque fois que vous avez besoin de l'heure actuelle pour la comparer à un PostgreSQL timestamptz
J'ai aussi fait face au même problème. Ensuite, j'ai trouvé une solution après de nombreuses recherches.
Le problème était que lorsque nous obtenons l'objet datetime du modèle ou de la forme, il est connaissance de l'offset et si nous obtenons l'heure par système, il l'est offset naïf.
Donc ce que j’ai fait, c’est que j’ai eu l’heure actuelle en utilisant timezone.now () et en important le fuseau horaire par depuis Django.utils import timezone et en plaçant le SE_TZ = True dans le fichier de paramètres de votre projet.
Je suis venu avec une solution ultra-simple:
import datetime
def calcEpochSec(dt):
epochZero = datetime.datetime(1970,1,1,tzinfo = dt.tzinfo)
return (dt - epochZero).total_seconds()
Il fonctionne avec des valeurs de date/heure naïves à chaque fuseau horaire. Et aucune autre bibliothèque ou solution de rechange à la base de données n'est requise.
Existe-t-il une raison pressante de ne pas pouvoir gérer le calcul de l'âge dans PostgreSQL lui-même? Quelque chose comme
select *, age(timeStampField) as timeStampAge from myTable
J'ai trouvé que timezone.make_aware(datetime.datetime.now())
est utile dans Django (je suis sur 1.9.1). Malheureusement, vous ne pouvez pas simplement créer un objet datetime
avec décalage, puis timetz()
. Vous devez faire un datetime
et faire des comparaisons sur cette base.
Je sais que c'est vieux, mais je pensais ajouter ma solution au cas où quelqu'un le jugerait utile.
Je voulais comparer le date-heure naïf local avec une date-heure consciente d'un serveur de temps. En gros, j'ai créé un nouvel objet date-heure naïf à l'aide de l'objet conscient de date-heure. C'est un peu un bidouillage et ne semble pas très jolie, mais fait le travail.
import ntplib
import datetime
from datetime import timezone
def utc_to_local(utc_dt):
return utc_dt.replace(tzinfo=timezone.utc).astimezone(tz=None)
try:
ntpt = ntplib.NTPClient()
response = ntpt.request('pool.ntp.org')
date = utc_to_local(datetime.datetime.utcfromtimestamp(response.tx_time))
sysdate = datetime.datetime.now()
... voici le fudge ...
temp_date = datetime.datetime(int(str(date)[:4]),int(str(date)[5:7]),int(str(date)[8:10]),int(str(date)[11:13]),int(str(date)[14:16]),int(str(date)[17:19]))
dt_delta = temp_date-sysdate
except Exception:
print('Something went wrong :-(')