вернуть дату и время в активном часовом поясе с помощью запроса django

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

вот мой текущий код:

min_time = datetime.datetime.now(link.monitor.timezone) - datetime.timedelta(hours=period)

timezone.activate(link.monitor.timezone)
rows = TraceHttp.objects.values_list('time', 'elapsed').filter(time__gt=min_time,link_id=link_id,elapsed__gt=0)

array = []
for row in rows:
    array.append((row[0].astimezone(link.monitor.timezone),row[1]))

Я хочу избежать использования функции astimezone и заставить Django сделать это за меня, иногда мне не хватает функции активации?

РЕДАКТИРОВАТЬ

Вот мои модели, как вы можете видеть, отображаемый часовой пояс сохраняется в модели «монитор»:

class Link(models.Model):
   ...
   monitor = models.ForeignKey(Monitor)
   ...

class Monitor(models.Model):
    ...
    timezone = TimeZoneField(default='Europe/London')

class TraceHttp(models.Model):
    link = models.ForeignKey(Link)
    time = models.DateTimeField()
    elapsed = models.FloatField()

person Jesus Gomez    schedule 20.10.2015    source источник


Ответы (3)


Если вы когда-нибудь обнаружите, что выполняете timezone.localtime(dt_value) или dt_value.astimezone(tzifo) в цикле несколько миллионов раз, чтобы вычислить текущую дату в вашем часовом поясе, вероятно, лучший подход с версии 1.10 ‹= django.VERSION ‹= 2.1 — использовать django.db.models .functions.Trunc и связанные функции, т.е. используйте набор запросов, например:

from django.db.models.functions import Trunc, TruncDate

qs = MyModel.objects.filter(...).values(
    'dtime',
    ...,
    dtime_at_my_tz=Trunc('dtime', 'second', tzinfo=yourtz),
    date_at_my_tz=TruncDate('dtime', tzinfo=yourtz),
    month=TruncDate(Trunc('dtime', 'month', tzinfo=yourtz)),
    quarter=TruncDate(Trunc('dtime', 'quarter', tzinfo=yourtz))
)

Это вернет дату и время или даты в правильном часовом поясе. Вы можете использовать другие функции Trunc* в качестве сокращения. TruncDate особенно полезен, если все, что вам нужно, это datetime.dates

Это позволит разгрузить вычисления даты в базе данных, как правило, со значительным снижением сложности кода и увеличением скорости (в моем случае более 6,5 миллионов timezone.localtime(ts) занимали 25% от общего времени процессора).

Примечание о TruncMonth и часовых поясах

Некоторое время назад я обнаружил, что не могу получить «правильные» месяцы из TruncMonth или TruncQuarter: 1 января станет 31 декабря.

TruncMonth использует текущий активный часовой пояс, поэтому (правильно) datetime из 2019-01-01T00:00:00Z преобразуется в предыдущий день для любого часового пояса, который имеет положительное смещение от UTC (Западная Европа и везде дальше на восток). Если вас интересует только «чистый месяц» события datetime (и, вероятно, это так, если вы используете TruncMonth), это бесполезно, однако, если вы timezone.activate(timezone.utc) перед выполнением запроса (то есть оценкой вашего QuerySet) вы получите ожидаемый результат. Имейте в виду, что события, произошедшие с вашей полуночи до полуночи UTC, будут подпадать под предыдущий месяц (и таким же образом datetimes от полуночи вашего часового пояса до полуночи UTC будут преобразованы в «неправильный» месяц)

person RobM    schedule 02.04.2019

После некоторых исследований я заметил, что Django всегда возвращает дату и время в формате UTC, и вы должны интерпретировать их в правильном часовом поясе, используя метод datetime.astimezone(timezone) или активируя определенный часовой пояс.

Активная функция django просто изменяет способ отображения даты и времени в шаблоне, но фактически не локализует часовой пояс.

person Jesus Gomez    schedule 29.10.2015

Вы можете использовать функцию now() из Django.utils, но вам нужно установить две переменные в настройках. USE_TZ и TIME_ZONE, первый с истинным, а другой с часовым поясом по умолчанию, который будет использоваться для создания даты и времени. Дополнительную информацию можно найти в документации по django здесь

person Stortz    schedule 20.10.2015
comment
Можете ли вы опубликовать код, показывающий, как функция now() работает с моим кодом? У меня уже есть USE_TZ=True и TIME_ZONE, обратите внимание, что link.monitor.timezone хранится в базе данных и может быть любым часовым поясом - person Jesus Gomez; 21.10.2015
comment
Хорошо, теперь я понял, вы можете указать, как поля в моделях? Поскольку Django по умолчанию не хранит часовой пояс... - person Stortz; 21.10.2015