Python datetime 如何处理时区信息


Posted in Python onSeptember 02, 2020

在 Python 常用日期处理 -- 内置模块 datetime 探讨了 Python 如何使用 datetime, 如果是一个跨时区的应用(Web 应用都是),就不能只存储一个时间而不带时区,如此,全球用户将会看到一个相同的时间字符串,白天黑夜就错乱了。比说用户信息的更新时间存储为 2020-07-07 13:46:08, 上海的用户和芝加哥的用户看到的是同一个时间字符串,实质上却相差好多个小时。

我们可以这么做,在服务端只存储一个 Timestamp 长整型值或 UTC 时间,Timestamp 是无关乎时区的,它总是相对于一个 UTC 时间的偏移值; 然后由客户端根据本地时区来显示当地时间。不过在服务端存储为 Timestamp 或 UTC 可读性就不强了,打开文件看到 Timestamp 整形值,大脑是无法直接转换为日期,UTC 时间略好一些。

另一种做法可在服务端存储为开发者便于理解的带时区的时间,如 2020-07-07T13:46:08.342+08:00, 客户获得该时间,因为带有时区信息也就能转换为客户端本地时间。

客户端请求时还可以把本地的时区信息传送给服务端,由服务端转换为相应的本地时间发送给客户端,但 HTTP 头信息默认不带时区信息,客户端必须主动发送它。

本人倾向于在服务端存为带时区的时间,2020-07-07T13:46:08.342+08:00 是一个标准的存储格式(ISO_OFFSET_DATE_TIME),客户端收到它再转换本地时间,JavaScript 一个很好的组件 moment 处理时间。

探索 Python 对时区的处理

Python 内置组件不能像 Java 的 ZoneId.of("Asia/Shanghai") 直接以时区名获得 Zone,而需要知道与标准时区的偏移,如上海是东八区,在 Python 中要用 timezone(timedelta(hours=+8)).

那么来看 Python 中输出带时区信息,以下是一些应用 Pytho 时区 timezone 的例子

from datetime import datetime, timezone, timedelta
 
tz = timezone(timedelta(hours=+8))
 
fmt = '%Y-%m-%dT%H:%M:%S.%f%z'
zoned_time1 = datetime.today().astimezone(tz)
print(1, zoned_time1.strftime(fmt))  # 2020-07-08T04:30:26.221450+0800
 
zoned_time2 = datetime.now(tz)
print(2, zoned_time2.strftime(fmt))  # 2020-07-08T04:30:26.221543+0800
 
zoned_time3 = datetime.utcnow()
print(3, zoned_time3.isoformat())   # 2020-07-07T20:30:26.221848
 
print(4, zoned_time2.strftime('%Y-%m-%dT%H:%M:%S.%f%Z')) # 2020-07-08T04:30:26.221543UTC+08:00
 
timestamp = datetime.today().timestamp()
print(5, timestamp)         # 1594153826.221895
print(6, datetime.fromtimestamp(timestamp, tz=tz)) # 2020-07-08 04:30:26.221895+08:00
 
zoned_time4 = datetime(2020, 7, 8, 4, 23, 53, 112, tzinfo=tz)
print(7, zoned_time4.isoformat())  # 2020-07-08T04:23:53.000112+08:00
 
print(8, zoned_time2.isoformat())  # 2020-07-08T04:30:26.221543+08:00

输出为, 已加到上面源代码中

1 2020-07-08T04:30:26.221450+0800
2 2020-07-08T04:30:26.221543+0800
3 2020-07-07T20:30:26.221848
4 2020-07-08T04:30:26.221543UTC+08:00
5 1594153826.221895
6 2020-07-08 04:30:26.221895+08:00
7 2020-07-08T04:23:53.000112+08:00
8 2020-07-08T04:30:26.221543+08:00

时间字符串中要带有时区信息,首先时间要转换为带时区的,如用

datetime.astimezone(tz)          # 已有时间转换为带时区的
datetime.fromtimestamp(timestamp, tz=tz) # 从 timestamp 构建 datetime 时加上时区

找到 Python 输出标准格式的方法

从上面的输出结果看第 8 行 2020-07-08T04:30:26.221543+08:00 接近于 Java 的 ISO_OFFSET_DATE_TIME 格式,只是毫秒段 Python 用了 6 位数字,参考 strftime-strptime-behavior 的 Python datetime 格式字符串定义找不到如何把毫秒段收缩为 3 位。

不过注意到 datetime.isoformat() 方法还有一个 timespec 可用,执行下面的代码

from datetime import datetime, timezone, timedelta
 
tz = timezone(timedelta(hours=+8))
now = datetime.now(tz)
print(now.isoformat(timespec='milliseconds'))

输出为

2020-07-08T04:41:10.793+08:00

这正式我们想要的。还不仅仅是,继续往下读,我们还需要让 Python 支持夏令时,否则对于芝加哥时间夏天和冬天看到的都是 -5, 那是不对的。

pytz 组件构建时区

Python 也有一个通过时区名称获得 timezone 的组件,那就是 pytz - Python TimeZone

$ pip install pytz

测试 pytz

from datetime import datetime
from pytz import timezone
 
tz_shanghai = timezone('Asia/Shanghai')
tz_chicago = timezone('America/Chicago')
 
print(datetime.now(tz=tz_shanghai).isoformat(timespec='milliseconds'))
print(datetime.now(tz=tz_chicago).isoformat(timespec='milliseconds'))

输出为

2020-07-08T04:55:29.699+08:00
2020-07-07T15:55:29.699-05:00

关于夏令时与冬令时

国内实行夏令时制还是很多年前的事了,80 后初期生人或许还有些印象,就是下午放了学走到街上就能看到《新闻联播》。为了达成一切形式的统一,我们不再实行夏令时制了,避免了造成可能的分裂。但其他国家仍然有下令时,这会造成同一个地方在一年中产生两个时区。

例如芝加哥,在夏季时 timezone 是 -05:00, 冬季时是 -06:00.

现在就来看一下 Python 是否能正确的处理夏令时(Date Saving Time)与冬令时(Night Saving Time)。回看上面代码是在 7 月份执行的结果,此时如果把本地时间改为 12 月份,再看输出

2020-12-08T06:10:27.862+08:00
2020-12-07T16:10:27.862-06:00

上海的时区仍然为 +08:00, 而芝加哥的时区变成了 -06:00

Python 本身不支持对时令的支持,Python 只知道与 UTC 标准时区的偏移,timezone(timedelta(hours=-5),夏天冬天它的偏移都是 -5,实现夏令冬令时是由 pytz 达成的,同样的 tz = timezone('America/Chiago')

夏天的结果是 Python 的 timezone(timedelta(hours=-5))
冬天的结果是 Python 的 timezone(timedelta(hours=-6))

对比 Java 对时区的处理

不妨看下隔壁 Java 是如何对时区处理的,分别测试了新旧时间 API

Date today = new Date();
System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX").format(today));
 
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println(now.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));

2020-07-07T14:53:55.017-05:00
2020-07-08T03:53:55.031+08:00

小结一下

时间用 Timestamp(长整形值) 或统一的 UTC 时间存储和传输,在显示时转换为本地时间,但存储介质上可读性差
用 timezone(timedelta(hours=-5)) 应用时区来存储,可读性增强,但会有夏/冬令时间误差问题
用 pytz 的 timezone('America/Chicago') 由时区名来构造 timezone 很好的解决了时区和夏/冬令时的问题

以上就是Python datetime 如何处理时区信息的详细内容,更多关于Python datetime 处理时区信息的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
Python读取mp3中ID3信息的方法
Mar 05 Python
python基于socket实现网络广播的方法
Apr 29 Python
Python 转义字符详细介绍
Mar 21 Python
TensorFlow变量管理详解
Mar 10 Python
解决python爬虫中有中文的url问题
May 11 Python
Python3.6实现带有简单界面的有道翻译小程序
Apr 16 Python
对python中不同模块(函数、类、变量)的调用详解
Jul 16 Python
wxPython电子表格功能wx.grid实例教程
Nov 19 Python
如何给Python代码进行加密
Jan 10 Python
用python写PDF转换器的实现
Oct 29 Python
Python 中Operator模块的使用
Jan 30 Python
详解Python牛顿插值法
May 11 Python
浅析python中的del用法
Sep 02 #Python
浅析NumPy 切片和索引
Sep 02 #Python
详解Python 函数参数的拆解
Sep 02 #Python
Python 常用日期处理 -- calendar 与 dateutil 模块的使用
Sep 02 #Python
python 常用日期处理-- datetime 模块的使用
Sep 02 #Python
详解Python中的路径问题
Sep 02 #Python
python dict如何定义
Sep 02 #Python
You might like
php生成xml简单实例代码
2009/12/16 PHP
PHP中的事务使用实例
2015/05/26 PHP
laravel实现查询最后执行的一条sql语句的方法
2019/10/09 PHP
dropdownlist之间的互相联动实现(显示与隐藏)
2009/11/24 Javascript
JavaScript中的变量作用域介绍
2014/12/31 Javascript
node.js中的forEach()是同步还是异步呢
2015/01/29 Javascript
iscroll.js的上拉下拉刷新时无法回弹的解决方法
2016/02/18 Javascript
基于jQuery实现音乐播放试听列表
2016/04/14 Javascript
js html5 css俄罗斯方块游戏再现
2016/10/17 Javascript
原生JS 购物车及购物页面的cookie使用方法
2017/08/21 Javascript
自定义类似于jQuery UI Selectable 的Vue指令v-selectable
2017/08/23 jQuery
nodejs 如何手动实现服务器
2018/08/20 NodeJs
Vue通过ref父子组件拿值方法
2018/09/12 Javascript
vue-video-player视频播放器使用配置详解
2020/10/23 Javascript
vue 函数调用加括号与不加括号的区别
2020/10/29 Javascript
原生JS实现弹幕效果的简单操作指南
2020/11/10 Javascript
[10:34]DOTA2上海特级锦标赛全纪录
2016/03/25 DOTA
详解Python中的多线程编程
2015/04/09 Python
学习python之编写简单乘法口诀表实现代码
2016/02/27 Python
python 网络爬虫初级实现代码
2016/02/27 Python
Python中不同进制的语法及转换方法分析
2016/07/27 Python
浅谈python的dataframe与series的创建方法
2018/11/12 Python
深入理解Django-Signals信号量
2019/02/19 Python
将python运行结果保存至本地文件中的示例讲解
2019/07/11 Python
python如何保存文本文件
2020/06/07 Python
Python猫眼电影最近上映的电影票房信息
2020/09/18 Python
python读取excel数据并且画图的实现示例
2021/02/08 Python
涂鸦板简单实现 Html5编写属于自己的画画板
2016/07/05 HTML / CSS
HTML5 绘制图像(上)之:关于canvas元素引领下一代web页面的问题
2013/04/24 HTML / CSS
分享全球十款超强HTML5开发工具
2014/05/14 HTML / CSS
Bjorn Borg官方网上商店:国际运动时尚品牌
2016/08/27 全球购物
新员工欢迎词
2014/01/12 职场文书
《童年的发现》教学反思
2014/02/14 职场文书
公司应聘自荐书
2014/06/14 职场文书
2016党校培训心得体会
2016/01/07 职场文书
python opencv旋转图片的使用方法
2021/06/04 Python