Python中时间处理模块的常见吐槽与优化方案

>>> dateutil.parser.parse("2017-03-09T09:32Z")
datetime.datetime(2017, 3, 9, 9, 32, tzinfo=tzutc())
>>> t1=dateutil.parser.parse("2017-03-09T09:32Z")
>>> t2=dateutil.parser.parse("2017-03-09T09:32Z").astimezone(dateutil.tz.tzstr("GMT+0800"))
>>> t1-t2
datetime.timedelta(0)
>>>
>>> t1
datetime.datetime(2017, 3, 9, 9, 32, tzinfo=tzutc())
>>> t2
datetime.datetime(2017, 3, 9, 17, 32, tzinfo=tzstr('GMT+0800'))
>>> t1-t2
datetime.timedelta(0)
>>> t2.strftime("%s")
'1489051920'
>>> t1.strftime("%s")
'1489023120'
>>>
  • datetime parse 的时候直接不管时区
  • 时间相等的 datetime 对象生成的时间戳居然不一样

为了方便小白理解?遇到好几个人觉得不同时区的时间戳不一样了……说不定是 Python 的锅


Python中时间处理模块的常见吐槽与优化方案

12 回复

不要用原生的时间处理模块,用第三方的库。比较有名的是 arrow
https://github.com/crsmithdev/arrow


Python里处理时间确实是个坑,datetime、time、pytz这些模块用起来经常让人头疼。最常见的问题就是时区处理,特别是naive datetime和aware datetime的转换问题。

import pytz
from datetime import datetime

# 常见坑:直接创建带时区的时间
dt = datetime(2024, 1, 1, 12, 0, tzinfo=pytz.timezone('Asia/Shanghai'))
# 这样创建会有问题,因为pytz时区对象不是简单的时区偏移

# 正确做法
tz = pytz.timezone('Asia/Shanghai')
dt = tz.localize(datetime(2024, 1, 1, 12, 0))
# 或者
dt = datetime(2024, 1, 1, 12, 0, tzinfo=tz)

另一个大坑是时间戳转换。Python的timestamp()方法返回的是UTC时间戳,但很多人以为返回的是本地时间。

# 时间戳转换的正确姿势
import time
from datetime import datetime

# 获取当前时间戳(UTC)
timestamp = time.time()  # 返回浮点数

# 时间戳转datetime
dt_utc = datetime.utcfromtimestamp(timestamp)  # 返回UTC时间
dt_local = datetime.fromtimestamp(timestamp)   # 返回本地时间

# datetime转时间戳
dt = datetime.now()
timestamp = dt.timestamp()  # 总是返回UTC时间戳

对于时区转换,推荐使用pytz或者Python 3.9+的zoneinfo:

# Python 3.9+ 推荐使用zoneinfo
from zoneinfo import ZoneInfo
from datetime import datetime

dt_utc = datetime(2024, 1, 1, 12, 0, tzinfo=ZoneInfo('UTC'))
dt_shanghai = dt_utc.astimezone(ZoneInfo('Asia/Shanghai'))

时间运算也有坑,比如跨夏令时的时间加减:

import pytz
from datetime import datetime, timedelta

tz = pytz.timezone('US/Eastern')
dt = tz.localize(datetime(2024, 3, 10, 1, 30))  # 夏令时开始前

# 直接加1小时会出问题
dt_wrong = dt + timedelta(hours=1)  # 这个时间在现实中不存在

# 正确做法:使用normalize方法
dt_correct = tz.normalize(dt + timedelta(hours=1))

格式化字符串也是个容易出错的地方,特别是%z和%Z的使用:

from datetime import datetime

dt = datetime.now()

# 错误的时区格式化
print(dt.strftime('%Y-%m-%d %H:%M:%S %Z'))  # 可能显示空字符串

# 正确的做法
from datetime import timezone
dt_utc = dt.astimezone(timezone.utc)
print(dt_utc.strftime('%Y-%m-%d %H:%M:%S %Z'))  # 显示UTC

对于时间解析,推荐使用dateutil.parser,它比strptime更灵活:

from dateutil import parser

# 自动解析各种格式的时间字符串
dt1 = parser.parse('2024-01-01')
dt2 = parser.parse('Jan 1, 2024 14:30')
dt3 = parser.parse('2024/01/01 2:30 PM')

总结:用对工具和方法很重要。

自己不看文档还怪 python 咯?
datetime.datetime 传的参数是本地时间,输出 timestamp 是是要转换到 UTC 的,你指定的时区不同,转换到 UTC 后当然不一样。
parse 的时候 2017-03-09T09:32Z 里面的 Z 就是 0 区的意思,你拿两个相同的时间相减,当然是等于 0 了。

好一个 输出 timestamp 是是要转换到 UTC 的

go 的时间模块也被吐槽的不行啊

推荐 pip install arrow
享受更好的时间处理

自带电池,只能让你享受一定程度的方便。(总比没电池好)

想更爽地使用,当然是插上电源,接通更人性化更现代的库, arrow, requests , jinja2 , lxml 。。。

难道你还用 urllib, str.format, etree ?



go 的 time 真的舒服嘛……

起码比较容易理解…

说 go 比 python 自带电池爽我也是没明白。。

不错了,
我在用 python 写时间时也郁闷过,相似功能的库太多了,一点都不正交,也不 pythonic
结果偶尔去写了个 js ,发现 js 居然没有内置时间格式化的函数,还得自己手撸,这才惨呢

回到顶部