一、通过datetime查询
>>>today = datetime.now()
>>>today
datetime.datetime(2018, 11, 22, 21, 52, 39, 207244)
>>>tomorrow = today + timedelta(days=1)
>>>tomorrow
datetime.datetime(2018, 11, 23, 21, 52, 39, 207244)
-
执行查询:
>>>transactions = Transaction.objects.filter(exchange_date__gte=today, exchange_date__lte=tomorrow)
>>>transactions.first().exchange_date
datetime.datetime(2018, 11, 22, 15, 1, 20, 69286, tzinfo=<UTC>) # 为UTC时间,比实际时间少8个小时
-
报如下警告:
/root/env/heat/lib/python3.5/site-packages/django/db/models/fields/__init__.py:1423: RuntimeWarning: DateTimeField Transaction.exchange_date received a naive datetime (2018-11-22 21:52:39.207244) while time zone support is active.
-
警告原因:
为时区问题,datetime.now()生成的不带时区的utc时间称为native time
使用django.utils.timezone.now()输出的是带时区的utc时间,称为active time
-
打印查询语句:
>>>print(transactions.query)
sql限定部分为:WHERE ("account_transaction"."exchange_date" <= 2018-11-23 21:52:39.207244+08:00 AND "account_transaction"."exchange_date" >= 2018-11-22 21:52:39.207244+08:00)
2018-11-22 21:52:39.207244+08:00和2018-11-23 21:52:39.207244+08:00加上了时区信息
可见django会将不带时区的naive datetime自动转化为setting.py里设置的东八区时间(+08:00)
二、 ORM可以通过时间字符串执行查询
>>>today_str = datetime.strftime(today, '%Y-%m-%d %H:%M:%S')
>>>today_str
'2018-11-22 21:52:39'
>>>tomorrow_str = datetime.strftime(tomorrow, '%Y-%m-%d %H:%M:%S')
>>>tomorrow_str
'2018-11-23 21:52:39'
-
执行查询:
>>>transactions = Transaction.objects.filter(exchange_date__gte=today_str, exchange_date__lte=tomorrow_str)
依然会出现同样的警告。
-
打印查询语句:
>>>print(transactions.query)
sql限定部分为:WHERE ("account_transaction"."exchange_date" <= 2018-11-21 21:52:39+08:00 AND "account_transaction"."exchange_date" >= 2018-11-22 21:52:39+08:00)
2018-11-22 21:52:39.207244+08:00和2018-11-23 21:52:39.207244+08:00加上了时区信息
可见django会将时间字符串默认为不带时区的naive datetime,并自动转化为setting.py里设置的东八区时间(+08:00)
三、ORM查询和sql语句查询
-
通过ORM查询
t>>>ransaction = Transaction.objects.filter(exchange_date__lte='2018-11-11', exchange_date__gte='2018-11-10').order_by('exchange_date').first()
>>>transantion.exchange_date
datetime.datetime(2018, 11, 9, 16, 0, 32, 350514, tzinfo=<UTC>)
查询的时间为UTC时间
-
通过sql查询
>>>select exchange_date from account_transaction where exchange_date>'2018-11-10' and exchange_date<'2018-11-11' order by exchange_date limit 1;
2018-11-10 00:00:32.350514+08
正好比通过ORM查询的时间多8个小时。
总结:
- Django如果通过一个不带时区的datetime或者时间字符串查询,都会自动转换为带时区(设置的东八区+08:00)的时间,并且数据库中储存的也是带有时区信息的时间,比ORM查询出的UTC时间多8小时。
- 查询或者储存时,只需要提供不带时区信息的datetime或者字符串就好了,如现在是北京时间2018年11月23日,提供datetime.datetime(2018, 11, 23, 00, 00, 00)或者'2018-11-11 00:00:00',Django就会自动处理为东八区时间。
- 如果要判断ORM查询出的时间是否过期,由于是UTC时间,datetime.now()的时间是不带时区信息的东八区时间,会比UTC时间多八个小时,所以需要去掉时区信息(.replace(tzinfo=None))并加上8小时后再进行对比。因为时区信息不同无法对比,如下:
from pytz import timezone
cst_tz = timezone('Asia/Shanghai')
utc_tz = timezone('UTC')
a = datetime.datetime.now()
a_now = a.replace(tzinfo=cst_tz) # 上海时区
a_utc = a.replace(tzinfo=utc_tz) # 格林尼治时区
print(a) # 2018-11-23 01:20:55.093091
print(a_now) # 2018-11-23 01:20:55.093091+08:06
print(a_utc) # 2018-11-23 01:20:55.093091+00:00
print(a_utc < a_now) # False
print(a_now == a_utc) # False
print(a_now > a_utc) # False
print(a > a_now) # TypeError: can't compare offset-naive and offset-aware datetimes