Django 时区混淆;Postgres 和 Apache

4 投票
1 回答
2291 浏览
提问于 2025-04-15 20:51

背景:在同一组服务器上有多个Django网站,它们都由同一组Apache进程提供服务。有些网站使用东部时间,有些使用中部时间。数据库是PostgreSQL,运行在另一台服务器上。

刚开始的时候,我没有仔细考虑这些网站如何处理时区的问题;我看到Django里有个TIMEZONE的设置,就以为它会自动处理好。现在我发现问题开始出现了。

第一个问题:时区似乎在东部和中部之间来回切换。我从这个网站上了解到,这可能是因为操作系统的环境变量TZ会根据Apache进程处理的Django网站而变化。如果这个进程接着处理另一个时区的网站请求,时区就会出错。我找到的解决办法是,不同时区的网站需要有不同的进程组来处理。请纠正我如果我理解错了。

第二个问题:在Linux上,我从一个使用中部时间的网站运行了./manage.py runserver(我自己在东部)。我创建了一个资产,它的发布时间在管理后台显示得正确,确实比实际时间晚了一个小时。但查看实际的PostgreSQL记录,发布时间的时区仍然显示为-04。PostgreSQL是不是只使用服务器或计算机本身的时区,而忽略Django里的任何时区设置?所以在东部时间的PostgreSQL服务器上保存的所有记录都会显示为-04或-05,具体取决于夏令时?

如果有其他人遇到过类似的问题,欢迎提供建议。即使我把中部网站的Apache进程分开,以确保它们的时区设置不冲突,我仍然需要解决PostgreSQL的问题。我还想知道,如果PSQL的时间戳是中部时间,而时区设置是东部时间,那么日期时间字段会考虑时区吗?也就是说,如果Django设置为东部时间,调用datetime.datetime.now()返回的是下午2点,然后我让它筛选发布时间早于这个结果的内容,它会只查找发布时间在下午1点中部时间或更早的内容吗?

1 个回答

2

这里有一些关于Django和Postgres处理时区的细节,但我强烈建议在后端只使用UTC时间,只有在前端展示给用户时才转换为当地时区。在Python中,你可以通过datetime.datetime.utcnow()获取当前的UTC时间。我甚至把我的服务器设置在UTC时区,但这并不是绝对必要的。

Django对多个时区的支持不是很好;可以参考这个问题。Python标准库中的日期时间对象是没有时区信息的,你需要像pytz这样的库来解决这个问题,但据我所知,Django仍然返回的是没有时区信息的日期时间对象,而不是可以用pytz构造的有时区信息的对象。

Postgres会检查几个地方来确定时区,包括TZ环境变量,但TZ必须在Postgres进程的环境中:

PostgreSQL 8.5.3. 时区

如果在postgresql.conf中没有指定时区,也没有作为postmaster命令行参数提供,服务器会尝试使用TZ环境变量的值作为默认时区。如果TZ没有定义,或者不是PostgreSQL已知的任何时区名称,服务器会通过检查C库函数localtime()的行为来确定操作系统的默认时区。默认时区会在PostgreSQL已知的时区中选择最接近的匹配。

撰写回答