django项目的settings.py中设置了USE_TZ=True后,不管TIME_ZONE设置的是什么,存入数据库的都是UTC时间,取出来时会转成当前时区的时间来显示。具体USE_TZ的作用在这里就不细说了。
环境说明
Django 3.2.8版本
myql使用的是8.0.25版本
windows10系统
出现的问题
最开始项目中使用的还是sqlite,项目中有个Model类包含了一个DateTimeField,在sqlite时查询是正常的。
下面是示例:
# 查询文章年份为2021年且月份为10月的
Article.objects.filter(post_datetime__year=2021, post_datetime__month=10)
同样的语句,同样的数据,当我迁移到mysql后就出现了上面的语句查询不出数据的情况,如果只查询年份就有结果,但是一旦加上查询月份就没有结果。
解决方法
Queryset中有个query的属性,可以显示查询具体执行了什么sql语句。
具体执行的sql语句:
SELECT `mainapp_article`.`id`, `mainapp_article`.`article_id`, `mainapp_article`.`title`, `mainapp_article`.`content`, `mainapp_article`.`post_datetime`, `mainapp_article`
.`likes`, `mainapp_article`.`category`, `mainapp_article`.`read_count`, `mainapp_article`.`kind_id` FROM `mainapp_article` WHERE (`mainapp_article`.`post_datetime` BETWEEN
2020-12-31 16:00:00 AND 2021-12-31 15:59:59.999999 AND EXTRACT(MONTH FROM CONVERT_TZ(`mainapp_article`.`post_datetime`, 'UTC', 'Asia/Shanghai')) = 10) ORDER BY `mainapp_a
rticle`.`post_datetime` DESC
其中出问题的是下面这个:
EXTRACT(MONTH FROM CONVERT_TZ(`mainapp_article`.`post_datetime`, 'UTC', 'Asia/Shanghai')) = 10)
Django中的settings.py我将TIME_ZONE设置为了Asia/shanghai,由于USE_TZ的值为True,所以会在查询数据时将数据库中存储的时间由UTC转为Asia/shanghai。DatetimeField对应着mysql里面的datetime类型。
CONVERT_TZ转换时区有以下两种形式:
-- 第一种
SELECT CONVERT_TZ('2021-10-17 13:51:53.777000','Asia/Shanghai','UTC') as cvt;
-- 第二种
SELECT CONVERT_TZ('2021-01-03 12:00:00','+00:00','+10:00')
windows中mysql没有时区表,所以使用第一种方式会导致查询不到数据,添加时区表就可以解决这个查询不到数据的问题了。
加载时区表可以参照这里。
当然,直接在Django项目中设置USE_TZ为False也可以解决这个问题。