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进阶教程之动态类型详解
Aug 30 Python
详解使用python的logging模块在stdout输出的两种方法
May 17 Python
利用Python将时间或时间间隔转为ISO 8601格式方法示例
Sep 05 Python
Django自定义manage命令实例代码
Feb 11 Python
Python数据分析matplotlib设置多个子图的间距方法
Aug 03 Python
pandas.DataFrame删除/选取含有特定数值的行或列实例
Nov 07 Python
对python操作kafka写入json数据的简单demo分享
Dec 27 Python
Python企业编码生成系统总体系统设计概述
Jul 26 Python
Python序列对象与String类型内置方法详解
Oct 22 Python
Pytorch .pth权重文件的使用解析
Feb 14 Python
Python3使用腾讯云文字识别(腾讯OCR)提取图片中的文字内容实例详解
Feb 18 Python
Python集合的基础操作
Nov 01 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文本数据库的搜索方法
2006/10/09 PHP
WordPress判断用户是否登录的代码
2011/03/17 PHP
PHP实现自动对图片进行滚动显示的方法
2015/03/12 PHP
laravel5创建service provider和facade的方法详解
2016/07/26 PHP
php如何获取Http请求
2020/04/30 PHP
imagettftext() 失效,不起作用
2021/03/09 PHP
10个基于Jquery的幻灯片插件教程
2010/10/29 Javascript
js动态修改input输入框的type属性(实现方法解析)
2013/11/13 Javascript
原生JS实现图片轮播与淡入效果的简单实例
2016/08/21 Javascript
JS转换HTML转义符的方法
2016/08/24 Javascript
AngularJs Understanding the Model Component
2016/09/02 Javascript
微信小程序 input输入框控件详解及实例(多种示例)
2016/12/14 Javascript
angularJs使用$watch和$filter过滤器制作搜索筛选实例
2017/06/01 Javascript
JavaScript实现选中文字提示新浪微博分享效果
2017/06/15 Javascript
基于Vue过渡状态实例讲解
2017/09/14 Javascript
JavaScript ES6常用基础知识总结
2019/02/09 Javascript
JS实现给数组对象排序的方法分析
2019/06/24 Javascript
Vue.js递归组件实现组织架构树和选人功能
2019/07/04 Javascript
vue 兄弟组件的信息传递的方法实例详解
2019/08/30 Javascript
详解NodeJs项目 CentOs linux服务器线上部署
2019/09/16 NodeJs
在Koa.js中实现文件上传的接口功能
2019/10/08 Javascript
vue视频播放暂停代码
2019/11/08 Javascript
JavaScript实现打砖块游戏
2020/02/25 Javascript
Vue数据双向绑定原理实例解析
2020/05/15 Javascript
ES2020让代码更优美的运算符 (?.) (??)
2021/01/04 Javascript
[59:07]海涛为你详解DOTA2新版本“贤哲秘契”
2014/11/22 DOTA
[01:44]《为梦想出发》—联想杯DOTA2完美世界全国高校联赛
2015/09/30 DOTA
Python cookbook(数据结构与算法)从任意长度的可迭代对象中分解元素操作示例
2018/02/13 Python
python 图片二值化处理(处理后为纯黑白的图片)
2019/11/01 Python
H&M旗下高端女装品牌:& Other Stories
2018/05/07 全球购物
德国专业木制品经销商:Holz-Direkt24
2019/12/26 全球购物
Python文件操作的面试题
2013/06/22 面试题
领班岗位职责范文
2014/02/06 职场文书
领导离职感言
2015/08/03 职场文书
学生会主席任命书
2015/09/21 职场文书
教你怎么用Python操作MySql数据库
2021/05/31 Python