48.python&&django时区转化

1.python时区转换:

最近工作中遇到了一个问题:我的server和client不是在一个时区,server时区是EDT,即美国东部时区,client,就是我自己的电脑,时区是中国标准时区,东八区。处于测试需要,我需要向server发送一个时间,使得server在这个时间戳去执行一些动作。这个时间戳通常是当前时间加2分钟或者几分钟。

通常美东在夏令时时,和我们相差12小时,所以直接减掉这12小时,然后再加两分钟,可以实现发送基于server的时间戳,但是只有一半时间是夏令时,所以考虑还是基于时区来做。百度了一下,Python有一个模块pytz是时区相关的,但不是builtin方法,所以需要安装一下。

1. 首先安装pytz,pip install pytz.

2. 试了一下水,打印出美国的时区:
    import pytz
    print(pytz.country_timezones('us'))  # 太长了自己打印
    
    
3.下一步,打印出美东的current time。
	import pytz
    import time
    import datetime
    tz = pytz.timezone('America/New_York')
    a = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
    print(a)

    #2016-08-18 02:26:53
    
4. 将时间转换为秒,加上120秒,然后再转换回标准格式:
    import pytz
    import time
    import datetime

    print(pytz.country_timezones('us'))
    tz = pytz.timezone('America/New_York')
    a = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
    print(a)
    b=time.mktime(time.strptime(a,'%Y-%m-%d %H:%M:%S'))+int(2)*60
    print(time.strftime("%Y-%m-%d %H:%M",time.localtime(b)))

2.django时区问题:

Django时间时区问题(received a naive datetime while time zone support is active)
在django1.4以后,存在两个概念
naive time(不带时区的时间)与 active time(带逝去的时间)。 timer.tzinfo查看所带时区,或者 import timezone , timzone.is_aware(timer) 带了返回true,不带返回false

举例来说,使用datetime.datetime.utcnow()、datetime.datetime.now()输出的类似2015-05-11 09:10:33.080451就是不带时区的时间(naive time),

而使用django.util.timezone.now()输出的类似2015-05-11 09:05:19.936835+00:00的时间就是带时区的时间(Active time),其中+00:00表示的就是时区相对性。

另外一个概念UTC时间,UTC时间表示的是格林尼治平均时即可,即零区时间。而北京时间表示的是东八区时间,即UTC+8。

下面列出了几个常见的时区问题
问题一:三个时间datetime.datetime.now()、datetime.datetime.utcnow()与django.util.timezone.now()的区别

datetime.datetime.now():输出的永远是本地时间(naive time)与配置无任任何关系。
datetime.datetime.utcnow():如果setting中配置USE_TZ=True则输出的是UTC时间(naive time),如果setting中配置USE_TZ=False,则该输出时间与datetime.datetime.now()完全相同。
django.util.timezone.now():如果setting中配置USE_TZ=True则输出的是UTC时间(active time),如果配置USE_TZ=False,则与datetime.datetime.now()完全相同。

问题二:django存储到数据库的时间比本地时间小8个小时?

首先要明确的一点,Django1.4版本之前,对时区毫无概概念,对时间的存取、展示不做任何处理,数据库里存储的通常是本地时间,当然都是naive time。
Django在1.4版本之后存储如果设置了USE_TZ=True,则存储到数据库中的时间永远是UTC时间。这时如果settings里面设置了USE_TZ=True与TIME_ZONE = 'UTC',用datetime.datetime.now()获取的时间django会把这个时间当成UTC时间存储到数据库中去。如果修改设置为USE_TZ=True与TIME_ZONE = 'Asia/Shanghai',用datetime.datetime.now()获取的时间由于不带时区,django会把这个时间当成Asia/Shanghai时间,即东八区时间,然后django会把这个时间转成带时区UTC时间存储到数据库中去,而读的时候直接按UTC时间读出来,这就是网上很多人遇到的存储到数据库中的时间比本地时间会小8个小时的原因。

问题三:DateTimeField role_cost_history.cost_time received a naive datetime (2015-05-12 19:59:01.259517) while time zone support is active?

这个问题是因为如果设置了USE_TZ=True之后,model里面认为DateTimeField使用UTC时间(带时区的时间),这时用datetime.datetime.now()获取的时间是不带时区的就会报这个问题。

问题四:django.util.timezone.now()输出时间比本地时间小8个小时

只要设置了USE_TZ=True,django.util.timezone.now()输出地永远是UTC时间,不管你设置的TIME_ZONE是什么。如果USE_TZ=False,则django.util.timezone.now()输出等同于datetime.datetime.now(),也不管TIME_ZONE设置的是什么。

问题五:模板显示时间

在设置了USE_TZ=True之后,如果设置了TIME_ZONE = 'Asia/Shanghai',尽管数据库中存储的是UTC时间,但在模板显示的时候,会转成TIME_ZONE所示的本地时间进行显示。

建议:为了统一时间,在django开发时,尽量使用UTC时间,即设置USE_TZ=True,TIME_ZONE = 'Asia/Shanghai',并且在获取时间的时候使用django.util.timezone.now()。因为后台程序使用时间时UTC时间就能满足,也能保证证模板时间的正确显示。

问题六:django时区问题解决 ***** 
    在Django的配置文件settings.py中,有两个配置参数是跟时间与时区有关的,分别是TIME_ZONE和USE_TZ.
    1.如果USE_TZ设置为True时,Django会使用系统默认设置的时区,即America/Chicago,此时的TIME_ZONE不管有没有设置都不起作用。

	2.如果USE_TZ 设置为False,而TIME_ZONE设置为None,则Django还是会使用默认的America/Chicago时间。

	3.如果TIME_ZONE设置为其它时区的话,则还要分情况,如果是Windows系统,则TIME_ZONE设置是没用的,Django会使用本机的时间。如果为其他系统,则使用该时区的时间,如设置USE_TZ = False, TIME_ZONE = 'Asia/Shanghai', 则使用上海的UTC时间。

    
根据上面的留个问题?
	我感觉直接设置为USE_TZ=True,是数据库存取都是用utc时间,TIME_ZONE使用UTC这样你存入数据库的时间和拿出来的时间都是utc,但是这个utc使用的却是你的本地时间.也就是说数据库存的是本地时间的UTC格式(可以理解为这个utc时间是假的,存的就是你本地时间,只不过因为你的TIME_ZONE设置的是UTC)
        TIME_ZONE = 'Asia/Shanghai'  # django中存入数据库(就是通过django Model建表字段中的的data相关的字段在生成时间时的时区auto_now 以及auto_now_add等)前获取时间过程使用时区(生成时)
        USE_TZ = True  # 存入数据库时的时候是否将存入的时间转换为utc时间(存之前)
	将经过TIME_ZONE生成的时间,存入数据库之前是否使用USE_TZ转换,True转化为UTC时间,False不转换
"""
	1.获取时间
        utc_time = datetime.utcnow()    # utcnow()获取世界标准时间。
        print(f'1、UTC时间为:{utc_time}')
     
        local_time = datetime.now()     # now() 获取本地时间。
        print(f'1、本地时间为:{local_time}')
    2.定义时区对象
        利用 timezone() 可以设置时区对象,里面参数可由 和 timedelta() 提供。
        timedelta() 是用来实现对日期的加减。参数如下:
        timedelta([days[, seconds[, microseconds[, milliseconds[, minutes[, hours[, weeks]]]]]]]) 
        从构造函数的定义中可以看出,所有参数都是可选的,并且默认都是0。
        from datetime import timezone, timedelta
        beijing = timezone(timedelta(hours=8))
        print(f'1、北京时区为:{beijing}')
        
        Tokyo = timezone(timedelta(hours=9))
        print(f'2、东京时区为:{Tokyo}')
         
        New_York = timezone(timedelta(hours=-4))
        print(f'3、纽约时区为:{New_York}')
         
        utc = timezone.utc
        print(f'4、世界标准时区为:{utc}'
    
"""
import datetime
import pytz
from django.utils import timezone

max = datetime.datetime.max.replace(tzinfo=datetime.timezone.utc)


def now():
    return datetime.datetime.utcnow().replace(tzinfo=pytz.utc)


def astimezone(dt: datetime.datetime, tzinfo: pytz.tzinfo.DstTzInfo):
    """如果带时区就转换"""
    assert timezone.is_aware(dt)
    return tzinfo.normalize(dt.astimezone(tzinfo))


def as_cn_cst(dt: datetime.datetime):
    """转换为上海时区"""
    return astimezone(dt, pytz.timezone('Asia/Shanghai'))


def as_current_tz(dt: datetime.datetime):
    """转换为本地时区"""
    return astimezone(dt, timezone.get_current_timezone())


def expires_hence(**delta):
    """时间的加减"""
    return now() + datetime.timedelta(**delta)


if __name__ == '__main__':
    import os, django
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'InfosecTestPlatform.settings')
    django.setup()
    tz = pytz.timezone("Asia/Shanghai")
    t1 = datetime.datetime.utcnow().replace(tzinfo=tz)
    t2 = datetime.datetime.utcnow().replace(tzinfo=timezone.utc)
    print(as_cn_cst(t1))
    print(as_cn_cst(t2))
    print(as_current_tz(t1))
    print(as_current_tz(t2))
    """
    3. astimezone修改时区操作
        2020-06-02 02:18:46.063493+08:00   # 会发现我给t1进行绑定初始时区为上海时间,然后再使用as_cn_cst转换的时候,他认为我的的时间本来就是上海时间,这个时候就不进+8操作
        2020-06-02 10:24:46.063493+08:00   # 而t2这个我将时区设置为utc时间,这是时候我和上海时间的差别是8小时,他自动给加上了
        2020-06-01 18:18:46.063493+00:00   # 这个函数是将时间转化为utc时间,我给t1设置的是上海时间,他给我减到了8小时之前
        2020-06-02 02:24:46.063493+00:00   # 这个时区我设置的就是utc所以没有进行转换
    总结:
        使用astimezone进行时区转化的时候,需要将你的时间有时区,同时建议统一的时区使用utc,方便之后转换,否则各种时区,搞乱之后,估计你也不知道使用的是哪个了.
        同时不建议使用astimezone进行时区修改,建议在数据库统一使用一个时区的时间,之后展示使用replace直接替换为你的本地时区
    """

参考:
https://www.cnblogs.com/nurruden/p/5783839.html

原文地址:https://www.cnblogs.com/liuzhanghao/p/12987082.html