• Python关于时区与时间相关的操作汇总


      日常的开发过程中总会与到日期与时间的处理,尤其是最近的2个项目都还会遇到时区问题,个人在开发的过程中也遇到过不同的问题,这里总结一下Python操作日期与时间相关的方案。

    《PythonCookBook》中关于日期时间的操作

      这本书中关于日期时间的操作非常值得参考:第三章:数字日期和时间

    个人之前总结的博客

          time模块

          datetime模块 

          分割处理存放连续时间字符串的列表

          datetime模块格式化以及去掉前导0的操作说明

          pymysql往数据库中插入datetime类型的"空数据"与MySQL5.7sql_mode的一个问题

    关于时区操作的pytz模块 ***

       有的时候我们会看到类似"10/Sep/2015:06:47:35"或"2015-9-10T06:47:35"这样的时间字符串。首先要强调的是上面两种表达方式无论哪一种都是错误的表达方式,因为没有时区的时间字符串是没有意义的!!!

      整个世界被分为12个时区,从-12~+12,负数代表西时区,而正数代表东时区,以英国的0时区为中心。比如中国的时区可以用+8来表示,更多的使用+08:00或+0800来表示,读作“东八区”。有些时候我们用CST时间表示中国标准时间,或者在某些操作系统中使用’Asia/Shanghai’代表东八区。

      所以正确的时间字符串应当是"10/Sep/2015:06:47:35 +0800""2015-9-10T06:47:35+0800"的包含时区的格式,如果不是,那么请确认你得到这份包含时间数据的语境以确保知道其时区,因为毕竟不同时区的同一时间实际上是不同的时间。

    获取0时区的操作

      直接使用内置的datetime模块中的utcnow方法:

    使用pytz模块转换时区

      使用第三方模块 pytz

     注意1

      时区的英文名称,比如这里使用的’Asia/Shanghai',我们如何才能知道其他地区的时区呢?可以通过pytz.all_timezones这个属性获取。

    注意2

      时间格式化函数strftime()及其参数’%Y-%m-%d %H:%M:%S%z’。

      这个函数的意思是将datetime类型的时间格式化成其参数所描述的格式,在上面的程序中很明显地,Y代表年,m代表月,d代表日,H代表小时,M代表分钟,S代表秒,z代表时区。

     

    字符串与时间戳相互转换的arrow模块 ***

    将包含时区的时间字符串转换成时间戳 ***

      相关的案例代码如下:

    import time
    from datetime import datetime
    
    import pytz
    import arrow
    
    
    tz = pytz.timezone("Asia/Shanghai")
    dt = datetime.utcnow()
    print("dt>>>",dt) # dt>>> 2020-09-28 11:05:43.693912
    time_now = time.time()
    print("time_now>>>",time_now) # time_now>>> 1601291143.693969
    
    # 格式化方式1
    cst_time1 = tz.fromutc(dt).strftime("%Y-%m-%d %H:%M:%S%z")
    print("sct_time1>>>",cst_time1) # sct_time1>>> 2020-09-28 19:05:43+0800
    arrow1 = arrow.get(cst_time1,"YYYY-MM-DD HH:mm:ssZ").timestamp
    print("arrow1>>>",arrow1) # arrow1>>> 1601291143
    
    # 格式化方式2
    cst_time2 = tz.fromutc(dt).strftime("%d/%b/%Y:%H:%M:%S%z")
    print("cst_time2>>>",cst_time2) # cst_time2>>> 28/Sep/2020:19:05:43+0800
    arrow2 = arrow.get(cst_time2,"DD/MMM/YYYY:HH:mm:ssZ").timestamp
    print("arrow2>>>",arrow2) # arrow2>>> 1601291143
    
    # 格式化方式3
    cst_time3 = tz.fromutc(dt).strftime("%Y-%m-%dT%H:%M:%S %z")
    print("cst_time3>>>",cst_time3) # cst_time3>>> 2020-09-28T19:05:43 +0800
    arrow3 = arrow.get(cst_time3,"YYYY-MM-DDTHH:mm:ss Z").timestamp
    print("arrow3>>>",arrow3) # arrow3>>> 1601291143
    
    # 格式化方式4
    cst_time4 = tz.fromutc(dt).strftime("%c %z")
    print("cst_time4>>>",cst_time4) # cst_time4>>> Mon Sep 28 19:05:43 2020 +0800
    arrow4 = arrow.get(cst_time4,"ddd MMM DD HH:mm:ss YYYY Z").timestamp
    print("arrow4>>>",arrow4) # arrow4>>> 1601291143

      有一点稍稍让人感到困扰,arrow需要的字符串格式化参数与Python标准库datetime的不同,虽然看起来大同小异,不过还是需要稍微熟悉一下。

    将时间戳转换成时间字符串 ***

      下面的代码分别使用Python标准库和arrow两种方法进行举例:

    import time
    from datetime import datetime
    
    import pytz
    import arrow
    
    tz = pytz.timezone("Asia/Shanghai")
    dt = datetime.utcnow()
    print("dt>>>",dt) # dt>>> 2020-09-28 11:51:32.814224
    time_now = time.time()
    print("time_now>>>",time_now) # time_now>>> 1601293892.814267
    
    ### python标准库方案
    ret1 = tz.fromutc(datetime.utcfromtimestamp(time_now)).strftime("%Y-%m-%d %H:%M:%S %z")
    print("标准库方案>>>",ret1,type(ret1)) # 标准库方案>>> 2020-09-28 19:51:32 +0800 <class 'str'>
    
    ### arrow方案
    ret2 = arrow.get(time_now).to(tz).format("YYYY-MM-DD HH:mm:ss Z")
    print("arrow方案>>>",ret2,type(ret2)) # arrow方案>>> 2020-09-28 19:51:32 +0800 <class 'str'>

    ~~~

    开始的时间是当天的0点的获取方式

    # 开始时间是当天的0点
    until = datetime.now()
    now_date_str = until.strftime("%Y-%m-%d")
    year, month, day = now_date_str.split("-")
    since = datetime(int(year), int(month), int(day), 00, 00, 00)

    使用字符串格式化进行时区转换

      实现的方式比较low(0-0),当作是笔记把!!!

      注意这种方式是在特定的业务场景下使用的,下面我会详细介绍。

      在实际的业务中,我使用SDK获取到的日期的格式是这样的:

    "created_time": "2020-09-11T18:42:32+0800"

      后面的 +0800 就是“东八区”的意思。我需要将获取到的数据经过结构的构建与逻辑的处理最后存入到MySQL数据库中。   

      但是数据的日期在数据库中必须按照 UTC0时区 的格式存储(历史原因...),所以我还需要额外的处理一下时区。网上找了很多这方面的资料,但是感觉还是跟自己业务逻辑相差比较远,根据自己的认真观察,发现存入数据库的日期数据其实就比当前获取的时间晚8小时——所以干脆进行timedelta操作就可以了...

      下面是实现的demo:

    # 业务代码略
    ret2 = cam.api_get(fields=fields)
    
    updated_time = ret2["updated_time"]
    print("updated_time>>>>>",updated_time) # updated_time>>>>> 2020-09-23T00:02:02+0800
    
    ### 如果是东8区时间 往后推8小时!!!
    if "0800" in updated_time:
        # 按照东8区的格式格式化
        print(updated_time, type(updated_time))  # 2020-09-23T00:02:02+0800 <class 'str'>
        publish_time = datetime.strptime(updated_time, "%Y-%m-%dT%H:%M:%S+0800")
        # 往后推8小时就是UTC时间
        publish_time = publish_time - timedelta(hours=8)
    # 如果是UTC时间直接处理并写入数据库
    elif "0000" in updated_time:
        # 按照UTC的格式格式化
        publish_time = datetime.strptime(updated_time, "%Y-%m-%dT%H:%M:%S+0000")
    else:
        raise Exception("时间格式不规范")
    
    ### 需要转换成str类型才能写入数据库!!!
    publish_time = str(publish_time)
    print("<<<<<",publish_time) # <<<<< 2020-09-22 16:02:02  

    ~~~

  • 相关阅读:
    机器学习 xgboost 笔记
    leetcode python 042收集雨水
    leetcode python 041首个缺失正数
    leetcode python 037 求解数独
    leetcode python 033 旋转数组查找
    jquery练习
    前端学习课件
    前端CSS
    MySQL_总目录
    MySQL之索引原理与慢查询优化
  • 原文地址:https://www.cnblogs.com/paulwhw/p/13745640.html
Copyright © 2020-2023  润新知