-
ISO 8601是国际标准化组织(ISO)制定的日期和时间的表示方法,全称为《数据存储和交换形式·信息交换·日期和时间的表示方法》。目前,ISO 8601是全球通用的日期和时间格式标准,它定义了日期和时间的表示方法,包括年、月、日、时、分、秒等1。除了ISO 8601之外,还有一些其他的日期和时间格式标准,例如RFC 3339、RFC 2822等2。
东八区标准时间格式示例
1970-01-01T00:00:00+08
一、核心模块:Python3 时间处理的 3 大工具
Python3 提供了 3 个核心模块用于时间处理,各自侧重不同场景,按需选择即可:
| 模块 | 核心作用 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
time |
底层时间操作(时间戳、休眠) | 快速获取时间戳、简单时间计算 | 轻量、执行快 | 格式化功能薄弱,不支持复杂日期运算 |
datetime |
日期时间类(datetime/date/time) |
大部分业务场景(格式转换、日期运算) | 功能全面、API 友好 | 时区支持需配合 pytz/zoneinfo |
calendar |
日历相关操作(月份日历、星期计算) | 日历生成、节假日判断 | 专注日历场景 | 日常格式化用不上,功能单一 |
建议:
优先使用
datetime模块,覆盖 90% 以上的时间格式化需求;复杂时区场景搭配zoneinfo(Python3.9+ 内置)或pytz。
二、基础用法:时间格式化核心操作
1. 关键概念:时间的 3 种表示形式
Python 中时间有 3 种常用表示,格式化的核心是「不同形式之间的转换」:
-
时间戳:从 1970-01-01 00:00:00 UTC 到当前时间的秒数(float 类型);
-
datetime 对象 :
datetime.datetime类实例(最灵活,支持各种运算和格式化); -
字符串 :人类可读的时间格式(如
2024-05-20 13:14:52、2024/05/20)。
2. 核心转换:3 种形式互转(高频)
(1)获取当前时间(3 种形式)
python
import time
from datetime import datetime
# 1. 获取时间戳(秒级)
timestamp = time.time()
print(f"秒级时间戳:{timestamp}") # 输出:1716202492.123456
# 2. 获取毫秒级时间戳(业务常用)
ms_timestamp = int(time.time() * 1000)
print(f"毫秒级时间戳:{ms_timestamp}") # 输出:1716202492123
# 3. 获取 datetime 对象(本地时间)
local_dt = datetime.now()
print(f"本地时间 datetime 对象:{local_dt}") # 输出:2024-05-20 13:14:52.123456
# 4. 获取 UTC 时间 datetime 对象
utc_dt = datetime.utcnow()
print(f"UTC 时间 datetime 对象:{utc_dt}") # 输出:2024-05-20 05:14:52.123456
(2)datetime 对象 → 字符串(格式化核心)
使用 datetime.strftime(format) 方法,通过格式化符定义输出格式,常用格式化符如下:
| 格式化符 | 说明 | 示例 |
|---|---|---|
%Y |
4 位年份 | 2024 |
%m |
2 位月份(01-12) | 05 |
%d |
2 位日期(01-31) | 20 |
%H |
24 小时制(00-23) | 13 |
%I |
12 小时制(01-12) | 01 |
%M |
2 位分钟(00-59) | 14 |
%S |
2 位秒数(00-59) | 52 |
%w |
星期(0-6,0 为周日) | 1(周一) |
%W |
当年第几周(00-53) | 20 |
%p |
上午 / 下午(AM/PM,仅 12 小时制) | PM |
示例:
python
from datetime import datetime
dt = datetime.now()
# 格式1:年月日 时分秒(最常用)
str1 = dt.strftime("%Y-%m-%d %H:%M:%S")
print(str1) # 输出:2024-05-20 13:14:52
# 格式2:年月日(无时间)
str2 = dt.strftime("%Y/%m/%d")
print(str2) # 输出:2024/05/20
# 格式3:带星期和上午/下午
str3 = dt.strftime("%Y-%m-%d %A %I:%M:%S %p")
print(str3) # 输出:2024-05-20 Monday 01:14:52 PM
# 格式4:自定义分隔符(如下划线)
str4 = dt.strftime("%Y_%m_%d_%H%M%S")
print(str4) # 输出:2024_05_20_131452(适合文件名)
(3)字符串 → datetime 对象(解析时间)
使用 datetime.strptime(string, format) 方法,format 必须与字符串格式完全一致,否则报错。
示例:
python
from datetime import datetime
# 示例1:解析标准格式字符串
str_time1 = "2024-05-20 13:14:52"
dt1 = datetime.strptime(str_time1, "%Y-%m-%d %H:%M:%S")
print(f"解析结果:{dt1},类型:{type(dt1)}") # 输出:2024-05-20 13:14:52,类型:.datetime'>
# 示例2:解析无分隔符格式
str_time2 = "20240520131452"
dt2 = datetime.strptime(str_time2, "%Y%m%d%H%M%S")
print(f"解析结果:{dt2}") # 输出:2024-05-20 13:14:52
# 示例3:解析带中文的格式
str_time3 = "2024年05月20日 13时14分52秒"
dt3 = datetime.strptime(str_time3, "%Y年%m月%d日 %H时%M分%S秒")
print(f"解析结果:{dt3}") # 输出:2024-05-20 13:14:52
(4)时间戳 ↔ datetime 对象
python
import time
from datetime import datetime
# 1. 时间戳 → datetime 对象(本地时间)
timestamp = 1716202492.123456
dt_local = datetime.fromtimestamp(timestamp)
print(f"本地时间:{dt_local}") # 输出:2024-05-20 13:14:52.123456
# 2. 时间戳 → datetime 对象(UTC 时间)
dt_utc = datetime.utcfromtimestamp(timestamp)
print(f"UTC 时间:{dt_utc}") # 输出:2024-05-20 05:14:52.123456
# 3. datetime 对象 → 时间戳
dt = datetime.now()
timestamp = dt.timestamp()
print(f"时间戳:{timestamp}") # 输出:1716202492.123456
三、进阶技巧:时区处理与日期运算
1. 时区处理(Python3.9+ 推荐 zoneinfo)
Python3.9 之前需安装 pytz(pip install pytz),3.9+ 内置 zoneinfo(无需额外安装),支持全球时区转换。
(1)获取指定时区的当前时间
python
from datetime import datetime
from zoneinfo import ZoneInfo # Python3.9+ 内置
# 1. 获取纽约时间(UTC-4/UTC-5,自动适配夏令时)
ny_tz = ZoneInfo("America/New_York")
ny_dt = datetime.now(ny_tz)
print(f"纽约时间:{ny_dt.strftime('%Y-%m-%d %H:%M:%S')}") # 输出:2024-05-20 01:14:52
# 2. 获取东京时间(UTC+9)
tokyo_tz = ZoneInfo("Asia/Tokyo")
tokyo_dt = datetime.now(tokyo_tz)
print(f"东京时间:{tokyo_dt.strftime('%Y-%m-%d %H:%M:%S')}") # 输出:2024-05-20 14:14:52
# 3. 获取北京时间(UTC+8)
bj_tz = ZoneInfo("Asia/Shanghai")
bj_dt = datetime.now(bj_tz)
print(f"北京时间:{bj_dt.strftime('%Y-%m-%d %H:%M:%S')}") # 输出:2024-05-20 13:14:52
(2)时区转换(如 UTC 转北京时间)
python
from datetime import datetime
from zoneinfo import ZoneInfo
# 1. 创建 UTC 时间对象
utc_dt = datetime(2024, 5, 20, 5, 14, 52, tzinfo=ZoneInfo("UTC"))
print(f"UTC 时间:{utc_dt}") # 输出:2024-05-20 05:14:52+00:00
# 2. 转换为北京时间(UTC+8)
bj_dt = utc_dt.astimezone(ZoneInfo("Asia/Shanghai"))
print(f"北京时间:{bj_dt.strftime('%Y-%m-%d %H:%M:%S')}") # 输出:2024-05-20 13:14:52
时区数据库:所有支持的时区名称可参考
(如
Europe/London、
Africa/Johannesburg)。
2. 日期运算(timedelta 类)
使用 datetime.timedelta 实现「加减天数 / 小时 / 分钟」等运算,无需手动处理月份天数、闰年等问题。
示例:
python
from datetime import datetime, timedelta
now = datetime.now()
# 1. 加 3 天
future_3d = now + timedelta(days=3)
print(f"3 天后:{future_3d.strftime('%Y-%m-%d')}") # 输出:2024-05-23
# 2. 减 1 小时 30 分钟
past_1h30m = now - timedelta(hours=1, minutes=30)
print(f"1 小时 30 分钟前:{past_1h30m.strftime('%Y-%m-%d %H:%M')}") # 输出:2024-05-20 11:44
# 3. 计算两个日期的差值
date1 = datetime(2024, 5, 20)
date2 = datetime(2024, 5, 10)
diff = date1 - date2
print(f"日期差值:{diff.days} 天") # 输出:10 天
print(f"总秒数:{diff.total_seconds()} 秒") # 输出:864000.0 秒
# 4. 加 1 个月(timedelta 不支持 months,需用 relativedelta)
# 安装:pip install python-dateutil
from dateutil.relativedelta import relativedelta
future_1m = now + relativedelta(months=1)
print(f"1 个月后:{future_1m.strftime('%Y-%m-%d')}") # 输出:2024-06-20
四、场景:格式化时间的高频用法
1. 生成带时间戳的文件名(日志 / 备份场景)
python
from datetime import datetime
# 生成格式:20240520_131452_backup.zip
filename = f"{datetime.now().strftime('%Y%m%d_%H%M%S')}_backup.zip"
print(filename) # 输出:20240520_131452_backup.zip
2. 计算程序运行时间
python
import time
from datetime import datetime
# 方法1:用 time 模块(简洁)
start_time = time.time()
# 模拟程序运行(如循环)
for _ in range(1000000):
pass
end_time = time.time()
print(f"程序运行时间:{end_time - start_time:.6f} 秒") # 输出:0.031250 秒
# 方法2:用 datetime 模块(可读性强)
start_dt = datetime.now()
for _ in range(1000000):
pass
end_dt = datetime.now()
diff = end_dt - start_dt
print(f"程序运行时间:{diff.total_seconds():.6f} 秒") # 输出:0.031250 秒
3. 格式化数据库时间(ORM 场景)
数据库存储时间常用 datetime 类型,查询后格式化输出:
python
from datetime import datetime
import pymysql
# 连接数据库(示例)
conn = pymysql.connect(host="localhost", user="root", password="123456", db="test")
cursor = conn.cursor()
# 查询数据库中的时间字段(假设字段 create_time 为 datetime 类型)
cursor.execute("SELECT create_time FROM user WHERE id = 1")
result = cursor.fetchone()
if result:
db_time = result[0] # 数据库返回的是 datetime 对象
# 格式化输出
formatted_time = db_time.strftime("%Y-%m-%d %H:%M:%S")
print(f"用户创建时间:{formatted_time}") # 输出:2024-05-20 13:14:52
cursor.close()
conn.close()
4. 处理前端传递的时间字符串
前端通常传递字符串格式的时间,后端解析后进行运算或存储:
python
from datetime import datetime
# 前端传递的时间字符串
front_time_str = "2024-05-20T13:14:52" # 常见于 JSON 数据
# 解析为 datetime 对象
dt = datetime.strptime(front_time_str, "%Y-%m-%dT%H:%M:%S")
# 加 1 天後返回给前端
next_day_dt = dt + timedelta(days=1)
front_response_str = next_day_dt.strftime("%Y-%m-%dT%H:%M:%S")
print(f"返回前端的时间:{front_response_str}") # 输出:2024-05-21T13:14:52
五、避坑指南:常见问题与解决方案
1. 问题:格式化符大小写混淆(如 %m vs %M)
-
错误示例:把「月份」的
%m和「分钟」的%M混用,导致解析失败; -
解决方案:牢记核心格式化符的大小写:
-
大写:
%Y(年份)、%M(分钟)、%H(24 小时制)、%S(秒); -
小写:
%y(两位年份)、%m(月份)、%h(12 小时制,同%I)、%s(无意义,别用)。
-
2. 问题:字符串与 format 不匹配(ValueError)
-
错误示例:
datetime.strptime("2024-05-20", "%Y/%m/%d")(分隔符不一致); -
解决方案:
-
严格保证
strptime的第二个参数与字符串格式完全一致(分隔符、位数、单位); -
若字符串格式不固定,先预处理(如替换分隔符):
-
python
str_time = "2024-05-20"
str_time = str_time.replace("-", "/") # 统一分隔符
dt = datetime.strptime(str_time, "%Y/%m/%d")
3. 问题:时区缺失导致的时间偏差
-
现象:本地时间存储到数据库后,查询时时间少 8 小时(如北京时间未带时区,被解析为 UTC 时间);
-
解决方案:
-
存储时间时统一使用 UTC 时间(避免时区差异);
-
前端展示时再转换为用户所在时区;
-
数据库字段建议设置为
TIMESTAMP WITH TIME ZONE(如 PostgreSQL)或DATETIME(MySQL 需手动处理时区)。
-
4. 问题:Python3.9 以下不支持 zoneinfo
-
解决方案:
-
升级 Python 到 3.9+(推荐);
-
安装
pytz替代:
-
python
import pytz
from datetime import datetime
bj_tz = pytz.timezone("Asia/Shanghai")
bj_dt = datetime.now(bj_tz)
print(bj_dt.strftime("%Y-%m-%d %H:%M:%S")) # 输出:2024-05-20 13:14:52
5. 问题:timedelta 不支持月份 / 年份运算
-
原因:月份天数不固定(28/29/30/31)、年份有闰年,
timedelta无法处理; -
解决方案:使用
python-dateutil的relativedelta:
python
from dateutil.relativedelta import relativedelta
from datetime import datetime
now = datetime.now()
next_year = now + relativedelta(years=1) # 加 1 年
last_month = now - relativedelta(months=1) # 减 1 个月