两种时间对象aware datetime
vs naive datetime
aware datime naive datetime
tzinfo属性有设置时区值 无
可以换成unix时间戳 无法直接转换成一个准确unix时间戳(会以当前系统时区为准)
from datetime import datetime
from django.utils import timezone
t = datetime.now()
print(timezone.is_aware(t))
print(timezone.is_naive(t))
# t是一个naive datetime,因为我们没有给他设置时区
Django的时区 USE_TZ
TIME_ZONE
USE_TZ
用来指定整个项目是否使用时区
如果USE_TZ的值设置为False,那么Django项目中所有时间都使用naive datetime(除非有明确指定时区的情况)
弊端:
数据库中保存的是naive datetime,导致在跨区域迁移数据的时候,可能无法准确定位到某个时间点
国际化企业可能面向不同国家有不同的网站,但后台数据库相同,此时究竟使用哪个时区保存和展示时间,将引起混乱
即使是同一个网站的用户,他们可能来自于全球各地,查看到的时间却是统一的服务器时间,对于高交互式的应用十分不友好
即使网站面向的用户仅来自于某一个地区,也会涉及到“夏时令”(Daylight Saving Time)相关的问题,
每年可能将会导致两次时间误差
TIME_ZONE
是默认时区的值
默认情况下,用django-admin生成的项目,其设置中USE_TZ等于True,这也是Django官方建议的配置。
此时
在网站内部存储与使用的是UTC时间
而与用户交互时使用TIME_ZONE或手工的时区
使用Django的 时间函数django.utils.timezone
now()
,返回当前的UTC时间
localtime()
,返回当前的本地时间(默认是TIME_ZONE配置指定的时区时间)
is_aware()
,传入的时间是否是aware datetime
is_naive()
,传入的时间是否是naive datetime
make_aware()
,将naive时间转换成aware时间
make_naive()
,将aware时间转换成naive时间
注意:
我们在获取当前时间的时候,一定要使用Django自带的now()
或localtime()
函数,
而不能使用Python的datetime.datetime.now()
函数
数据库存储的时间 ORM 的 DatetimeField
class Archive(models.Model):
title = models.CharField('title', max_length=256)
now_time = models.DateTimeField(default=timezone.now)
local_time = models.DateTimeField(default=timezone.localtime)
# 不管传入的时间对象时区是什么,其内部存储的时间均为UTC时区
# 不管使用a.now_time还是a.local_time,读取到的datetime对象的tzinfo都是UTC
返回给前端展示需要进行时区转换
data = dict(
id=object.pk,
now_time=object.now_time,
local_time=timezone.localtime(object.local_time) # 转换本地时间
)
return JsonResponse(data=data)
时间比较
1) 不涉及__day、__date、__year等时间lookups
,使用任何aware时间
均可(会被自动转换成UTC)
timezone.now timezone.localtime 都可以
from django.db import models
from django.utils import timezone
class Account(models.Model):
username = models.CharField(max_length=256)
password = models.CharField(max_length=64)
created_time = models.DateTimeField(default=timezone.now)
expired_time = models.DateTimeField()
if models.Account.objects.filter(expired_time__gt=timezone.now()).exists():
...
2) queryset查询,涉及到时间lookups时
,使用本地时间
timezone.localtime
Django
在使用日期、时间有关的lookups
时,会在数据库层面对时间进行时区的转换
再进行比较,
所以我们需要使用本地时间而不是UTC时间
models.Account.objects.filter(created_time__day=timezone.localtime().day).all()
# SQL语句中使用了django_datetime_extract('day', "sample_account"."created_time", 'Asia/Shanghai', 'UTC')
# 将UTC时间转换成了北京时间
注意:
任何比较都使用aware时间,不能使用naive时间
时间属性直接比较时,使用任何aware时间均可(会被自动转换成UTC)
queryset查询,不涉及__day、__date、__year等时间lookups时,使用任何aware时间均可(会被自动转换成UTC)
queryset查询,涉及到时间lookups时,使用本地时间