0x00.问题发现
关于时间处理的爱恨情仇~
每个网站存储时间都有不同的格式,或者说有不同的显示格式,这一点在python里其实可以得到很丰富的转换和reformat
有一天遇到了一个没见过的warning
RuntimeWarning: DateTimeField received a naive datetime while time zone support is active.
虽然是warning,但是被写在log里也还是怪膈应的,所以探寻了一下问题的源头。
0x01.Time zones
首先,USE_TZ = True
在项目的settings中是默认的,他表示时间类型里会包含时区信息。默认的时区是UTC,如果不加修改的话,我们在shell里看到的时间会比现实时间晚8h哦
如果开启了USE_L10N
,地区也会被格式化。
0x02.Naive and aware datetime objects
打个比方:在做爬虫的时候,页县时间一般是不包含tz_info的,所以在存储的时候因为缺少时区信息,就会出现顶端的这个warning,这种时间就是naive的。
解决办法就是django提供了make aware方法来为naive time加上tz_info
使用这个方法要调用到 django.utils 中的timezone
aware_time = timezone.make_aware(naive_time, timezone.get_current_timezone())
还蛮好理解的吧
0x03.timezone.now() and datetime.now()
假设我们现在设置了USE_TZ = True,让我们来参观一下源码
timezone.now():
def now():
"""
Return 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()
显而易见的是,只有设置了Use_tz两者才有区别,USE_TZ的情况下,返回的是UTC的时间,并不受项目设置的影响(可能我会设置为Asia/Shanghai)
再来看看 datetime.now():
@classmethod
def now(cls, tz=None):
"Construct a datetime from time.time() and optional time zone info."
t = _time.time()
return cls.fromtimestamp(t, tz)
当直接调用datetime.now()的时候,并没有传进tz的参数,因此_fromtimestamp中的utc参数为False,所以converter被赋值为time.localtime
_fromtimestamp(cls, t, utc, tz):
(!省略)
converter = _time.gmtime if utc else _time.localtime
(!省略)
所以本质就是,时区会影响now()返回的信息
0x04.MySQL DatetimeField
mysql中的时间存储也和USE_TZ的设置有关联,如果你关闭了USE_TZ,
却向MySQL中存储了一个aware datetime object,就会报错
"ValueError: MySQL backend does not support timezone-aware datetimes. "
0x05.参考
https://docs.djangoproject.com/en/2.2/topics/i18n/timezones/
https://juejin.im/post/5848b301128fe1006907d5ed
网友评论