datetime 模块简介
datetime 模块提供了多个类来操作日期和时间,理解这些类的区别和用途是第一步。

主要包含以下几个核心类:
datetime: 最常用的类,包含日期和时间信息(年、月、日、时、分、秒、微秒)。date: 仅包含日期信息(年、月、日)。time: 仅包含时间信息(时、分、秒、微秒)。timedelta: 表示两个date或datetime对象之间的时间差(持续时间)。tzinfo: 时区信息类的基类(通常不直接使用,而是使用其子类)。timezone:tzinfo的一个具体实现,用于处理时区。
核心类详解
1 datetime 类
这是模块的中心,我们大部分操作都围绕它展开。
创建 datetime 对象
-
获取当前时间 使用
datetime.now(),它返回一个包含本地时区信息的datetime对象。from datetime import datetime now = datetime.now() print(f"当前时间: {now}") print(f"类型: {type(now)}") # 输出示例: # 当前时间: 2025-10-27 15:30:45.123456 # 类型: <class 'datetime.datetime'> -
创建指定时间的
datetime对象 使用datetime()构造函数。
(图片来源网络,侵删)# 创建一个特定的 datetime 对象 dt = datetime(2025, 10, 27, 10, 30, 0) print(f"指定时间: {dt}") # 输出: 指定时间: 2025-10-27 10:30:00
datetime 对象的属性
创建后,可以通过属性访问年、月、日等具体信息。
dt = datetime(2025, 10, 27, 10, 30, 45)
print(f"年: {dt.year}")
print(f"月: {dt.month}")
print(f"日: {dt.day}")
print(f"时: {dt.hour}")
print(f"分: {dt.minute}")
print(f"秒: {dt.second}")
print(f"微秒: {dt.microsecond}")
print(f"星期几 (0是周一, 6是周日): {dt.weekday()}") # 或者 isoweekday()
print(f"ISO 星期几 (1是周一, 7是周日): {dt.isoweekday()}")
datetime 对象的方法
-
格式化输出 (
strftime) 将datetime对象格式化为字符串。strftime的意思是 "string format time"。dt = datetime(2025, 10, 27, 10, 30, 45) # 常用格式代码 # %Y: 四位年份 (2025) # %m: 两位月份 (10) # %d: 两位日期 (27) # %H: 24小时制小时 (10) # %M: 分钟 (30) # %S: 秒 (45) # %A: 星期全名 (Friday) # %B: 月份全名 (October) formatted_str = dt.strftime("%Y-%m-%d %H:%M:%S") print(f"标准格式: {formatted_str}") # 输出: 2025-10-27 10:30:45 pretty_str = dt.strftime("%A, %B %d, %Y") print(f"易读格式: {pretty_str}") # 输出: Friday, October 27, 2025 -
解析字符串 (
strptime) 将字符串解析为datetime对象。strptime的意思是 "string parse time"。date_str = "2025-10-27 15:45:00" dt_object = datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S") print(f"解析后的对象: {dt_object}") print(f"类型: {type(dt_object)}") # 输出: # 解析后的对象: 2025-10-27 15:45:00 # 类型: <class 'datetime.datetime'> -
日期/时间计算 与
timedelta对象进行加减运算。
(图片来源网络,侵删)from datetime import timedelta now = datetime.now() # 计算3天后的时间 future_time = now + timedelta(days=3) print(f"3天后: {future_time}") # 计算2小时前的时间 past_time = now - timedelta(hours=2) print(f"2小时前: {past_time}")
2 date 类
只处理日期,不包含时间信息。
创建 date 对象
from datetime import date
# 获取当前日期
today = date.today()
print(f"今天日期: {today}")
# 创建指定日期
some_day = date(2025, 1, 1)
print(f"指定日期: {some_day}")
date 对象的属性和方法
属性与 datetime 类似(year, month, day)。
方法也包含格式化和解析,但没有时间相关的。
today = date.today()
# 格式化
formatted_date = today.strftime("%Y年%m月%d日")
print(f"格式化日期: {formatted_date}")
# 解析
date_str = "2025-12-25"
parsed_date = date.strptime(date_str, "%Y-%m-%d")
print(f"解析后的日期: {parsed_date}")
# 替换日期中的某一部分
new_date = today.replace(year=2025)
print(f"替换年份后的日期: {new_date}")
3 timedelta 类
表示一个时间段,用于日期和时间的计算。
from datetime import datetime, timedelta
now = datetime.now()
# 创建一个1天5小时30秒的时间差
delta = timedelta(days=1, hours=5, seconds=30)
future = now + delta
past = now - delta
print(f"当前时间: {now}")
print(f"未来时间: {future}")
print(f"过去时间: {past}")
# 也可以直接比较两个 datetime 对象得到 timedelta
delta_from_calculation = future - now
print(f"计算出的时间差: {delta_from_calculation}")
print(f"时间差的天数: {delta_from_calculation.days}")
print(f"时间差的秒数: {delta_from_calculation.seconds}") # 注意:只包含未满一天的秒数
时区处理 (Time Zones)
在处理跨时区的应用时,时区至关重要,Python 3.2+ 的 datetime 模块内置了 timezone 类来简化时区操作。
1 使用 timezone
from datetime import datetime, timezone, timedelta
# 获取当前时间(无时区信息,称为 "naive" datetime)
naive_now = datetime.now()
print(f"无时区时间: {naive_now}")
# 创建一个带时区的 datetime 对象
# 1. 创建一个时区对象(东八区 UTC+8)
tz_east = timezone(timedelta(hours=8), name='CST') # CST 可以是 China Standard Time
aware_now_east = datetime.now(tz_east)
print(f"东八区时间: {aware_now_east}")
# 2. 使用 UTC 时区
utc_now = datetime.now(timezone.utc)
print(f"UTC时间: {utc_now}")
# 3. 给一个 "naive" datetime 添加时区
# 这很重要,因为很多库要求 datetime 对象必须是 "aware" 的
naive_dt = datetime(2025, 1, 1, 12, 0)
aware_dt_utc = naive_dt.replace(tzinfo=timezone.utc)
print(f"指定UTC时区的时间: {aware_dt_utc}")
2 使用第三方库 pytz (推荐)
虽然内置的 timezone 很好用,但 pytz 库提供了更全面、更准确的时区数据库(来自 IANA),并且处理夏令时等复杂情况更可靠,如果你需要处理复杂的时区问题,强烈推荐使用 pytz。
安装 pytz:
pip install pytz
使用 pytz:
import pytz
from datetime import datetime
# 获取所有可用的时区
# print(pytz.all_timezones)
# 创建一个带时区的 datetime 对象
tz_ny = pytz.timezone('America/New_York')
ny_now = datetime.now(tz_ny)
print(f"纽约时间: {ny_now}")
# 给一个 "naive" datetime 添加时区 (pytz 的推荐方式)
# 注意:pytz 要求先本地化,再设置时间
naive_dt = datetime(2025, 1, 1, 12, 0)
# 先创建一个 UTC 时间
utc_dt = pytz.utc.localize(naive_dt)
# 或者直接创建带时区的时间
# aware_dt_ny = tz_ny.localize(naive_dt)
print(f"UTC时间: {utc_dt}")
# 转换时区
tz_sh = pytz.timezone('Asia/Shanghai')
sh_now = utc_dt.astimezone(tz_sh)
print(f"北京时间: {sh_now}")
最佳实践和常见问题
1 Naive vs Aware Datetime
- Naive (天真): 不包含时区信息的
datetime对象,在进行跨时区计算或存储到数据库时,这可能会导致严重错误。 - Aware (感知): 包含时区信息的
datetime对象。始终推荐在业务逻辑中使用 Aware Datetime。
最佳实践: 在你的应用程序内部,统一使用 UTC 时间的 Aware Datetime,只有在需要向用户展示时,才将其转换为用户的本地时区。
# 推荐做法
from datetime import datetime, timezone, timedelta
# 1. 存储和计算时使用 UTC
utc_time = datetime.now(timezone.utc)
print(f"内部存储时间 (UTC): {utc_time}")
# 2. 展示时转换为本地时区
tz_local = timezone(timedelta(hours=8)) # 假设是东八区
local_time = utc_time.astimezone(tz_local)
print(f"向用户展示时间 (本地): {local_time}")
2 修改时间对象
- 错误示范: 直接修改
datetime对象的属性(如dt.year = 2025)会引发AttributeError。datetime对象是不可变的。 - 正确做法: 使用
replace()方法。
dt = datetime(2025, 10, 27, 10, 30)
# 错误
# dt.year = 2025 # AttributeError: can't set attribute
# 正确
new_dt = dt.replace(year=2025, month=5)
print(f"修改后的时间: {new_dt}")
| 类 | 用途 | 关键方法/属性 |
|---|---|---|
datetime |
核心类,同时处理日期和时间 | now(), datetime(), strftime(), strptime(), replace(), +/- timedelta |
date |
仅处理日期 | today(), datetime(), strftime(), strptime(), replace() |
time |
仅处理时间 | strftime(), replace() |
timedelta |
表示时间差 | days, seconds, (用于日期计算) |
timezone |
处理时区 (内置) | timezone(timedelta(hours=...)), datetime.now(tz=...) |
pytz |
处理时区 (第三方,更强大) | pytz.timezone('...'), localize(), astimezone() |
掌握 datetime 模块是 Python 开发中一项必备技能,尤其是在处理日志、数据分析、任务调度、用户管理等任何与时间相关的功能时。
