Nie można odjąć daty offsetowej i offsetowej

Mam pole timezone aware timestamptz w PostgreSQL. Kiedy wyciągam dane z tabeli, a następnie chcę odjąć czas teraz, więc mogę uzyskać to wiek.

Problem, który mam polega na tym, że zarówno datetime.datetime.now() jak i datetime.datetime.utcnow() wydają się zwracać nieświadome strefy czasowej znaczniki czasu, co powoduje, że dostaję ten błąd:

TypeError: can't subtract offset-naive and offset-aware datetimes 

Czy istnieje sposób, aby tego uniknąć (najlepiej bez użycia zewnętrznego modułu).

EDIT: dzięki za sugestie, jednak staram się dostosować Strefa czasowa wydaje się dawać mi błędy.. więc po prostu użyję timezone timestamps w PG i zawsze wstawiam używając:

NOW() AT TIME ZONE 'UTC'

W ten sposób wszystkie moje znaczniki czasu są domyślnie UTC(nawet jeśli jest to bardziej denerwujące).

Author: Acumenus, 2009-04-28

11 answers

Czy próbowałeś usunąć świadomość strefy czasowej?

Z http://pytz.sourceforge.net/

naive = dt.replace(tzinfo=None)

Może być również konieczne dodanie konwersji strefy czasowej.

Edit: proszę pamiętać o wieku tej odpowiedzi. Odpowiedź dotycząca dodania informacji o strefie czasowej zamiast usuwania jej w Pythonie 3 znajduje się poniżej. https://stackoverflow.com/a/25662061/93380

 354
Author: phillc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-24 15:07:07

Poprawnym rozwiązaniem jest dodanie informacji o strefie czasowej, np. aby uzyskać bieżący czas jako świadomy obiekt datetime w Pythonie 3:

from datetime import datetime, timezone

now = datetime.now(timezone.utc)

W starszych wersjach Pythona można samemu zdefiniować obiekt utc tzinfo (przykład z datetime docs):

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()

Wtedy:

now = datetime.now(utc)
 265
Author: jfs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-04 09:37:14

Wiem, że niektórzy ludzie używają Django specjalnie jako interfejsu do abstrakcji tego typu interakcji z bazą danych. Django dostarcza narzędzia, które mogą być użyte do tego:

from django.utils import timezone
now_aware = timezone.now()

Musisz skonfigurować podstawową infrastrukturę ustawień Django, nawet jeśli używasz tylko tego typu interfejsu(w Ustawieniach musisz dołączyć USE_TZ=True, Aby uzyskać świadomy datetime).

Samo w sobie, prawdopodobnie nie jest to wystarczająco blisko, aby zmotywować cię do używania Django jako interfejsu, ale jest wiele innych korzyści. Z drugiej strony, jeśli natknąłeś się tutaj, ponieważ niszczyłeś swoją aplikację Django( tak jak ja), to może to pomoże...

 65
Author: sage,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-21 16:23:52

Jest to bardzo proste i jasne rozwiązanie
dwie linijki kodu

# 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

Wniosek: musisz mange swoje zmienne datetime z tym samym czasie info

 34
Author: ePi272314,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-30 11:08:17

Ja również stanąłem przed tym samym problemem. Potem znalazłem rozwiązanie po wielu poszukiwaniach .

Problem polegał na tym, że gdy otrzymujemy obiekt datetime z modelu lub postaci, jest to offset aware , a jeśli otrzymamy czas przez system, to jest to offset naive.

Więc to, co zrobiłem, to otrzymałem bieżący czas używając strefy czasowej.now () i zaimportuj strefę czasową przez z django.utils importuje strefę czasową i umieszcza USE_TZ = True w pliku ustawień projektu.

 8
Author: Ashok Joshi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-22 08:01:18

Moduł psycopg2 ma własne definicje stref czasowych, więc skończyło się na pisaniu własnego wrappera wokół utcnow:

def pg_utcnow():
    import psycopg2
    return datetime.utcnow().replace(
        tzinfo=psycopg2.tz.FixedOffsetTimezone(offset=0, name=None))

I po prostu użyj pg_utcnow, gdy potrzebujesz bieżącego czasu, aby porównać z PostgreSQL timestamptz

 6
Author: erjiang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-29 13:43:51

Wymyśliłem ultra-proste rozwiązanie:

import datetime

def calcEpochSec(dt):
    epochZero = datetime.datetime(1970,1,1,tzinfo = dt.tzinfo)
    return (dt - epochZero).total_seconds()

Działa zarówno z wartością timezone-aware, jak i timezone-naiwne datetime. Nie są wymagane żadne dodatkowe biblioteki ani obejścia w bazie danych.

 2
Author: John L. Stanley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-15 20:39:59

Znalazłem timezone.make_aware(datetime.datetime.now()) jest pomocny w django(jestem na 1.9.1). Niestety nie można po prostu zrobić datetime obiekt offsetowy świadomy, a następnie timetz() to. Musisz zrobić datetime i dokonać porównań na tej podstawie.

 1
Author: Joseph Coco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-25 19:39:16

Czy Jest jakiś pilny powód, dla którego nie możesz poradzić sobie z obliczaniem wieku w samym PostgreSQL? Coś jak

select *, age(timeStampField) as timeStampAge from myTable
 1
Author: Nic Gibson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-14 10:09:43

Wiem, że to stare, ale pomyślałem, że dodam moje rozwiązanie na wypadek, gdyby ktoś uznał je za przydatne.

Chciałem porównać lokalny naiwny datetime ze świadomym datetime z serwera czasowego. W zasadzie stworzyłem nowy naiwny obiekt datetime przy użyciu świadomego obiektu datetime. To trochę hack i nie wygląda bardzo ładnie, ale robi robotę.

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()

...nadchodzi krówka...

    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 :-(')
 0
Author: I_do_python,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-29 16:24:36

Nie potrzebujesz niczego poza std libs

datetime.datetime.now().astimezone()

Jeśli po prostu zastąpisz strefę czasową, nie dostosujesz czasu. Jeśli Twój system jest już UTC to .replace (TZ='UTC') jest w porządku.

>>> x=datetime.datetime.now()
datetime.datetime(2020, 11, 16, 7, 57, 5, 364576)

>>> print(x)
2020-11-16 07:57:05.364576

>>> print(x.astimezone()) 
2020-11-16 07:57:05.364576-07:00

>>> print(x.replace(tzinfo=datetime.timezone.utc)) # wrong
2020-11-16 07:57:05.364576+00:00
 0
Author: JeffCharter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-16 15:13:14