我正在使用flask sqlalchemy和postgreSQL,并且我对显示的日期时间有问题,在调查这个问题时,我发现了另一个奇怪的事情:
以隐姓埋名模式(chrome浏览器选项卡)创建DB条目会给出不同/错误的时间。编辑:这与隐姓埋名模式无关,这两种情况都发生在正常模式下。我还没弄清楚为什么。
这是代码:
我更改了数据库的默认时区:
ALTER DATABASE postgres SET timezone TO 'Europe/Berlin';
型号:
class User(UserMixin, Base):
__tablename__ = 'users'
date_added = Column(DateTime(timezone=True), nullable=False)
我用来将日期时间添加到数据库的方法:
date_added=datetime.today()
它在数据库中的样子(我当时的本地时间是13:53:46):
创建不在隐名中的条目
timestamp with time zone
2019-02-01 13:53:46.73817+01
在隐名中创建条目
timestamp with time zone
2019-02-01 12:53:46.73817+01
这真的让我担心。这完全是错误的。即使我将日期时间对象转换为本地时间。两个条目同时完成,但显示的结果不同,这怎么可能呢?
此外,在HTML中查看这些日期时,postgreSQL不会应用偏移量,因此第一个日期看起来是正确的,但第二个日期是错误的。
起初,我只是想找到一种方法,将所有日期时间对象存储在欧洲/柏林,并在欧洲/德国时间返回,所以我不必将UTC转换为欧洲/德国,但现在我认为出现了严重的问题。
我还仔细检查了我的代码,我没有使用其他方法来操作日期时间对象。
编辑
每次用户登录时,我都会保存一个日期时间。目前我在不隐姓埋名的情况下尝试过。我的本地时间是14:13:33
,但它保存到数据库中:CCD_ 2。这怎么可能呢?我知道它不可能是随机的,但现在看起来它的保存时间是随机的——有时UTC有偏移,有时欧洲/柏林有偏移。
编辑
我用SHOW timezone;
仔细检查了所有有问题的表,它们都正确地返回了Europe/Berlin
datetime.today()
返回一个时间戳,不包含当前本地时间的时区信息(返回值为时区naive)。问题的根源在于,在SQL Alchemy的postgres适配器和postgres本身之间,它必须在某个时区进行猜测。正如你可能想象的那样,如果没有明确提供时区,计算机系统倾向于假设UTC,但工具套件集的精确逻辑可能很复杂,很难调试(这取决于你计算机上的本地时区设置、数据库中的系统级设置、会话级设置和工具制造商的偏好)。你可以通过以下方式避开这整罐蠕虫:
-
在UTC中存储所有不带时区的时间戳,然后根据需要转换为所需的时间戳
-
始终使用带时区的时间戳(即,用
datetime.now()
替换datetime.today()
并在所需时区中传递,以便您始终处理时区感知值),因此计算机无需假定时区。
注意,在postgres中,timestamp with time zone
类型仍然总是存储为UTC,没有额外的信息,数据库只是使用会话级配置来决定输出时显示为哪个时区。