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查找相似单词的方法
Mar 05 Python
安装ElasticSearch搜索工具并配置Python驱动的方法
Dec 22 Python
Python读取指定目录下指定后缀文件并保存为docx
Apr 23 Python
windows下Python实现将pdf文件转化为png格式图片的方法
Jul 21 Python
python实现百万答题自动百度搜索答案
Jan 16 Python
django用户注册、登录、注销和用户扩展的示例
Mar 19 Python
python定时检测无响应进程并重启的实例代码
Apr 22 Python
使用Python-OpenCV向图片添加噪声的实现(高斯噪声、椒盐噪声)
May 28 Python
python常见字符串处理函数与用法汇总
Oct 30 Python
python opencv图片编码为h264文件的实例
Dec 12 Python
keras model.fit 解决validation_spilt=num 的问题
Jun 19 Python
Python基础之元组与文件知识总结
May 19 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-CGI进程CPU 100% 与 file_get_contents 函数的关系分析
2011/08/15 PHP
PHP获取指定时间段之间的 年,月,天,时,分,秒
2016/06/05 PHP
Prototype 学习 工具函数学习($A方法)
2009/07/12 Javascript
不要在cookie中使用特殊字符的原因分析
2010/07/13 Javascript
通过Jscript中@cc_on 语句识别IE浏览器及版本的代码
2011/05/07 Javascript
Jquery 表格合并的问题分享
2011/09/17 Javascript
jQuery对象的selector属性用法实例
2014/12/27 Javascript
javascript操作select元素实例分析
2015/03/27 Javascript
jquery中$each()方法的使用指南
2015/04/30 Javascript
jQuery结合CSS制作漂亮的select下拉菜单
2015/05/03 Javascript
Javascript简写条件语句(推荐)
2016/06/12 Javascript
nodejs基础知识
2017/02/03 NodeJs
原生JS实现图片翻书效果
2017/02/16 Javascript
angularjs $http实现form表单提交示例
2017/06/09 Javascript
JavaScript之面向对象_动力节点Java学院整理
2017/06/29 Javascript
Underscore之Array_动力节点Java学院整理
2017/07/10 Javascript
vue.js实现的经典计算器/科学计算器功能示例
2018/07/11 Javascript
Vue.js组件间通信方式总结【推荐】
2018/11/23 Javascript
Vue项目中数据的深度监听或对象属性的监听实例
2020/07/17 Javascript
python实现mysql的单引号字符串过滤方法
2015/11/14 Python
用python找出那些被“标记”的照片
2017/04/20 Python
python二维列表一维列表的互相转换实例
2018/07/02 Python
keras分类模型中的输入数据与标签的维度实例
2020/07/03 Python
python3爬虫中异步协程的用法
2020/07/10 Python
HTML4和HTML5之间除了相似以外的10个主要不同
2012/12/13 HTML / CSS
五分钟学会HTML5的WebSocket协议
2019/11/22 HTML / CSS
新西兰床上用品和家居用品购物网站:Adairs
2018/04/27 全球购物
成功经营餐厅的创业计划书范文
2013/12/26 职场文书
中介业务员岗位职责
2014/04/09 职场文书
安全承诺书格式
2014/05/21 职场文书
政府个人对照检查材料思想汇报
2014/10/08 职场文书
个人股份合作协议书
2014/10/24 职场文书
综治工作汇报材料
2014/10/27 职场文书
2015年毕业实习工作总结
2014/12/12 职场文书
公司人力资源管理制度
2015/08/05 职场文书
保安辞职申请书应该怎么写?
2019/07/15 职场文书