Skip to content

25|日期与时间

程序中处理时间的场景很多:记录事件发生的时刻、计算两个时间点之间的间隔、格式化输出给用户看、解析用户输入的时间字符串。Python 的 datetime 模块提供了完整的日期时间处理能力。

一、datetime 对象

python
from datetime import datetime, date, time, timedelta

# 当前日期时间
now = datetime.now()
print(now)   # 2024-06-01 10:30:15.123456

# 当前日期
today = date.today()
print(today)   # 2024-06-01

# 指定日期时间创建
dt = datetime(2024, 6, 1, 10, 30, 0)
print(dt)   # 2024-06-01 10:30:00

datetime 包含日期和时间两部分。date 只有日期,time 只有时间。

二、格式化输出

strftime() 把 datetime 对象格式化成字符串:

python
now = datetime.now()

now.strftime("%Y-%m-%d")          # '2024-06-01'
now.strftime("%Y-%m-%d %H:%M:%S") # '2024-06-01 10:30:15'
now.strftime("%H:%M")             # '10:30'

常用格式符:

格式符含义示例
%Y四位年份2024
%m月份(01-12)06
%d日期(01-31)01
%H小时(00-23)10
%M分钟(00-59)30
%S秒(00-59)15
%f微秒123456
%A星期几(英文)Saturday
%a星期几缩写Sat

三、解析字符串

strptime() 把字符串解析成 datetime 对象:

python
dt = datetime.strptime("2024-06-01 10:30:00", "%Y-%m-%d %H:%M:%S")
print(dt)   # 2024-06-01 10:30:00

格式字符串要和输入字符串严格匹配:

python
datetime.strptime("2024/06/01", "%Y-%m-%d")   # ValueError,分隔符不匹配

四、时间差

两个 datetime 相减得到 timedelta

python
start = datetime(2024, 6, 1, 10, 0, 0)
end = datetime(2024, 6, 1, 10, 30, 15)

delta = end - start
print(delta)           # 0:30:15
print(delta.days)      # 0
print(delta.seconds)   # 1815,注意:不是总秒数,是去掉天后的秒数
print(delta.total_seconds())   # 1815.0,总秒数

timedelta 的属性容易混淆:

  • days:完整的天数
  • seconds:去掉天数后剩余的秒数(0-86399)
  • microseconds:去掉天数和秒数后剩余的微秒
  • total_seconds():转换为总秒数(包含天数)

创建时间差:

python
from datetime import timedelta

future = now + timedelta(days=7)        # 7 天后
past = now - timedelta(hours=3)         # 3 小时前
interval = timedelta(weeks=1, days=2)   # 9 天

五、比较时间

datetime 对象可以直接比较:

python
dt1 = datetime(2024, 6, 1, 10, 0)
dt2 = datetime(2024, 6, 1, 11, 0)

dt1 < dt2     # True
dt1 == dt2    # False

判断某个时间是否在范围内:

python
start = datetime(2024, 6, 1, 9, 0)
end = datetime(2024, 6, 1, 18, 0)
now = datetime.now()

start <= now <= end   # 链式比较

六、时区处理

不带时区的 datetime 叫"naive",带时区的叫"aware"。

python
from datetime import datetime, timezone, timedelta

# 创建带时区的时间
utc = timezone.utc
beijing_tz = timezone(timedelta(hours=8))

now_utc = datetime.now(utc)
now_bj = datetime.now(beijing_tz)

print(now_utc)   # 2024-06-01 02:30:00+00:00
print(now_bj)    # 2024-06-01 10:30:00+08:00

转换时区:

python
now_bj.astimezone(utc)   # 转成 UTC

Python 3.9+ 推荐使用 zoneinfo 模块(标准库):

python
from zoneinfo import ZoneInfo

bj = ZoneInfo("Asia/Shanghai")
now_bj = datetime.now(bj)

时区名称可以从 IANA 时区数据库查询(如 Asia/ShanghaiAmerica/New_York)。

容器中的时区问题:容器默认使用 UTC,应用按本地时间记录日志时,和宿主机可能差 8 小时。解决方式是在容器内设置 TZ 环境变量,或程序显式处理时区。

七、时间戳

时间戳是从 1970-01-01 00:00:00 UTC 到指定时间的秒数:

python
now = datetime.now()
ts = now.timestamp()          # 浮点数秒数
dt = datetime.fromtimestamp(ts)   # 时间戳转 datetime

时间戳是跨系统交换时间的常用格式——它是纯数字,不受时区和格式影响。

八、给文件名加日期

python
from datetime import datetime
from pathlib import Path

today = datetime.now().strftime("%Y%m%d")
backup = Path(f"backup-{today}.zip")
print(backup)   # backup-20240601.zip

记忆锚点datetime.now() 获取当前时间;strftime() 格式化,strptime() 解析;timedelta 表示时间差,total_seconds() 转总秒数;datetime 可直接比较大小;naive 是不带时区的,aware 是带时区的;ZoneInfo 处理时区(Python 3.9+);时间戳是纯数字,跨系统交换用时间戳。