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中的并发编程实例
Jul 07 Python
使用IronPython把Python脚本集成到.NET程序中的教程
Mar 31 Python
TensorFlow实现Logistic回归
Sep 07 Python
python3.6下Numpy库下载与安装图文教程
Apr 02 Python
Python实现通过解析域名获取ip地址的方法分析
May 17 Python
pandas.read_csv参数详解(小结)
Jun 21 Python
python批量读取文件名并写入txt文件中
Sep 05 Python
python自动结束mysql慢查询会话的实例代码
Oct 27 Python
Python实现socket非阻塞通讯功能示例
Nov 06 Python
Python tkinter三种布局实例详解
Jan 06 Python
python和php学习哪个更有发展
Jun 17 Python
Python机器学习之KNN近邻算法
May 14 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 图片上传实现代码 带详细注释
2010/04/29 PHP
20个2014年最优秀的PHP框架回顾
2014/10/22 PHP
LaravelS通过Swoole加速Laravel/Lumen详解
2018/03/02 PHP
一种JavaScript的设计模式
2006/11/22 Javascript
jquery的$getjson调用并获取远程的JSON字符串问题
2012/12/10 Javascript
windows系统下简单nodejs安装及环境配置
2013/01/08 NodeJs
JQuery slideshow的一个小问题(如何发现及解决过程)
2013/02/06 Javascript
js定时器(执行一次、重复执行)
2014/03/07 Javascript
JS实现进入页面时渐变背景色的方法
2015/02/25 Javascript
纯JavaScript实现的兼容各浏览器的添加和移除事件封装
2015/03/28 Javascript
JavaScript中的pow()方法使用详解
2015/06/15 Javascript
jquery表格datatables实例解析 直接加载和延迟加载
2016/08/12 Javascript
Vue.js常用指令汇总(v-if、v-for等)
2016/11/03 Javascript
详解node.js搭建代理服务器请求数据
2017/04/08 Javascript
微信小程序实现图片懒加载的示例代码
2017/12/13 Javascript
nodeJS模块简单用法示例
2018/04/21 NodeJs
Vue中使用的EventBus有生命周期
2018/07/12 Javascript
Vue中JS动画与Velocity.js的结合使用
2019/02/13 Javascript
JavaScript生成一个不重复的ID的方法示例
2019/09/16 Javascript
js实现盒子移动动画效果
2020/08/09 Javascript
pyenv命令管理多个Python版本
2017/03/26 Python
python操作小程序云数据库实现简单的增删改查功能
2019/06/06 Python
Scrapy爬虫文件批量运行的实现
2020/09/30 Python
Python绘制K线图之可视化神器pyecharts的使用
2021/03/02 Python
使用JS+CSS3技术:让你的名字动起来
2013/04/27 HTML / CSS
利用CSS3的border-radius绘制太极及爱心图案示例
2016/05/17 HTML / CSS
美国婴儿用品店:Babies”R”Us
2017/10/12 全球购物
美国在线购买和出售礼品卡网站:EJ Gift Cards
2019/06/09 全球购物
餐饮营销方案
2014/02/23 职场文书
项目经理聘任书
2014/03/29 职场文书
诚信教育主题班会
2015/08/13 职场文书
学雷锋广播稿大全
2015/08/19 职场文书
先进党支部事迹材料2016
2016/02/26 职场文书
SQL SERVER存储过程用法详解
2022/02/24 SQL Server
Pycharm远程调试和MySQL数据库授权问题
2022/03/18 MySQL
vscode内网访问服务器的方法
2022/06/28 Servers