# Django 日期聚合查询的时区坑

- 原文地址：https://www.kuddy.cn/archives/155
- 发布时间：2024-12-30 10:36:34
- 更新时间：2026-05-18 02:42:15
- 分类：后端开发
- 标签：Django, 安全

> 启用时区后，直接按时间字段做日期聚合可能导致日期提前 8 小时。本文记录问题原因，并给出使用 TruncDate 规避时区偏移的处理方式。

---

在 Django 项目启用时区后，如果直接使用时间字段做日期聚合，查询结果可能会出现日期提前 8 小时的问题。这个坑通常出现在按天统计、报表汇总、趋势图聚合等场景里。

## 问题现象

数据库里保存的是带时区语义的时间，但聚合时如果直接截取时间字段，最终分组日期可能和业务预期不一致，表现为统计结果被归到前一天。

## 处理方式

不要直接拿时间字段做日期聚合。先使用 TruncDate 将时间转换成日期字段，再基于转换后的日期字段进行分组统计。

```
from django.db.models import Count
from django.db.models.functions import TruncDate

daily_stats = (
    queryset.annotate(day=TruncDate("created_at"))
    .values("day")
    .annotate(total=Count("id"))
)
```

## 结论

启用时区后，日期统计要显式处理时区转换。对报表类查询而言，使用 TruncDate 比直接截取时间字段更稳定，也更符合业务日期的预期。