1. Python时间处理的基石:datetime模块深度解析
在Python开发中,时间处理就像空气一样无处不在却又容易被忽视。从记录日志时间戳到计算用户会员有效期,从生成报表日期范围到实现定时任务调度,datetime模块始终默默支撑着这些基础但关键的功能。作为Python标准库中的时间处理担当,datetime模块已经陪伴Python开发者走过了二十多个年头,其API设计经受住了时间的考验。
提示:Python的datetime模块首次出现在Python 2.3版本中,由Tim Peters设计实现,这位同时也是Python之禅(The Zen of Python)的作者。
1.1 四大核心类:各司其职的时间管家
datetime模块的精妙之处在于它的职责划分。与某些语言将日期时间混为一谈不同,Python清晰地划分了四个核心类,每个类都像专业工匠一样专注自己的领域:
python复制from datetime import date, time, datetime, timedelta
# 专注日期的艺术家 - date类
birthday = date(1990, 5, 15) # 只关心年月日
print(f"生日: {birthday}") # 输出: 1990-05-15
# 时间细节的观察者 - time类
meeting_time = time(14, 30, 0) # 专注时分秒
print(f"会议时间: {meeting_time}") # 输出: 14:30:00
# 全能型选手 - datetime类
current_moment = datetime.now() # 日期时间全掌握
print(f"当前时刻: {current_moment}") # 输出: 2024-03-15 09:45:30.123456
# 时间魔术师 - timedelta类
two_weeks = timedelta(days=14) # 表示时间间隔
future_date = birthday + two_weeks
print(f"生日两周后: {future_date}") # 输出: 1990-05-29
这种设计哲学带来了几个显著优势:
- 单一职责原则:每个类只处理自己专精的领域,避免功能臃肿
- 内存效率:date类比datetime类更轻量,当不需要时间部分时可节省资源
- 接口清晰:避免了无意义的属性(比如date类没有hour属性)
1.2 时间创建的四种姿势
创建时间对象就像准备食材,不同的场景需要不同的处理方式。以下是datetime模块提供的四种"烹饪方法":
python复制from datetime import datetime
import time
# 方法1:新鲜出炉 - 获取当前时间
now = datetime.now() # 本地当前时间
utc_now = datetime.utcnow() # UTC当前时间
print(f"本地现在: {now}\nUTC现在: {utc_now}")
# 方法2:精确配方 - 指定具体时间
new_year = datetime(2025, 1, 1, 0, 0, 0) # 2025年元旦
print(f"2025新年: {new_year}")
# 方法3:时间罐头 - 从时间戳还原
timestamp = time.time() # 当前时间戳
from_timestamp = datetime.fromtimestamp(timestamp)
print(f"从时间戳恢复: {from_timestamp}")
# 方法4:文字解谜 - 解析时间字符串
date_str = "2024-03-15 14:30:00"
parsed = datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S")
print(f"字符串解析结果: {parsed}")
每种创建方式都有其典型应用场景:
- 日志记录:优先使用
now()获取当前时刻 - 固定日期:直接构造指定时间对象
- 数据存储:通常转换为时间戳存储
- 用户输入:需要从字符串解析
1.3 为什么选择datetime模块?
在Python的时间处理生态中,datetime模块之所以能成为标准答案,是因为它完美平衡了以下几个维度:
-
功能完整性:
- 覆盖从年、月、日到时、分、秒、微秒的全粒度时间处理
- 支持时区感知(aware)和时区未感知(naive)两种模式
- 提供丰富的时间计算和比较操作
-
API设计美学:
- 符合Python的"显式优于隐式"哲学
- 方法命名直观(如
strftime表示"string format time") - 运算符重载合理(如直接用
+进行时间加法)
-
性能考量:
- 作为内置模块无需额外安装
- 核心计算用C实现,效率有保障
- 与time模块无缝互操作
-
扩展性:
- 与第三方库(如pytz、arrow)良好兼容
- 可以轻松扩展自定义的时间处理逻辑
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. datetime模块实战手册
2.1 时间格式化与解析的艺术
时间格式化就像翻译工作,需要在机器理解和人类阅读之间架起桥梁。datetime模块提供了强大的strftime(格式化)和strptime(解析)方法来完成这项任务。
2.1.1 格式化符号全解
以下是最常用的格式化指令:
| 指令 | 含义 | 示例 |
|---|---|---|
| %Y | 四位年份 | 2024 |
| %m | 两位月份 | 03 |
| %d | 两位日期 | 15 |
| %H | 24小时制小时 | 14 |
| %I | 12小时制小时 | 02 |
| %M | 分钟 | 30 |
| %S | 秒 | 45 |
| %f | 微秒 | 123456 |
| %A | 完整星期名 | Friday |
| %a | 简写星期名 | Fri |
| %B | 完整月份名 | March |
| %b | 简写月份名 | Mar |
| %p | AM/PM | PM |
| %j | 年中的第几天 | 075 |
| %U | 年中的第几周 | 10 |
2.1.2 实战格式化示例
python复制from datetime import datetime
now = datetime.now()
# 标准格式
print(now.strftime("%Y-%m-%d %H:%M:%S")) # 2024-03-15 14:30:45
# 中文友好格式
print(now.strftime("%Y年%m月%d日 %H时%M分%S秒")) # 2024年03月15日 14时30分45秒
# 文件命名友好格式
print(now.strftime("%Y%m%d_%H%M%S")) # 20240315_143045
# 可读性强的英文格式
print(now.strftime("%A, %B %d, %Y at %I:%M %p")) # Friday, March 15, 2024 at 02:30 PM
2.1.3 字符串解析技巧
解析用户输入的时间字符串时,需要注意几个要点:
python复制from datetime import datetime
# 多格式兼容解析
def flexible_parse(date_str):
formats = [
"%Y-%m-%d %H:%M:%S",
"%Y/%m/%d %H:%M",
"%m-%d-%Y",
"%Y年%m月%d日",
"%b %d, %Y", # Mar 15, 2024
]
for fmt in formats:
try:
return datetime.strptime(date_str, fmt)
except ValueError:
continue
raise ValueError(f"无法解析的时间字符串: {date_str}")
# 测试不同格式
test_cases = [
"2024-03-15 14:30:00",
"2024/03/15 14:30",
"03-15-2024",
"2024年03月15日",
"Mar 15, 2024"
]
for case in test_cases:
parsed = flexible_parse(case)
print(f"'{case}' -> {parsed}")
注意:strptime的性能在大量解析时可能成为瓶颈,对于固定格式的高频解析场景,可以考虑预编译正则表达式或使用第三方库如dateutil。
2.2 时间计算与比较
datetime模块的时间计算能力就像一台精密的时间计算机,让各种时间运算变得直观简单。
2.2.1 基础时间运算
python复制from datetime import datetime, timedelta
now = datetime.now()
# 基本时间加减
print("现在:", now)
print("1天后:", now + timedelta(days=1))
print("3小时前:", now - timedelta(hours=3))
print("2周半后:", now + timedelta(weeks=2, days=3, hours=12))
# 计算时间差
new_year = datetime(2025, 1, 1, 0, 0, 0)
time_left = new_year - now
print("\n距离2025年还有:")
print(f" 总天数: {time_left.days}天")
print(f" 总秒数: {int(time_left.total_seconds())}秒")
print(f" 约合: {time_left.days // 30}个月零{time_left.days % 30}天")
2.2.2 复杂日期计算
实现更复杂的日期计算,如月末、季度初等:
python复制from datetime import datetime, timedelta
import calendar
def end_of_month(dt):
"""获取当月最后一天"""
_, last_day = calendar.monthrange(dt.year, dt.month)
return dt.replace(day=last_day)
def next_weekday(dt, weekday):
"""获取下一个指定星期几"""
days_ahead = weekday - dt.weekday()
if days_ahead <= 0: # 目标日在当前日之后
days_ahead += 7
return dt + timedelta(days=days_ahead)
# 使用示例
today = datetime.now().date()
print("本月最后一天:", end_of_month(today))
print("下个周五:", next_weekday(today, 4)) # 0=周一, 4=周五
2.2.3 时间比较的注意事项
时间比较看似简单,但有几个陷阱需要注意:
python复制from datetime import datetime, timezone
# 创建两个时间对象
dt1 = datetime(2024, 3, 15, 14, 30)
dt2 = datetime(2024, 3, 15, 14, 30, 1) # 比dt1多1秒
# 基本比较
print("dt1 < dt2:", dt1 < dt2) # True
print("dt1 == dt2:", dt1 == dt2) # False
# 时区感知比较
naive = datetime.now()
aware = datetime.now(timezone.utc)
try:
print(naive == aware) # 会引发TypeError
except TypeError as e:
print(f"比较错误: {e}") # 不能比较naive和aware datetime
重要提示:比较带时区和不带时区的时间对象会引发TypeError。在比较前请确保时间对象的时区状态一致。
2.3 实用时间工具函数集
下面这些经过实战检验的工具函数可以收藏到你的代码库中:
python复制from datetime import datetime, timedelta
import calendar
def calculate_age(birth_date, at_date=None):
"""精确计算年龄(考虑闰年)"""
at_date = at_date or datetime.now().date()
age = at_date.year - birth_date.year
# 如果今年生日还没过,年龄减1
if (at_date.month, at_date.day) < (birth_date.month, birth_date.day):
age -= 1
return age
def business_days(start, end):
"""计算两个日期之间的工作日天数"""
total_days = (end - start).days + 1
full_weeks, remaining_days = divmod(total_days, 7)
# 完整周的工作日数
business_days = full_weeks * 5
# 剩余天数中的工作日
for day in range(remaining_days):
if (start + timedelta(days=day)).weekday() < 5: # 0-4是工作日
business_days += 1
return business_days
def humanize_duration(seconds):
"""将秒数转换为人类友好的时间描述"""
intervals = [
('年', 31536000), # 60*60*24*365
('个月', 2592000), # 60*60*24*30
('天', 86400), # 60*60*24
('小时', 3600), # 60*60
('分钟', 60),
('秒', 1)
]
parts = []
for name, count in intervals:
value = seconds // count
if value:
seconds -= value * count
parts.append(f"{int(value)}{name}")
return ''.join(parts[:3]) # 最多显示3个最大单位
# 使用示例
birthday = datetime(1990, 5, 15).date()
print(f"年龄: {calculate_age(birthday)}岁")
start = datetime(2024, 3, 1).date()
end = datetime(2024, 3, 15).date()
print(f"{start}到{end}的工作日: {business_days(start, end)}天")
durations = [3661, 123456, 7200]
for sec in durations:
print(f"{sec}秒 = {humanize_duration(sec)}")
3. datetime高级应用与性能优化
3.1 时区处理实战
时区处理是时间处理中最容易出错的环节之一。Python的datetime模块提供了基础的时区支持,但对于复杂时区规则,建议使用pytz库。
3.1.1 基础时区操作
python复制from datetime import datetime, timezone, timedelta
# 创建UTC时间
utc_now = datetime.now(timezone.utc)
print(f"UTC时间: {utc_now}")
# 创建自定义时区
beijing_tz = timezone(timedelta(hours=8)) # 东八区
newyork_tz = timezone(timedelta(hours=-5)) # 西五区
# 转换为北京时间
beijing_time = utc_now.astimezone(beijing_tz)
print(f"北京时间: {beijing_time}")
# 转换为纽约时间
ny_time = utc_now.astimezone(newyork_tz)
print(f"纽约时间: {ny_time}")
# 时区感知与未感知的区别
naive = datetime.now()
aware = datetime.now(beijing_tz)
print(f"未感知: {naive}\n已感知: {aware}")
print(f"时区信息: {aware.tzinfo}")
3.1.2 处理夏令时
对于有夏令时的地区,建议使用pytz库:
python复制import pytz
from datetime import datetime
# 创建时区对象
eastern = pytz.timezone('US/Eastern')
# 正确处理夏令时转换
dt = datetime(2024, 3, 10, 1, 30) # 美国夏令时开始时间
localized = eastern.localize(dt)
print(f"本地化时间: {localized}")
# 尝试转换到UTC
try:
utc_time = localized.astimezone(pytz.utc)
print(f"UTC时间: {utc_time}")
except pytz.AmbiguousTimeError:
print("遇到模糊时间(夏令时转换时会发生)")
重要提示:直接给datetime对象设置pytz时区和使用localize方法效果不同。对于固定时区(如UTC),可以直接设置;对于有夏令时的时区,必须使用localize方法。
3.2 性能优化技巧
虽然datetime模块已经足够高效,但在处理大规模时间数据时,仍有优化空间:
3.2.1 批量处理优化
python复制from datetime import datetime
import time
# 不优化的写法
def parse_dates_naive(date_strings):
return [datetime.strptime(s, "%Y-%m-%d") for s in date_strings]
# 优化后的写法
def parse_dates_optimized(date_strings):
fmt = "%Y-%m-%d"
return [datetime(*(time.strptime(s, fmt)[:6])) for s in date_strings]
# 测试性能
test_data = ["2024-{:02d}-{:02d}".format(m, d) for m in range(1, 13) for d in range(1, 29)]
start = time.time()
parse_dates_naive(test_data)
print(f"原生方法耗时: {time.time() - start:.4f}秒")
start = time.time()
parse_dates_optimized(test_data)
print(f"优化方法耗时: {time.time() - start:.4f}秒")
3.2.2 替代方案性能对比
在某些场景下,其他模块可能更高效:
| 操作类型 | 推荐模块 | 优势 |
|---|---|---|
| 高频获取当前时间 | time.time() | 比datetime.now()快5-10倍 |
| 简单日期计算 | date | 比datetime轻量 |
| 时间戳转换 | time.localtime | 比fromtimestamp快 |
| 大量日期解析 | 预编译正则 | 比strptime快 |
3.3 常见陷阱与解决方案
在实际使用中,datetime模块有几个常见的"坑"需要注意:
-
月份和星期的编号不一致:
- 月份:1(一月)到12(十二月)
- 星期:0(周一)到6(周日)
-
夏令时转换时的模糊时间:
- 解决方案:使用pytz库的localize方法处理
-
时区未感知对象的比较:
- 解决方案:统一转换为UTC再比较
-
datetime对象的不可变性:
- 解决方案:使用replace方法创建新对象
python复制from datetime import datetime
# 不可变示例
dt = datetime.now()
try:
dt.year = 2025 # 会引发AttributeError
except AttributeError:
print("datetime对象是不可变的")
# 正确修改方式
new_dt = dt.replace(year=2025)
print(f"修改后的时间: {new_dt}")
4. 综合实战:企业级考勤系统开发
让我们用一个完整的案例来展示datetime模块在实际项目中的应用。假设我们要开发一个简单的企业考勤系统,需要处理员工的打卡记录、计算工作时长和迟到早退等。
4.1 数据模型设计
python复制from datetime import datetime, time, timedelta
from typing import List, Dict
import csv
class AttendanceSystem:
"""企业考勤系统核心类"""
def __init__(self):
self.records = [] # 存储所有打卡记录
self.work_schedule = {
'start': time(9, 0), # 上班时间
'end': time(18, 0), # 下班时间
'flexible': timedelta(minutes=30) # 弹性时间
}
def load_records(self, filepath: str):
"""从CSV文件加载打卡记录"""
with open(filepath, mode='r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
try:
dt = datetime.strptime(
f"{row['date']} {row['time']}",
"%Y-%m-%d %H:%M:%S"
)
self.records.append({
'employee_id': row['employee_id'],
'datetime': dt,
'type': row['type'] # 'in'或'out'
})
except ValueError as e:
print(f"解析错误: {row} - {e}")
# 按时间排序
self.records.sort(key=lambda x: x['datetime'])
def calculate_daily(self, date: datetime.date):
"""计算某日的考勤情况"""
date_records = [
r for r in self.records
if r['datetime'].date() == date
]
employees = {r['employee_id'] for r in date_records}
result = {}
for emp in employees:
emp_records = [r for r in date_records if r['employee_id'] == emp]
in_records = [r for r in emp_records if r['type'] == 'in']
out_records = [r for r in emp_records if r['type'] == 'out']
if not in_records or not out_records:
result[emp] = {'status': 'incomplete'}
continue
first_in = min(r['datetime'] for r in in_records)
last_out = max(r['datetime'] for r in out_records)
# 计算迟到早退
late = max(
(first_in.time() > self.work_schedule['start']),
(first_in - datetime.combine(date, self.work_schedule['start'])) >
self.work_schedule['flexible']
)
early_leave = max(
(last_out.time() < self.work_schedule['end']),
(datetime.combine(date, self.work_schedule['end']) - last_out) >
self.work_schedule['flexible']
)
# 计算工作时长
work_duration = last_out - first_in
lunch_break = timedelta(hours=1) # 假设午餐休息1小时
actual_work = work_duration - lunch_break
result[emp] = {
'first_in': first_in,
'last_out': last_out,
'work_duration': work_duration,
'actual_work': actual_work,
'is_late': late,
'is_early': early_leave,
'status': 'normal'
}
return result
def generate_monthly_report(self, year: int, month: int):
"""生成月度考勤报告"""
start_date = datetime(year, month, 1).date()
end_date = (datetime(year, month + 1, 1) - timedelta(days=1)).date() if month < 12 \
else datetime(year, 12, 31).date()
current = start_date
report = {}
while current <= end_date:
daily = self.calculate_daily(current)
for emp, data in daily.items():
if emp not in report:
report[emp] = {
'late_count': 0,
'early_count': 0,
'work_days': 0,
'total_hours': timedelta()
}
if data['status'] == 'normal':
report[emp]['work_days'] += 1
report[emp]['total_hours'] += data['actual_work']
if data['is_late']:
report[emp]['late_count'] += 1
if data['is_early']:
report[emp]['early_count'] += 1
current += timedelta(days=1)
return report
4.2 使用示例
python复制# 初始化考勤系统
attendance = AttendanceSystem()
# 加载打卡记录(假设CSV文件格式:employee_id,date,time,type)
attendance.load_records('attendance_records.csv')
# 计算某日考勤
daily_report = attendance.calculate_daily(datetime(2024, 3, 15).date())
print("2024年3月15日考勤:")
for emp, data in daily_report.items():
print(f"员工{emp}:")
print(f" 上班: {data['first_in'].strftime('%H:%M')}")
print(f" 下班: {data['last_out'].strftime('%H:%M')}")
print(f" 实际工作: {data['actual_work']}")
print(f" 迟到: {'是' if data['is_late'] else '否'}")
print(f" 早退: {'是' if data['is_early'] else '否'}")
# 生成月度报告
monthly_report = attendance.generate_monthly_report(2024, 3)
print("\n2024年3月月度报告:")
for emp, data in monthly_report.items():
print(f"员工{emp}:")
print(f" 出勤天数: {data['work_days']}")
print(f" 总工时: {data['total_hours']}")
print(f" 迟到次数: {data['late_count']}")
print(f" 早退次数: {data['early_count']}")
4.3 性能优化建议
对于大型企业的考勤系统,可以考虑以下优化措施:
- 使用数据库存储:对于大量打卡记录,使用SQLite或MySQL等数据库替代CSV文件
- 批量处理优化:使用pandas等库进行向量化计算
- 缓存计算结果:对历史考勤数据进行缓存,避免重复计算
- 异步处理:使用多线程或异步IO处理大量数据的导入和计算
5. datetime模块的局限与替代方案
虽然datetime模块功能强大,但在某些场景下可能需要考虑替代方案。
5.1 内置模块的局限性
| 局限性 | 影响场景 | 解决方案 |
|---|---|---|
| 时区支持有限 | 需要处理复杂时区规则 | 使用pytz或zoneinfo |
| 解析能力有限 | 需要处理多种非标准时间格式 | 使用dateutil的parser |
| 不可变对象 | 需要频繁修改时间对象 | 使用replace方法创建新对象 |
| 性能瓶颈 | 高频时间操作场景 | 使用time模块或缓存结果 |
5.2 主流替代方案对比
5.2.1 pytz
python复制import pytz
from datetime import datetime
# 处理复杂时区
tz = pytz.timezone('Asia/Shanghai')
dt = datetime(2024, 3, 15, 14, 30)
localized = tz.localize(dt)
print(f"上海时间: {localized}")
print(f"转换为纽约时间: {localized.astimezone(pytz.timezone('America/New_York'))}")
适用场景:需要处理历史时区变化和复杂夏令时规则
5.2.2 dateutil
python复制from dateutil import parser
from dateutil.relativedelta import relativedelta
# 强大的时间解析
dt = parser.parse("March 15, 2024 at 2:30pm")
print(f"解析结果: {dt}")
# 更灵活的时间计算
one_month_later = dt + relativedelta(months=1)
print(f"一个月后: {one_month_later}")
适用场景:需要解析各种非标准时间格式或进行复杂日期计算
5.2.3 arrow
python复制import arrow
# 更人性化的API
now = arrow.now()
print(f"现在: {now.format('YYYY-MM-DD HH:mm:ss')}")
# 时区转换更简单
utc = now.to('UTC')
print(f"UTC时间: {utc}")
适用场景:追求更简洁优雅的API设计
5.2.4 pandas Timestamp
python复制import pandas as pd
# 处理时间序列数据
ts = pd.Timestamp('2024-03-15 14:30:00')
print(f"时间戳: {ts}")
print(f"下个季度: {ts + pd.offsets.QuarterBegin()}")
# 批量处理
dates = pd.date_range('2024-01-01', periods=12, freq='M')
print(f"2024年各月末: {dates.tolist()}")
适用场景:数据分析领域,需要处理大量时间序列数据
5.3 选择建议
- 简单日期处理:优先使用标准库datetime
- 复杂时区处理:pytz + datetime组合
- 非标准时间解析:dateutil.parser
- 更人性化API:arrow
- 数据分析场景:pandas Timestamp
提示:在性能敏感的场景中,datetime模块通常是最快的选择,因为它是用C实现的。第三方库虽然提供了更丰富的功能,但往往以性能为代价。
6. 最佳实践与经验分享
经过多年的Python开发实践,我总结了以下datetime模块的使用心得:
6.1 时间处理黄金法则
-
明确时区:始终清楚你的时间对象是naive还是aware,建议在系统内部统一使用UTC,只在显示时转换为本地时间。
-
早解析晚格式化:尽早将用户输入的时间字符串解析为datetime对象,只在最后输出时格式化为字符串。
-
使用合适的类型:如果只需要日期,使用date类;如果只需要时间,使用time类;需要完整时间戳时再用datetime。
-
边界条件检查:特别注意月末、闰年、夏令时转换等边界情况。
-
文档化假设:明确记录所有关于时间处理的假设(如工作日定义、时区规则等)。
6.2 性能优化技巧
- 避免频繁调用now():在性能关键代码中,可以缓存当前时间而不是重复调用。
python复制# 不推荐
for item in large_list:
process(item, datetime.now())
# 推荐
current_time = datetime.now()
for item in large_list:
process(item, current_time)
-
批量处理时间字符串:对于大量时间字符串解析,考虑预编译正则表达式。
-
使用timestamp存储:在需要存储大量时间数据时,使用时间戳而非字符串可以节省空间和提高处理速度。
-
选择合适的数据结构:对于时间范围查询,考虑使用专门的时间索引数据结构。
6.3 常见错误排查
当时间处理出现问题时,可以按照以下步骤排查:
- 检查时区状态:确认所有比较的时间对象都是naive或都是aware
- 验证输入格式:确保时间字符串与格式说明符完全匹配
- 检查夏令时转换:特别关注3月和11月的时间数据
- 测试边界条件:验证月末、闰年等特殊日期
- 记录中间结果:在复杂时间计算中记录关键步骤的结果
6.4 测试策略
健全的时间处理测试应该包括:
python复制import unittest
from datetime import datetime, timedelta
class TestDateTimeHandling(unittest.TestCase):
def test_normal_case(self):
# 测试正常情况
pass
def test_leap_year(self):
# 测试闰年
feb28 = datetime(2024, 2, 28)
self.assertEqual((feb28 + timedelta(days=1)).day, 29)
def test_timezone_awareness(self):
# 测试时区感知
naive = datetime.now()
aware = datetime.now(timezone.utc)
with self.assertRaises(TypeError):
_ = naive == aware
def test_month_end(self):
# 测试月末处理
jan31 = datetime(2024, 1, 31)
feb28 = datetime(2024, 2, 28)
self.assertEqual((jan31 + timedelta(days=28)), feb28)
def test_dst_transition(self):
# 测试夏令时转换
pass # 需要使用pytz测试
6.5 扩展思考
-
时间旅行测试:在测试环境中模拟时间前进、后退,验证系统在时间变化时的行为。
-
多时区协作:设计系统时考虑全球化团队的工作时间重叠计算。
-
历史时间处理:对于需要处理历史数据的系统,注意历法变化(如1582年格里高利历改革)。
-
时间精度选择:根据业务需求选择合适的时间精度(秒、毫秒、微秒等)。
-
不可变时钟:在测试中使用可模拟的时钟接口,而不是直接调用datetime.now()。
时间处理看似简单,但魔鬼藏在细节中。掌握datetime模块的方方面面,你就能在Python时间处理的世界里游刃有余。记住,好的时间处理代码应该像精确的瑞士手表一样可靠,像优雅的诗歌一样清晰。
