2009-04-28 3 views
174

У меня есть уведомление о часовом поясе timestamptz Поле в PostgreSQL. Когда я извлекаю данные из таблицы, я тогда хочу вычесть время прямо сейчас, чтобы получить возраст.Невозможно вычесть время с наименьшим временем смещения и смещения

Проблема у меня в том, что оба datetime.datetime.now() и datetime.datetime.utcnow(), кажется, вернуть часовой пояс не подозревая метки времени, что приводит меня получаю эту ошибку:

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

Есть ли способ избежать этого (желательно без третьего -партийный модуль).

EDIT: Спасибо за предложения, однако, пытаясь настроить часовой пояс, кажется, дает мне ошибки .. так что я просто хочу, чтобы использовать часовой пояс не подозревая временные метки в PG и всегда вставлять с помощью:

NOW() AT TIME ZONE 'UTC' 

Это по умолчанию все мои временные метки UTC по умолчанию (хотя это более раздражает).

ответ

195

Вы пытались удалить осведомленность о часовом поясе?

от http://pytz.sourceforge.net/

naive = dt.replace(tzinfo=None) 

может потребоваться добавить преобразование часового пояса, а также.

Редактировать: Пожалуйста, обратите внимание на возраст этого ответа. Ниже приведен ответ Python 3.

+25

Это, по-видимому, единственный способ сделать это. Кажется довольно хромым, что у python есть такая дерьмовая поддержка часовых поясов, что нужен сторонний модуль для правильной работы с отметками времени. – Ian

+16

python 3000 должен быть в порядке. – phillc

+27

(Только для записи). Фактически добавление информации о часовом поясе может быть лучшей идеей: http://stackoverflow.com/a/4530166/548696 – Tadeck

1

Есть ли какая-то насущная причина, по которой вы не можете справиться с вычислением возраста в PostgreSQL? Что-то вроде

select *, age(timeStampField) as timeStampAge from myTable 
+1

Да, есть .. но я в основном спрашивал, потому что я хочу избежать выполнения всех вычислений в postgre. – Ian

5

The psycopg2 модуля имеет свои собственные определения часового пояса, так что я в конечном итоге писать свою собственную оболочку вокруг utcnow:

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

и просто использовать pg_utcnow всякий раз, когда вам нужно текущее время для сравнения PostgreSQL timestamptz

+0

Любой объект tzinfo, который возвращает нулевое смещение utc, сделает [например] (http://stackoverflow.com/a/25662061/4279). – jfs

0

Я знаю, что это старо, но просто подумал, что добавлю свое решение на случай, если кто-то найдет его полезным.

Я хотел сравнить локальное наивное datetime с осведомленным временем datetime от сервера времени. В основном я создал новый объект наивного datetime, используя объект datetime. Это немного взломать и выглядит не очень красиво, но выполняет свою работу.

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

... здесь приходит выдумка ...

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

FYI, ['utc_to_local()' из моего ответа] (http://stackoverflow.com/a/13287083/4279) возвращает локальное время как ** осознанный объект ** datetime (это код Python 3.3+) – jfs

+0

Это неясно, что ваш код пытается сделать. Вы можете заменить его на 'delta = response.tx_time - time.time()'. – jfs

76

Правильное решение для добавить инфо-часовой пояс, например,, Чтобы получить текущее время, как осознаваемый объект даты и времени в Python 3:

from datetime import datetime, timezone 

now = datetime.now(timezone.utc) 

На старых версиях Python, вы можете определить utc tzinfo объект самостоятельно (пример из даты и времени, документов):

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

затем :

now = datetime.now(utc) 
+2

Лучше, чем удаление tz в качестве принятого ответа, защищает ИМХО. – Shautieh

+1

Это должен быть принятый ответ –

+0

Работал отлично, спасибо. – philipjc

36

Я знаю, что некоторые люди используют Django специально как интерфейс для абстрактного взаимодействия этого типа базы данных. Django предоставляет утилиты, которые могут быть использованы для этого:

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

Вам необходимо создать базовую Джанго настройки инфраструктуры, даже если вы используете только этот тип интерфейса (в настройках, вам необходимо включить USE_TZ=True, чтобы получить знающее время и время).

Сам по себе это, вероятно, нигде не достаточно, чтобы мотивировать вас использовать Django в качестве интерфейса, но есть много других льгот. С другой стороны, если вы наткнулись здесь, потому что вы были коверкая приложение Django (как я), то, возможно, это помогает ...

+0

вам нужно 'USE_TZ = True', чтобы узнать о нем время от времени. – jfs

+1

Да. Я забыл упомянуть, что вам нужно настроить параметры settings.py, как описывает J.F.Sebastian (я думаю, это был пример «set and forget»). – sage

10

Это очень простое и ясное решение
Две строки кода

# 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 

Вы должны чесотки переменные даты-времени с того же времени информация

+0

неверно: 'datetime.now (timezone.utc)' работает здесь тоже ('(a - b) == (a.replace (tzinfo = None) - a.utcoffset() - b.replace (tzinfo = None) + b.utcoffset()) ') – jfs

+0

Неверно? Код, который я написал, был протестирован, и я использую его в проекте django. Очень ясно и просто – ePi272314

+0

«неправильный» относится к последнему предложению в вашем ответе: * «... должен добавить ... не UTC» * - часовой пояс UTC работает здесь, поэтому утверждение неверно. – jfs

4

Я также столкнулся с той же проблемой. Затем я нашел решение после многого поиска.

Проблемы заключался в том, что, когда мы получаем объект DATETIME от модели или формы это смещение известно и если мы получим время системы это смещение наивных.

Так что я сделал это, я получил текущее время, используя timezone.now() и импортировать часовой пояс по из django.utils импорт часового пояса и поставить USE_TZ = True в файле настроек проекта.

0

Я нашел timezone.make_aware(datetime.datetime.now()) полезен в django (я на 1.9.1). К сожалению, вы не можете просто сделать объект datetime объектно-ориентированным, а затем timetz(). Вы должны сделать datetime и сделать сравнения на основе этого.

Смежные вопросы