【问题标题】:Stop Django translating times to UTC停止 Django 将时间转换为 UTC
【发布时间】:2019-04-09 16:46:03
【问题描述】:

时区快把我逼疯了。每次我想我已经弄明白了,有人改变了时钟,我得到了十几个错误。我想我终于到了存储正确价值的地步。我的时间是timestamp with time zone,我不会在保存时区之前删除它们。

TIME_ZONE = 'Europe/London'
USE_I18N = USE_L10N = USE_TZ = True

这是 Postgres 通过 dbshel​​l 获取的特定值:

=> select start from bookings_booking where id = 280825;
2019-04-09 11:50:00+01

但是这里通过 shell_plus 的记录是一样的

Booking.objects.get(pk=280825).start
datetime.datetime(2019, 4, 9, 10, 50, tzinfo=<UTC>)

DAMMIT DJANGO,这不是 UTC 时间!

这些时间在模板/管理员/等中工作很好,但是当我生成 PDF 和电子表格报告时,这一切都出错了,我突然不得不手动重新本地化时间。我不明白为什么我必须这样做。数据已本地化。查询到数据库和我获取数据之间发生了什么?

我经常遇到这些问题,我对自己在这里完全没有信心——这对高级开发人员来说非常令人不安——所以我把自己放在你的脚下。我应该做什么?

【问题讨论】:

  • 请注意,数据库连接有自己的timezone settings:“PostgreSQL 后端将日期时间存储为timestamp with time zone。实际上,这意味着它将日期时间从连接的时区转换为存储上的 UTC,并从UTC 到检索时连接的时区。” Django sets the database connection to UTC,而您的 dbshel​​l 配置可能使用了其他东西。

标签: django postgresql django-postgresql django-timezone


【解决方案1】:

您对此的解释是错误的。数据库大部分时间都存储 UTC 时间。如果您使用 PostgreSQL,数据库可以存储带有时区信息的时间,但出于实际目的 (*),最简单的方法是认为您的数据库中的时间存储为 UTC(即可以转换为任何时间的绝对时间区)当USE_TZ = True。它始终代表您不需要记住或假设任何时区的正确时间点。据我所知,Django 将始终将时间存储为 UTC 时区中的时间感知。

因此,当您在 psql 中使用 select 获取时间对象时,您将获取机器本地时区(运行 psql 的时区)的时间.如果“America/New_York”中的某个人运行相同的选择查询,她会看到 -04 时间戳。如果日期是 2019 年 3 月 20 日,您会看到 2019-03-20 10:50:00+00,因为在那一天,欧洲/伦敦和 UTC 相同。

当获取DateTimeField 的值作为python datetime.datetime 对象时,Django 总是获取UTC 值,因为:

处理感知日期时间对象并不总是直观的。为了 例如,标准日期时间构造函数的 tzinfo 参数 对于使用 DST 的时区,不能可靠地工作。通常使用 UTC 安全的;如果您使用其他时区,您应该查看 pytz 仔细记录。

这使得在 Python 代码中使用这些日期时间对象变得更加容易:它们始终是 UTC 时间。

如果您想在 PDF 中打印这些值,请使用 Django 用于模板呈现的相同方法:

from django.utils import timezone
print(timezone.template_localtime(Booking.objects.get(pk=280825).start))

这会将日期时间呈现在默认时区(或者如果您 activate() 使用不同的时区,则在 当前时区)。

(*) 注意:为什么您不应该对保存在数据库中的时区赋予任何意义,而只是将其视为所有 UTC:如果您要在不同的时区运行服务器,您实际上可能最终会保存时间戳在不同的时区。它们仍然都是正确的(绝对时间戳),并且可以转换为任何其他时区。所以基本上用于保存的时区是没有意义的。

【讨论】:

  • 非常感谢您的解释,但我仍然无法相信自称为“带时区的时间戳”的 PG 数据类型实际上并没有保持偏移量,这不是 Django 成为我的眼中钉这里。综上所述,我将开始将所有输出包装在 timezone.template_localtime 中。
  • 为了加剧这种怀疑,我更改了我的开发机器上的时区,重新启动了 PG,但我仍然得到 +01 时间。看起来 Postgres 并没有将所有内部持有的 UTC 时间转换为系统本地时间。
  • 好吧,也许我在 psql 的输出中错了。但其余的都是正确的。保存到数据库时无法确定使用的是哪个时区,因此 Django 总是在 python 对象中返回一个 UTC 日期时间。
  • 别让我说服你。 IRC 上的某个人也说了同样的话。 PG 文档说了同样的话(“一直是UTC”),当我认为看到别的东西时,这很令人沮丧。它还会产生各种小问题,让我觉得我应该一直存储幼稚的日期时间。
  • 如果你这么想真的很简单:数据库保存了正确的绝对时间; Django 在它传递的对象中总是使用基于 UTC 的时间;渲染时,您可以使用转换为您想要的任何时区的函数。
【解决方案2】:

请注意,Django 和 Postgresql 数据库都有自己的时区设置。

Django 时区在 settings.py 文件中设置:

TIME_ZONE = 'UTC'
USE_TZ = True

可以使用以下命令检查 Postgresql 设置:

SHOW TIMEZONE;

并设置使用:

SET TIMEZONE='UTC';

我不是这方面的专家,但我相信 Django 想要在数据库中以 UTC 格式存储所有内容,然后在查询后转换为 Django 时区设置。在此基础上,我认为您希望将 Postgresql 时区设置为 UTC,然后由您决定是否更改 Django 设置以获取自动转换或将其保留为 UTC 并自己在代码中处理任何转换。

【讨论】:

    猜你喜欢
    • 2021-02-04
    • 1970-01-01
    • 2020-01-11
    • 2018-08-14
    • 2013-02-03
    • 1970-01-01
    • 1970-01-01
    • 2017-04-27
    相关资源
    最近更新 更多