1 錯誤描述
在查詢資料集中的日期時間物件時
In [38]: Device.objects.datetimes('latest_alarm_time', 'month')
Out[38]: SELECT DISTINCT
CAST(DATE_FORMAT(CONVERT_TZ(`device_device`.`latest_alarm_time`, 'UTC', 'Asia/Shanghai'), '%Y-%m-01 00:00:00') AS DATETIME) AS `datetimefield` FROM `device_device` WHERE `device_device`.`latest_alarm_time` IS NOT NULL ORDER BY `datetimefield` ASC LIMIT 21
然後報錯
ValueError: Database returned an invalid datetime value. Are time zone definitions for your database installed?
2 解決問題
實際情況,資料庫中是有資料,目測月份提取失敗;到 mysql 執行了下
mysql root@localhost:py365> select convert_tz('2018-05-10 12:30:00', 'UTC', 'Asia/Shanghai');
+-------------------------------------------------------------+
| convert_tz('2018-05-10 12:30:00', 'UTC', 'Asia/Shanghai') |
|-------------------------------------------------------------|
| NULL |
+-------------------------------------------------------------+
果然,結果返回令人詫異的 NULL
看了下 Django orm 的 datetimes 官方文件
Note
This function performs time zone conversions directly in the database. As a consequence, your database must be able to interpret the value of tzinfo.tzname(None). This translates into the following requirements:
SQLite: no requirements. Conversions are performed in Python with pytz (installed when you install Django).
PostgreSQL: no requirements (see Time Zones).
Oracle: no requirements (see Choosing a Time Zone File).
MySQL: load the time zone tables with mysql_tzinfo_to_sql.
即 mysql 需要使用 mysql_tzinfo_to_sql 載入時區表,接著跳到 https://dev.mysql.com/doc/ref...
按照 mysql 官方的文件
For the first invocation syntax, pass the zoneinfo directory path name to mysql_tzinfo_to_sql and send the output into the mysql program. For example:
我需要按照以下命令執行
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql
然後再次執行上面執行過的轉換語句
mysql root@localhost:py365> select convert_tz('2018-05-10 12:30:00', 'UTC', 'Asia/Shanghai');
+-------------------------------------------------------------+
| convert_tz('2018-05-10 12:30:00', 'UTC', 'Asia/Shanghai') |
|-------------------------------------------------------------|
| 2018-05-10 20:30:00 |
+-------------------------------------------------------------+
yes,返回了正確的結果;
在 shell 中 執行資料庫查詢語句
In [45]: Device.objects.datetimes('latest_alarm_time', 'month')
Out[45]: SELECT DISTINCT CAST(DATE_FORMAT(CONVERT_TZ(`device_device`.`latest_alarm_time`, 'UTC', 'Asia/Shanghai'), '%Y-%m-01 00:00:00') AS DATETIME) AS `datetimefield` FROM `device_device` WHERE `device_device`.`latest_alarm_time` IS NOT NULL ORDER BY `datetimefield` ASC LIMIT 21
Execution time: 0.000591s [Database: default]
<QuerySet [datetime.datetime(2018, 5, 1, 0, 0, tzinfo=<DstTzInfo 'Asia/Shanghai' CST+8:00:00 STD>)]>
正常,so 問題解決,看來還得認真看文件呀