停止 Django 将时间转换为 UTC

Oli*_*Oli 7 django postgresql django-postgresql django-timezone

时区让我发疯。每次我认为我已经弄明白了,有人改变了时钟,我得到了十几个错误。我想我终于到了存储正确值的地步。我的时代是timestamp with time zone,我不会在它们被保存之前剥离时区。

TIME_ZONE = 'Europe/London'
USE_I18N = USE_L10N = USE_TZ = True
Run Code Online (Sandbox Code Playgroud)

这是 Postgres 到 dbshel​​l 的特定值:

=> select start from bookings_booking where id = 280825;
2019-04-09 11:50:00+01
Run Code Online (Sandbox Code Playgroud)

但是这里通过 shell_plus 得到了相同的记录

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

该死的DJANGO,这不是UTC时间!

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

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

dir*_*ten 9

你错误地解释了这一点。大多数情况下,数据库存储 UTC 时间。如果您使用 PostgreSQL,数据库可以存储带有时区信息的时间,但出于实际目的 (*) 最简单的方法是认为您的数据库中的时间存储为 UTC(即作为可以转换为任何时间的绝对时间)区)时USE_TZ = True。它始终代表一个正确的时间点,您无需记住或假设任何时区。据我所知,Django 将始终以 UTC 时区的时间感知方式存储时间。

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

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

处理有意识的日期时间对象并不总是直观的。例如,标准 datetime 构造函数的 tzinfo 参数对于带有 DST 的时区不能可靠地工作。使用 UTC 通常是安全的;如果您使用其他时区,则应仔细查看 pytz 文档。

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

如果要在 PDF 中打印这些值,请使用 Django 用于模板渲染的相同方法:

from django.utils import timezone
print(timezone.template_localtime(Booking.objects.get(pk=280825).start))
Run Code Online (Sandbox Code Playgroud)

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

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