2019 年 4 月 8 日更新
这是 django<=2.2 的一个已知错误,自本PR起已修复
==================================
(我们假设 mysql 后端)
我可以在 中设置TIME_ZONE
多次settings.py
,一个用于全局 django 应用程序,一个用于每个数据库(参见https://docs.djangoproject.com/en/1.11/ref/settings/#time-zone (ref1))
典型用法是日期时间不以 UTC 存储的旧数据库。
没有日期查询
查询我的数据库会考虑此设置,例如:
在settings.py
USE_TZ = True
TIME_ZONE = 'Europe/Paris' # tz1
DATABASES = {
'legacy': {
'ENGINE': 'django.db.backends.mysql',
'OPTIONS': {
'read_default_file': '....cnf',
},
'TIME_ZONE': 'Europe/Paris', # tz2
},
'default' : {
'ENGINE': 'django.db.backends.mysql',
'OPTIONS': {
'read_default_file': '....cnf',
},
}
}
在里面manage.py shell
>>> dt = timezone.make_aware(datetime.datetime(2017, 7, 6, 20, 50))
>>> dt
datetime.datetime(2017, 7, 6, 20, 50, tzinfo=<DstTzInfo 'Europe/Paris' CEST+2:00:00 DST>)
>>> MyModel.objects.filter(my_datetime_field=dt).exists()
True
这有效,因为我的数据库读取'2017-07-06 20:50:00'
带日期查询
相关文档https://docs.djangoproject.com/en/1.11/ref/models/querysets/#date (ref2)
但这不起作用,虽然它在逻辑上应该
>>> MyModel.objects.filter(my_datetime_field__date=dt.date()).exists()
False*
来自 DEBUG 的相关 SQL 查询是:
SELECT (1) AS `a` FROM `my_model` WHERE DATE(CONVERT_TZ(`my_model`.`my_datetime_field`, 'UTC', 'Europe/Paris')) = '2017-07-06' LIMIT 1;
(*) 请注意,我没有填写 MySQL 中的时区表,因此结果应该是True
在这种情况下,但可能False
接近午夜。相关文档是https://dev.mysql.com/doc/refman/5.7/en/mysql-tzinfo-to-sql.html
有两件事是错误的。首先,转换应该是从巴黎到巴黎,而不是UTC到巴黎。转换应该从数据库时区 tz2 到 django 应用程序一个 tz1。
确实来自 ref1 :
当 USE_TZ 为 True 并且数据库不支持时区(例如 SQLite、MySQL、Oracle)时,如果设置了此选项,Django根据本地时间读取和写入日期时间,如果没有设置,则使用 UTC。
和 ref2 :
当 USE_TZ 为 True 时,字段在过滤前转换为当前时区
其次,当 tz1 == tz2 时,应该不需要使用CONVERT_TZ
,并且查询将在 MySQL 中没有时区表的情况下工作。
显式查询是:
mysql> SELECT (1) AS `a` FROM `my_model` WHERE `my_model`.`my_datetime_field` = '2017-07-06 20:50:00' LIMIT 1;
+---+
| a |
+---+
| 1 |
+---+
1 row in set (0.00 sec)
mysql> SELECT (1) AS `a` FROM `my_model` WHERE DATE(`my_model`.`my_datetime_field`) = '2017-07-06' LIMIT 1;
+---+
| a |
+---+
| 1 |
+---+
1 row in set (0.00 sec)
为什么会'UTC'
出现在查询中?不应该'Europe/Paris'
吗?
我是否误解了文档中的某些内容,还是错误?
谢谢你。
编辑:我的系统 tz 不是 UTC,如果这有帮助的话
mysql> SELECT @@global.time_zone, @@session.time_zone, @@system_time_zone;
+--------------------+---------------------+--------------------+
| @@global.time_zone | @@session.time_zone | @@system_time_zone |
+--------------------+---------------------+--------------------+
| SYSTEM | SYSTEM | CEST |
+--------------------+---------------------+--------------------+