使用 django 查询返回活动时区中的日期时间
Posted
技术标签:
【中文标题】使用 django 查询返回活动时区中的日期时间【英文标题】:return datetimes in the active timezone with a django query 【发布时间】:2016-01-19 18:34:23 【问题描述】:我正在尝试从表中检索最后 n 小时的行并在给定的时区打印它们的日期时间,给出打印日期时使用的时区,我正在尝试使用 activate 使 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 为我执行此操作,是否有时我会遗漏 activate 函数?
编辑
这是我的模型,您可以看到要显示的时区保存在“监视器”模型上:
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()
【问题讨论】:
【参考方案1】:经过一些研究,我注意到 Django 总是将日期时间返回为 UTC,您可以通过使用 datetime.astimezone(timezone) 方法或激活某个时区来在正确的时区解释它们。
django active 函数只是改变了日期时间在模板上的呈现方式,但实际上并没有本地化时区。
【讨论】:
【参考方案2】:如果您发现自己在循环中执行 timezone.localtime(dt_value)
或 dt_value.astimezone(tzifo)
几百万次以计算您所在时区的当前日期,那么截至 1.10
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* 函数作为速记。如果您只需要datetime.date
s,TruncDate
特别有用
这会将日期计算卸载到数据库中,通常会大大降低代码复杂性并提高速度(在我的例子中,超过 650 万个 timezone.localtime(ts)
贡献了总 CPU 时间的 25%)
关于 TruncMonth 和时区的注意事项
不久前,我发现我无法从 TruncMonth
或 TruncQuarter
中获得“合适的”月份:1 月 1 日将变成 12 月 31 日。
TruncMonth 使用当前活动的时区,因此(正确地)datetime
of 2019-01-01T00:00:00Z 对于与 UTC 有正偏移的任何时区(西欧和更远的地方)转换为前一天东方)。
如果您只对事件datetime
的“纯月份”感兴趣(如果您使用的是 TruncMonth,您可能会感兴趣),那么这没有帮助,但是如果您在执行查询之前timezone.activate(timezone.utc)
(也就是说,评估您的 QuerySet),您将获得预期的结果。请记住,从您的午夜到 UTC 午夜发生的事件将低于上个月(同样datetime
s 从您的时区午夜到 UTC 午夜将被转换为“错误”月份)
【讨论】:
【参考方案3】:您可以使用 Django.utils 中的 now() 函数,但是,您需要在设置中设置两个变量。 USE_TZ 和 TIME_ZONE,第一个为 true,另一个为用于生成日期时间的默认时区。 您可以在 django 文档中查看更多信息here
【讨论】:
你能发布一些代码来展示 now() 函数如何与我的代码一起工作吗?我已经设置了 USE_TZ=True 和 TIME_ZONE,请注意 link.monitor.timezone 存储在数据库中,可能是任何时区 好的,现在我明白了,你能把字段放在模型中吗?因为Django默认不存储时区...以上是关于使用 django 查询返回活动时区中的日期时间的主要内容,如果未能解决你的问题,请参考以下文章
Django:时区支持处于活动状态时的天真日期时间(sqlite)
Django:RunTimeWarning:DateTimeField 在时区支持处于活动状态时收到了一个天真的日期时间