[django]Django 日期时间从数据库加载不正确

· 收录于 2023-12-06 06:26:08 · source URL

问题详情

我有一个用于查看传感器观察结果的 Django 应用程序。这是我的观察模型:

class Observation(models.Model):
    timestamp = models.DateTimeField()
    sensor = models.ForeignKey(Sensor, on_delete=models.CASCADE)
    value = models.DecimalField(max_digits=6, decimal_places=3)

在我的一个观点中,我想使用最新观测值的时间戳:

latest_observation = Observation.objects.order_by('-timestamp').values('timestamp').first()
context['latest_data_timestamp'] = latest_observation['timestamp'] if latest_observation else None

时间戳正确存储在数据库中 (UTC)。但是,在运行我的视图时,时间戳更改为 settings.py 中设置的时区,但 tzinfo 仍然是UTC。

settings.py 中启用了时区支持:

例如,存储在数据库中的时间戳为 2023-11-22 18:00:00+00:00,加载为 2023-11-22 19:00:00+00:00,

但如果我理解正确,应该是 2023-11-22 19:00:00+01:00(忽略夏令时,欧洲/阿姆斯特丹UTC+1

我正在使用 Django 4.2.7 和 PostgreSQL 进行生产,使用 SQLite 进行开发,但问题在这两种环境中都存在。

做错了什么,我该如何解决这个问题?

我尝试使用 astimezone 正确设置时区,但这不起作用。我也可以简单地替换 tzinfo,但这感觉像是一个糟糕的解决方案。可能有更好的方法......

最佳回答

来自 TIME_ZONE 选项上的 Django 文档

  • 如果数据库后端不支持时区(例如 SQLite、MySQL、Oracle),Django 会根据此选项以本地时间读取和写入日期时间(如果已设置),如果未设置,则以 UTC 格式读取和写入日期时间。

    • 如果 Django 管理数据库,而你没有充分的理由这样做,你应该不设置这个选项。

因此,这解释了使用 SQLite 的开发环境的结果。

PostgreSQL在这方面的行为有所不同。 来自相同的文档:

  • 如果数据库后端支持时区(例如 PostgreSQL),则很少需要 TIME_ZONE 选项。它可以随时更改;数据库负责将日期时间转换为所需的时区。

因此,无论哪种方式,您都应该只设置 USE_TZ = True而不是设置 TIME_ZONE 选项。 仅当连接到以本地时间存储其日期/时间值的旧数据库时,才设置 TIME_ZONE 选项。 如果以 UTC 格式存储时间,则不应使用 TIME_ZONE 选项。

请改用 timezone.activate 函数,将用户的显示时区设置为特定时区。

其中一些也解释了在 Django 时区的文档中