PostgreSQL SQLalchemy 和时间戳带时区,为什么隐身与正常不同?

Rom*_*man 0 python postgresql timezone datetime sqlalchemy

我正在使用 Flask sqlalchemy 和 postgreSQL 并且显示的日期时间有问题,在调查这个问题时我发现了另一个奇怪的事情:

在隐身模式(chrome 浏览器选项卡)下创建数据库条目会给出不同/错误的时间。编辑:它与隐身模式无关,这两种情况也发生在正常模式下。我还没有弄清楚为什么。

这是代码:

我更改了数据库的默认时区:

ALTER DATABASE postgres SET timezone TO 'Europe/Berlin';
Run Code Online (Sandbox Code Playgroud)

该模型:

class User(UserMixin, Base):
    __tablename__ = 'users'
    date_added = Column(DateTime(timezone=True), nullable=False)
Run Code Online (Sandbox Code Playgroud)

我用来将日期时间添加到数据库的方法:

date_added=datetime.today()
Run Code Online (Sandbox Code Playgroud)

它在数据库中的外观(此时我的本地时间是 13:53:46):

不在隐身模式下创建条目

timestamp with time zone
2019-02-01 13:53:46.73817+01
Run Code Online (Sandbox Code Playgroud)

在隐身模式下创建条目

timestamp with time zone
2019-02-01 12:53:46.73817+01
Run Code Online (Sandbox Code Playgroud)

这真的让我担心。这是错误的。即使我将日期时间对象转换为本地时间。两个条目同时完成,但显示不同的结果,这怎么可能?

同样在 HTML 中查看这些日期时,postgreSQL 不会应用偏移量,因此第一个日期看起来正确,但第二个日期是错误的。

最初我只是想找到一种方法来在欧洲/柏林存储所有日期时间对象并在欧洲/柏林时间返回它们,所以我不必将 UTC 转换为欧洲/柏林,但现在我认为出现了可怕的错误。

我也到处都仔细检查了我的代码,我没有使用其他方法来操作日期时间对象。

编辑

每次用户登录时,我都会保存一个日期时间。目前我在非隐身模式下尝试过。我的本地时间是14:13:33但它保存到数据库中: 2019-02-01 13:13:33.804339+01。这怎么可能?我知道它不能是随机的,但现在看起来它的保存时间是随机的,有时是带有偏移量的 UTC,有时是带有偏移量的欧洲/柏林。

编辑

我仔细检查了所有有问题的表格SHOW timezone;,它们都正确返回Europe/Berlin

Geo*_*e S 8

datetime.today()返回没有当前本地时间的时区信息时间戳(返回值是 timezone naive)。您的问题的根源在于,在 SQL Alchemy 的 postgres 适配器和 postgres 本身之间的某个地方,它必须猜测时区。正如您可能想象的那样,如果没有明确提供时区,计算机系统倾向于假设 UTC,但工具集的精确逻辑可能很复杂且难以调试(我取决于您计算机上的本地时区设置,系统级db 中的设置、会话级别设置以及工具制造商的偏好)。您可以通过以下任一方式避开这整个蠕虫罐头:

  1. 以 UTC 格式存储没有时区的所有时间戳,然后根据需要转换为所需的时间戳

  2. 始终使用时间戳与时区(如更换datetime.today()datetime.now(),并传入所需的时区,这样你总是与时区交易感知价值),所以没有必要为计算机承担的时区。

请注意,在 postgres 中,timestamp with time zone类型仍然始终存储为 UTC,没有额外信息,数据库仅使用会话级配置来决定在输出时将其显示为哪个时区。