美文网首页
naive和aware时间

naive和aware时间

作者: 小吉头 | 来源:发表于2020-06-14 22:48 被阅读0次

python中什么是naive时间和aware时间

naive时间表示幼稚时间,不知道自己所在的时区
aware时间表示清醒时间,知道自己所在时区

aware时间的作用

aware时间知道自己的时区,在国际化时可以方便的转换成其它时区。开发中一般都用aware时间。

举个例子

使用比较多的datetime.now()返回的其实是naive时间,比如naive时间转utc时区,会抛异常

from datetime import datetime
import pytz

naive_date = datetime.now()
target_timezone = pytz.timezone("UTC")
utc_date = naive_date.astimezone(target_timezone) #astimezone()作用是转换时区
#抛异常
>>>astimezone() cannot be applied to a naive datetime

naive转aware后再改时区

#naive时间转aware时间
from datetime import datetime
import pytz

naive_date = datetime.now()
print(naive_date)
target_timezone = pytz.timezone("Asia/Shanghai")
aware_date = naive_date.replace(tzinfo=target_timezone)#replace()作用是修改时间属性,可以修改年月日时分秒、时区
print(aware_date)
utc_timezone = pytz.timezone("UTC")
utc_date = aware_date.astimezone(utc_timezone)
print(utc_date)
>>>2020-06-10 18:22:59.108800
>>>2020-06-10 18:22:59.108800+08:06
>>>2020-06-10 10:16:59.108800+00:00

可以看到打印结果,区别就是有没有带上时区

django中怎么生成aware时间

直接生成aware时间:
from django.utils import timezone
print(timezone.now())
>>>2020-06-10 10:32:06.143800+00:00

打印结果是一个utc时区的aware时间,看下源码timezone.now()这个函数做了什么:

def now():
    """
    Returns an aware or naive datetime.datetime, depending on settings.USE_TZ.
    """
    if settings.USE_TZ:
        # timeit shows that datetime.now(tz=utc) is 24% slower
        return datetime.utcnow().replace(tzinfo=utc)
    else:
        return datetime.now()

如果settings.py文件中USE_TZ = True,将datetime.utcnow()返回的utc naive时间修改成utc aware时间。如果是False返回datetime.now(),是基于当前时区的naive时间。

naive时间转aware时间:
from django.utils.timezone import make_aware
naive_time = datetime(year=2020,month=5,day=31,hour=8)
print(naive_time)
aware_time = make_aware(naive_time)
print(aware_time)
>>>2020-05-31 08:00:00
>>>2020-05-31 08:00:00+08:00

可以自行查看下make_aware的实现代码,如果没有传timezone参数,使用的是settings文件的TIME_ZONE属性,这里aware时间时区显示+8是因为TIME_ZONE = 'Asia/Shanghai'

ORM中常用的时间查询

有了上面的时间概念,来看下orm中的时间查询示例
订单表如下:

+----+-----------+----------------------------+
| id | order_num | create_time                |
+----+-----------+----------------------------+
|  1 | 002       | 2020-05-31 08:29:41 |
|  2 | 001       | 2020-05-31 08:59:35 |
+----+-----------+----------------------------+
range
#USE_TZ = True
start_date = datetime(year=2020,month=5,day=31,hour=8)
end_date = datetime(year=2020,month=5,day=31,hour=9)
orders = Order.objects.filter(create_time__range=(start_date,end_date))
print(orders.query)
print(orders)
>>>RuntimeWarning: DateTimeField Order.create_time received a naive datetime (2020-05-31 08:00:00) while time zone support is active.
>>>SELECT `goods_order`.`id`, `goods_order`.`order_num`, `goods_order`.`create_time` FROM `goods_order` WHERE `goods_order`.`create_time` BETWEEN 2020-05-31 00:00:00 AND 2020-05-31 01:00:00
>>><QuerySet []>
#USE_TZ = False
>>>SELECT `goods_order`.`id`, `goods_order`.`order_num`, `goods_order`.`create_time` FROM `goods_order` WHERE `goods_order`.`create_time` BETWEEN 2020-05-31 08:00:00 AND 2020-05-31 09:00:00
>>><QuerySet [<Order: Order object>, <Order: Order object>]>

如果USE_TZ = True,我理解的sql翻译的规则是:ORM会在逻辑上将settings中的TIME_ZONE 对应的时区直接附加到查询时间上,再计算出对应的utc时间,比如2020-5-31 9:00,假设TIME_ZONE = Asia/Shanghai,逻辑上看做2020-5-31 9:00+08:00,计算出的utc时间就是2020-5-31 1:00+00:00
通过警告可以看出是一个2020-05-31 08:00:00的naive时间,要想得到正确结果并且取消警告,操作如下:

start_date = make_aware(datetime(year=2020,month=5,day=31,hour=16))
end_date = make_aware(datetime(year=2020,month=5,day=31,hour=17))
...
>>>SELECT `goods_order`.`id`, `goods_order`.`order_num`, `goods_order`.`create_time` FROM `goods_order` WHERE `goods_order`.`create_time` BETWEEN 2020-05-31 08:00:00 AND 2020-05-31 09:00:00
>>><QuerySet [<Order: Order object>, <Order: Order object>]>
date,根据年月日查找
#USE_TZ = True
search_date = datetime(year=2020,month=5,day=31)
orders = Order.objects.filter(create_time__date=search_date)
print(orders.query)
print(orders)
>>>SELECT `goods_order`.`id`, `goods_order`.`order_num`, `goods_order`.`create_time` FROM `goods_order` WHERE DATE(CONVERT_TZ(`goods_order`.`create_time`, 'UTC', Asia/Shanghai)) = 2020-05-31
>>><QuerySet []>
#USE_TZ = False
>>>SELECT `goods_order`.`id`, `goods_order`.`order_num`, `goods_order`.`create_time` FROM `goods_order` WHERE DATE(`goods_order`.`create_time`) = 2020-05-31
>>><QuerySet [<Order: Order object>, <Order: Order object>]>

如果USE_TZ = True,查询结果为空,DATE(CONVERT_TZ(goods_order.create_time, UTC, Asia/Shanghai))使用了时区mysql表中没有存储时区信息,windows相同可以在http://dev.mysql.com/downloads/timezones.html下载文件解压后复制到mysql5.7.24\data\mysql下,再次查询即可查到正确的数据。

week_day,根据星期查找

1-7表示从周日到周六

#USE_TZ = True
orders = Order.objects.filter(create_time__week_day=1)
print(orders.query)
print(orders)
>>>SELECT `goods_order`.`id`, `goods_order`.`order_num`, `goods_order`.`create_time` FROM `goods_order` WHERE DAYOFWEEK(CONVERT_TZ(`goods_order`.`create_time`, 'UTC', Asia/Shanghai)) = 1
>>><QuerySet [<Order: Order object>, <Order: Order object>]>
#USE_TZ = False
>>>SELECT `goods_order`.`id`, `goods_order`.`order_num`, `goods_order`.`create_time` FROM `goods_order` WHERE DAYOFWEEK(`goods_order`.`create_time`) = 1
>>><QuerySet [<Order: Order object>, <Order: Order object>]>
time,根据时分秒查找
#USE_TZ = True
from datetime import time
search_time = time(hour=16,minute=59,second=35)
orders = Order.objects.filter(create_time__time=search_time)
print(orders.query)
print(orders)
>>>SELECT `goods_order`.`id`, `goods_order`.`order_num`, `goods_order`.`create_time` FROM `goods_order` WHERE TIME(CONVERT_TZ(`goods_order`.`create_time`, 'UTC', Asia/Shanghai)) = 16:59:35
>>><QuerySet [<Order: Order object>]>
#USE_TZ = False
search_time = time(hour=8,minute=59,second=35)
>>>SELECT `goods_order`.`id`, `goods_order`.`order_num`, `goods_order`.`create_time` FROM `goods_order` WHERE TIME(`goods_order`.`create_time`) = 08:59:35
>>><QuerySet [<Order: Order object>]>

精确到秒,一般使用time进行范围查询:

#USE_TZ = True
start_time = time(hour=16,minute=59,second=35)
start_end = time(hour=16,minute=59,second=36)
Order.objects.filter(create_time__time__range=(start_time,end_time))

相关文章

  • naive和aware时间

    python中什么是naive时间和aware时间 naive时间表示幼稚时间,不知道自己所在的时区aware时间...

  • datetime

    naive aware对于datetime.datetime和datetime.time类型才有aware对象最佳...

  • pytz

    提供了两种方式来构建本地时间 localize 用于naive时间转换 astimezone 用于aware时间转...

  • TypeError: can't compare offset-

    TypeError: can't compare offset-naive and offset-aware da...

  • pandas 时区问题

    术语解释:naive(无时区类型数据), aware(有时区类型数据)pandas中, datetime和time...

  • python时间问题

    python的时间分为带有时区的tz-aware和没有时区的tz-naive,这两个时间无法进行比较,必须转换为同...

  • Python中datetime的常用操作

    总结几个我们在程序中常用到的关于datetime的操作,以供参考。 一、naive类型和aware类型的相互转换。...

  • 模型常用字段-navie和aware类型时间

    navie时间和aware时间 navie没有指定时区的,不知道自己的时间。 aware指定了时区,知道自己的时间...

  • spring中Aware后缀

    aware: 意识到的;知道的; spring中带有Aware后缀的接口主要是和bean有关,实现了Aware后...

  • [Spring]Spring的Aware接口-装配

    Aware Aware:察觉的、意识到的。英文示例: She was not aware of having d...

网友评论

      本文标题:naive和aware时间

      本文链接:https://www.haomeiwen.com/subject/izynohtx.html