
django 并不读取系统环境变量 `tz` 来设置时区,而是依赖自身配置项 `time_zone`(默认值为 `"america/chicago"`),该设置独立于操作系统级 `tz` 变量,且对 python 的 `time` 模块生效,但不影响 `zoneinfo` 或 `pytz` 的行为。
在 Django 应用中观察到 os.environ.get('TZ') 返回 "America/Chicago",而系统终端执行 printenv TZ 或在纯 Python 脚本中获取却得到其他值(如 "Asia/Shanghai"),这并非 Django “篡改”了环境变量,而是Django 在启动时主动设置了 os.environ['TZ'],以确保底层 C 库(如 time.timezone、time.localtime())能与 Django 的 TIME_ZONE 配置保持一致。
该行为源于 Django 内部的时区初始化逻辑(见 django.utils.timezone.activate() 和 django.setup() 流程)。当 settings.TIME_ZONE 被设定(无论来自 settings.py、DJANGO_SETTINGS_MODULE 还是环境变量 DJANGO_TIME_ZONE),Django 会调用 time.tzset()(仅限 Unix/Linux/macOS),并同步将 os.environ['TZ'] 设为对应时区字符串。
✅ 正确做法:
- 始终通过 settings.TIME_ZONE 控制 Django 时区,而非依赖系统 TZ;
- 若需动态设置,推荐使用环境变量 DJANGO_TIME_ZONE=Asia/Shanghai(Django ≥ 4.0 原生支持),或在 settings.py 中写:
import os TIME_ZONE = os.getenv('DJANGO_TIME_ZONE', 'UTC') - 避免手动修改 os.environ['TZ'] —— Django 启动后覆盖它,可能导致 time 模块行为不一致。
⚠️ 注意事项:
- TZ 环境变量仅影响 time 模块(如 time.strftime()),不影响 datetime 对象、zoneinfo.ZoneInfo 或 Django ORM 的时区感知字段;
- Django 的 USE_TZ=True 模式下,所有时间存储为 UTC,显示时按 TIME_ZONE 转换,此时系统 TZ 完全无关;
- 在容器化部署(如 Docker)中,建议显式设置 ENV TZ=Asia/Shanghai 仅用于基础系统工具(如 date 命令),而 Django 仍以 DJANGO_TIME_ZONE 为准,避免混淆。
简言之:Django 的 TIME_ZONE 是权威时区源,TZ 环境变量只是其副作用;理解这一设计边界,可避免调试时陷入“环境变量被悄悄修改”的误区。










