Docker容器中Linux date正常但Python tzlocal返回UTC的问题
我之前也碰到过一模一样的问题——容器里date命令显示的时区完全正常,但Python交互环境和Django里用tzlocal模块就是返回UTC。咱们一步步来解决:
先确认问题场景
你的情况应该是这样的:
ogixbuild$ docker exec -it qlogixwebapi bash root@3e1a15562c2f:/var/lib/django/webapi# date Thu Feb 8 15:14:31 MST 2018 root@3e1a15562c2f:/var/lib/django/webapi# python3 Python 3.6.4 (default, Dec 21 2017, 01:35:12) [GCC 4.9.2] on linux >>> import tzlocal >>> tzlocal.get_localzone() <UTC>
问题根源
date命令主要依赖/etc/localtime的链接,但Python的tzlocal模块会优先检查TZ环境变量,然后才会读取/etc/timezone或者/etc/localtime的信息。如果这些配置要么不存在、要么Python没权限读取,就会 fallback 到UTC。
解决步骤
1. 检查容器内的时区配置文件
先看看容器里的时区文件是不是正确配置了:
# 查看/etc/timezone内容 cat /etc/timezone # 查看/etc/localtime的链接指向 ls -l /etc/localtime
正常情况下,/etc/timezone应该输出你需要的时区(比如America/Denver对应MST),/etc/localtime要链接到/usr/share/zoneinfo/下的对应文件。如果不对,手动修正:
echo "America/Denver" > /etc/timezone ln -sf /usr/share/zoneinfo/America/Denver /etc/localtime
2. 给Python明确设置TZ环境变量
tzlocal会优先读取TZ环境变量,这是最直接的解决办法。你可以在Docker Compose里添加这个环境变量:
services: qlogixwebapi: # 其他配置... environment: - TZ=America/Denver
也可以进入容器临时测试:
export TZ=America/Denver python3 -c "import tzlocal; print(tzlocal.get_localzone())"
这下应该能返回正确的时区了。
3. 确认Django的时区配置
别忽略Django自身的设置!在settings.py里检查这两个配置:
TIME_ZONE = 'America/Denver' # 改成你需要的时区 USE_TZ = True
就算系统时区正确,Django如果硬设了TIME_ZONE = 'UTC',那肯定还是用UTC。
4. 检查挂载的时区文件权限
如果你是通过挂载主机的时区文件到容器(比如/etc/localtime),要确保挂载方式是只读,并且容器内的用户能读取:
services: qlogixwebapi: # 其他配置... volumes: - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro
:ro标记能避免容器修改这些文件,同时保证读取权限。
总结
这个问题本质是Python和系统date命令的时区检测逻辑不一样,要么通过环境变量直接指定,要么把系统时区配置文件弄对并确保Python能读取到。
内容的提问来源于stack exchange,提问作者Michaela Ervin

