工作生活

Django timezone

2019-07-02  本文已影响0人  catttthrine

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

上一篇下一篇

猜你喜欢

热点阅读