【问题标题】:Why does Django create Postgres timestamp columns with time zones?为什么 Django 创建带有时区的 Postgres 时间戳列?
【发布时间】:2011-12-27 10:34:48
【问题描述】:

我认为 Django 创建了与时区无关的日期时间列,但是当我查看我的 Postgres 表时,我发现那里记录的值具有时区信息。

进一步我发现 Postgres 后端指示 Django 创建使用时区的列。

来自 django/db/backends/postgresql/creation.py:

data_types = {
        ...
        'DateTimeField':     'timestamp with time zone',
        ...

架构显示创建的列被指定为“timestamp with time zone”。

CREATE TABLE notification_notice
(
  ...
  created timestamp with time zone NOT NULL,
  ...

Postgres 日志显示已发送的更新语句。 Django 根据我的 Django 设置文件构建了一个使用 UTC 作为时区的 SQL 语句。

UPDATE "notification_notice" SET "sender_id" = 1, "group_id" = NULL, "notice_type_id" = 1, "content_type_id" = 21, "object_id" = 3, "created" = E'2011-11-11 22:31:08.022148' WHERE "notification_notice"."id" = 14

这就是我的桌子的样子。创建的列有一个时间戳,其时区为“-08”。 Postgres 必须检查我的系统时钟的时区才能找到时区。

my_db=# select * from notification_notice limit 1;
 id | sender_id | group_id | notice_type_id | content_type_id | object_id |           created            | last_interaction_time 
----+-----------+----------+----------------+-----------------+-----------+------------------------------+-----------------------
  1 |           |        3 |             21 |              53 |         6 | 2011-11-11 14:31:02.98882-08 | 
(1 row)

问题:
Django 对时区没有放手政策吗?
为什么 Postgres 后端对 models.DateTimeField 使用时区?这是 Postgres 要求的吗?
有没有办法强制 Django 在不使用时区的 Postgres 中创建时间戳列?

【问题讨论】:

  • 可能的答案:here

标签: python django postgresql datetime timezone


【解决方案1】:

坏消息是问题的根源在于 Python 的日期时间实现。

好消息是 Django 在这个问题上有an open ticket

坏消息是2006年开票。

好消息是recent proposal 更有用,而且似乎正在开发中。包含该提案的帖子很长,但信息量很大。

坏消息是该提案归结为“这真是一团糟”。 (不过,它还在开发中。)

更进一步,我发现 Postgres 后端将 Django 定向到 创建使用时区的列。

不,这是 Django 的设计决定。 PostgreSQL 只存储 UTC;它不存储时区,也不存储偏移量。时区在概念上类似于一个环境变量,当它们被插入或选择以进行检索时,它会应用于时间戳。

来自django developer's mail archive。 . .

在数据库中没有实际时区支持的情况下,任何操作 由 django 采取会给某人带来不便,并且可能会 不兼容非django使用同一个数据库。

这是一个大问题——一个可能使数据库与其他语言或框架不兼容的修复。这绝对是我工作的地方。许多编程语言和框架都可以访问数据库。

SQLite、Microsoft Access 和 MySQL(日期时间数据类型,而不是时间戳)在该线程中被引用为在数据库中缺乏时区支持。

【讨论】:

  • 是的,我知道这是 Django 设计说明。 “Postgres 后端”是指 Django ORM 的 Postgres 后端。
  • 如果时区就像一个环境变量,那是否意味着我只需要在我的数据库连接中设置时区(例如UTC)?
  • @hekevintran:我仍在(再次)阅读我发布的那些参考资料。当我使用时区和多个应用程序时,突然间我的名字是“Alice”,我陷入了困境:我不再确定我知道什么和不知道什么。我要说“不”,因为您的 Django 应用程序在存储它们之前仍然必须将每个时间戳标准化为 UTC。他们每一个人,永远。我还要说,“不”,因为我很确定我错过了一些微妙的点。也许我只是累了。
  • 我想我有答案了。来自postgresql.org/docs/8.4/static/datatype-datetime.html:“所有可识别时区的日期和时间都以 UTC 格式在内部存储。在显示给客户端之前,它们会转换为 timezone 配置参数指定的区域中的本地时间。”您可以使用 SET TIME ZONE 'UTC'; 设置所需的时区。
  • 为什么会破坏数据? Django ORM 设置 Postgres 连接的时区。我只使用天真的日期时间对象并假设它们是 UTC。我将 TIME_ZONE 设置为“UTC”。我有表单和模板标记代码,可以在用户的​​时区和服务器的时区之间转换日期时间对象。我写这个问题的原因是我在查询表时看到了“-08”。我没有意识到这不是实际数据,而是时区在连接中的影响。我现在对你正在努力解决的问题感到困惑。时区感知对象?我只是避免他们:)。
【解决方案2】:

我认为你的假设不正确。 PostgreSQL does not store time zone information:

对于timestamp with time zone内部存储的值始终采用 UTC(通用协调时间,传统上称为格林威治标准时间,GMT)。具有指定明确时区的输入值将使用该时区的适当偏移量转换为 UTC。如果输入字符串中没有说明时区,则假定它在系统的 TimeZone 参数指示的时区中,并使用时区的偏移量转换为 UTC。

实际上,时区信息丢失了。但是时间瞬间被保留

这意味着当您获得时间戳信息时,无论您或您的服务器当前处于什么时区,都将始终正确。对于大多数应用程序,这正是您想要的。

【讨论】:

    【解决方案3】:

    Postgresql 能够存储带有时区的时间戳,这是一件好事。时间戳应该代表一个时间点。如果您阅读“2013-03-15 14:38:00”,是否足以确切知道所代表的时间点?不!可能是纽约的 14:38 或柏林的 14:38,这是两个不同的时间点。所以真的不应该有没有时区的时间戳(它们被称为“朴素”的日期时间),除非隐含一个特定的时区(例如 UTC)。

    在我看来,Django 创建带有时区的时间戳的事实是一件好事。您可以通过 writing your own DatetimeField 覆盖该默认行为,但我不建议这样做,除非您有充分的理由摆脱数据库中的时区(例如,因为它破坏了一些其他遗留程序)。

    如果您使用 Django DST 时间更改时遇到问题。例如,“2013-10-26 02:30:00”是模棱两可的:它是凌晨 2:30 的第一次出现还是第二次出现?如果你走这条路,你必须在你的 Django 代码中将所有日期时间与 UTC 转换,并将 UTC 日期时间存储在数据库中。

    如果你使用 Django >= 1.4,那么默认情况下它是时区感知的,并且期望每个日期时间都有一个时区。由于python datetimes 默认没有时区,因此您应该使用pytz package 来确保您操作的每个日期时间都是时区感知的。

    Django documentation about timezones 非常好读。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-08
      • 2021-12-07
      • 1970-01-01
      • 2020-09-19
      • 2015-10-07
      • 2013-10-13
      • 1970-01-01
      • 2018-01-18
      相关资源
      最近更新 更多