dateutil 是 Python 标准库 datetime 的一个强大扩展,它提供了许多非常实用的日期和时间处理功能,其中最核心、最常用的模块是 parser 和 rrule。

安装
你需要安装这个库,它通常与 python-dateutil 这个包名一起使用。
pip install python-dateutil
核心功能一:灵活的日期解析 (parser模块)
datetime.strptime() 是 Python 标准库中解析日期字符串的方法,但它有一个很大的缺点:你必须提前知道日期字符串的确切格式("%Y-%m-%d %H:%M:%S")。
dateutil.parser 的优势在于,它能自动识别多种常见的日期和时间格式,非常灵活。
基本用法:parser.parse()
from dateutil import parser
# 1. 解析标准格式
date_str1 = "2025-10-27 10:30:00"
dt1 = parser.parse(date_str1)
print(f"解析 '{date_str1}': {dt1} (类型: {type(dt1)})")
# 2. 解析没有前导零的格式
date_str2 = "27-Oct-2025 9:5:2" # 月份可以是英文全称或缩写
dt2 = parser.parse(date_str2)
print(f"解析 '{date_str2}': {dt2}")
# 3. 解析只有日期的字符串
date_str3 = "October 27, 2025"
dt3 = parser.parse(date_str3)
print(f"解析 '{date_str3}': {dt3}")
# 4. 解析只有时间的字符串 (默认会加上当前日期)
date_str4 = "14:45:30"
dt4 = parser.parse(date_str4)
print(f"解析 '{date_str4}': {dt4}")
# 5. 解析各种人类可读的格式
date_str5 = "tomorrow" # 甚至可以解析相对时间
dt5 = parser.parse(date_str5)
print(f"解析 '{date_str5}': {dt5}")
date_str6 = "last Friday"
dt6 = parser.parse(date_str6)
print(f"解析 '{date_str6}': {dt6}")
输出示例:

解析 '2025-10-27 10:30:00': 2025-10-27 10:30:00 (类型: <class 'datetime.datetime'>)
解析 '27-Oct-2025 9:5:2': 2025-10-27 09:05:02
解析 'October 27, 2025': 2025-10-27 00:00:00
解析 '14:45:30': 2025-10-27 14:45:30 (注意日期是今天的)
解析 'tomorrow': 2025-10-28 00:00:00
解析 'last Friday': 2025-10-20 00:00:00
高级用法:parser.parse() 的参数
-
dayfirst: 当日和月可能混淆时,优先将数字解释为日。# ambiguous string: "01/02/2025" # In the US, this is Jan 2. In many other places, it's Feb 1. print(parser.parse("01/02/2025")) # 默认按美国习惯 -> 2025-01-02 00:00:00 print(parser.parse("01/02/2025", dayfirst=True)) # 优先解释为日 -> 2025-02-01 00:00:00 -
yearfirst: 当年、月、日都可能混淆时,优先将数字解释为年。# ambiguous string: "02/03/04" print(parser.parse("02/03/04")) # 默认 -> 2004-03-02 00:00:00 print(parser.parse("02/03/04", yearfirst=True)) # 优先解释为年 -> 2002-03-04 00:00:00 -
default: 为缺失的日期或时间部分提供一个默认值。# 只有年月,没有日 # parser.parse("2025-10") # 会报 ValueError print(parser.parse("2025-10", default=day=1)) # 提供默认日 -> 2025-10-01 00:00:00 # 只有时间,没有日期 # parser.parse("08:30") # 默认会加上今天的日期 print(parser.parse("08:30", default=datetime.date(2025, 1, 1))) # 指定默认日期 -> 2025-01-01 08:30:00
核心功能二:日期时间计算 (relativedelta模块)
datetime.timedelta 可以用来进行简单的日期时间加减(如加减天数、秒数),但它的功能有限,它不能正确处理“一个月后”或“一年后”这种跨月、跨年的情况。

dateutil.relativedelta 就是为了解决这个问题而生的。
from datetime import datetime
from dateutil.relativedelta import relativedelta
dt = datetime(2025, 1, 31)
# 1. 加上一个月
# timedelta 无法做到这一点
one_month_later = dt + relativedelta(months=+1)
print(f"2025-01-31 加上一个月后: {one_month_later}") # 正确处理到月末 -> 2025-02-28
# 2. 加上一年
one_year_later = dt + relativedelta(years=+1)
print(f"2025-01-31 加上一年后: {one_year_later}") # -> 2025-01-31
# 3. 加上指定的年、月、日、小时等
custom_delta = dt + relativedelta(years=+2, months=-3, days=15, hours=5)
print(f"自定义增量: {custom_delta}") # -> 2025-10-16 05:00:00
# 4. 计算两个日期之间的差值
dt1 = datetime(2025, 10, 27)
dt2 = datetime(2025, 5, 15)
delta = relativedelta(dt1, dt2) # 较大的日期 - 较小的日期
print(f"从 {dt2} 到 {dt1} 的差值是:")
print(f" 年: {delta.years}")
print(f" 月: {delta.months}")
print(f" 日: {delta.days}")
输出示例:
2025-01-31 加上一个月后: 2025-02-28 00:00:00
2025-01-31 加上一年后: 2025-01-31 00:00:00
自定义增量: 2025-10-16 05:00:00
从 2025-05-15 00:00:00 到 2025-10-27 00:00:00 的差值是:
年: 1
月: 5
日: 12
核心功能三:重复日期时间规则 (rrule模块)
rrule 是一个功能极其强大的模块,用于生成符合特定规则的日期时间序列,它模仿了 iCalendar (RFC 5545) 标准。
基本用法:rrule.rrule()
from dateutil import rrule
from datetime import datetime
# 设置开始时间
start_date = datetime(2025, 1, 1)
# 1. 生成从开始日期起,每周一
mondays = rrule.rrule(rrule.WEEKLY, dtstart=start_date, count=5, byweekday=rrule.MO)
print("未来5个周一:")
for dt in mondays:
print(dt.strftime("%Y-%m-%d (%A)"))
print("-" * 20)
# 2. 生成每月的15号
monthly_15th = rrule.rrule(rrule.MONTHLY, dtstart=start_date, count=6, bymonthday=15)
print("未来6个月的15号:")
for dt in monthly_15th:
print(dt.strftime("%Y-%m-%d"))
print("-" * 20)
# 3. 生成一个更复杂的规则:从今天起,每个工作日(周一到周五),共10次
from datetime import date
today = datetime.now()
weekdays = rrule.rrule(rrule.DAILY, dtstart=today, count=10, byweekday=(rrule.MO, rrule.TU, rrule.WE, rrule.TH, rrule.FR))
print("未来10个工作日:")
for dt in weekdays:
print(dt.strftime("%Y-%m-%d (%A)"))
输出示例:
未来5个周一:
2025-01-02 (Monday)
2025-01-09 (Monday)
2025-01-16 (Monday)
2025-01-23 (Monday)
2025-01-30 (Monday)
--------------------
未来6个月的15号:
2025-01-15
2025-02-15
2025-03-15
2025-04-15
2025-05-15
2025-06-15
--------------------
未来10个工作日: (输出会根据当前日期变化)
2025-10-27 (Friday)
2025-10-30 (Monday)
2025-10-31 (Tuesday)
2025-11-01 (Wednesday)
2025-11-02 (Thursday)
2025-11-03 (Friday)
...
常用参数
freq: 频率 (rrule.YEARLY,rrule.MONTHLY,rrule.WEEKLY,rrule.DAILY,rrule.HOURLY,rrule.MINUTELY,rrule.SECONDLY)dtstart: 开始日期时间。until: 结束日期时间(包含)。count: 生成的总次数。interval: 间隔。freq=rrule.WEEKLY, interval=2表示每两周一次。bysetpos: 在生成的集合中选择第几个。bysetpos=-1表示最后一个。bymonth: 指定月份。bymonthday: 指定月中的哪一天。byweekday: 指定星期几。
其他实用功能
-
时区处理 (
tz模块):dateutil.tz提供了方便的时区对象,可以轻松处理带时区的 datetime 对象。from dateutil import tz from datetime import datetime # 创建一个时区感知的 datetime 对象 # 使用 'local' 时区 local_tz = tz.tzlocal() now_local = datetime.now(local_tz) print(f"本地时间: {now_local}") # 使用 'UTC' 时区 utc_tz = tz.tzutc() now_utc = datetime.now(utc_tz) print(f"UTC时间: {now_utc}") # 在时区之间转换 # 假设 now_local 是北京时间 (UTC+8) # Beijing = tz.gettz("Asia/Shanghai") # now_beijing = datetime.now(Beijing) # now_utc_from_beijing = now_beijing.astimezone(utc_tz) # print(f"北京时间转UTC: {now_utc_from_beijing}")
总结与最佳实践
| 功能 | datetime 标准库 |
dateutil 扩展库 |
何时使用 |
|---|---|---|---|
| 解析日期 | strptime() (需精确格式) |
parser.parse() (自动识别) |
当日期字符串格式不固定、来源多样或为自然语言时,dateutil 是不二之选。 |
| 时间差计算 | timedelta (天、秒、微秒) |
relativedelta (年、月、日、周等) |
需要计算“几个月后”或“几年后”时,必须用 relativedelta。 |
| 重复日期 | 无内置功能 | rrule (极其强大灵活) |
需要生成日历事件、提醒计划等重复性日期序列时。 |
| 时区 | pytz (另一个库) 或 zoneinfo (Python 3.9+) |
dateutil.tz (方便) |
dateutil.tz 提供了 tzlocal() 和 tzutc() 等便捷对象,非常易用。 |
最佳实践建议:
- 解析时保持警惕:
parser.parse()虽然强大,但过于宽松,如果它能解析 "Aug 9, 99" 为 1999 年,也可能解析你意料之外的字符串,在数据来源可控的环境中非常方便,但在处理不可信的输入时,最好先进行格式验证。 - 组合使用:
dateutil通常是作为datetime的补充,而不是完全替代,解析出来的对象是datetime对象,之后你仍然可以使用datetime的所有方法。 relativedelta是处理月份的利器:任何涉及月份加减的场景,都应该优先考虑relativedelta,以避免timedelta带来的错误。
希望这份详细的介绍能帮助你掌握 dateutil 的使用!
