Django 时区设置

本文详细介绍了Django在处理时区时的情况,包括通过datetime查询、ORM查询时间字符串时,Django如何将不带时区信息的时间自动转换为设置的东八区时间,并在查询结果中体现。同时指出,ORM查询出的时间为UTC时间,需要进行时区转换才能与本地时间准确对比。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 一、通过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个小时。

总结:

  1. Django如果通过一个不带时区的datetime或者时间字符串查询,都会自动转换为带时区(设置的东八区+08:00)的时间,并且数据库中储存的也是带有时区信息的时间,比ORM查询出的UTC时间多8小时。
  2. 查询或者储存时,只需要提供不带时区信息的datetime或者字符串就好了,如现在是北京时间2018年11月23日,提供datetime.datetime(2018, 11, 23, 00, 00, 00)或者'2018-11-11 00:00:00',Django就会自动处理为东八区时间。
  3. 如果要判断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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值