第3章:数字、日期与时间
一、导读
1.1 本章学习目标
第3章讲解 Python 中数字和日期时间的处理技巧:decimal 精确计算、datetime 时区处理。
本章核心学习目标:
- 掌握 decimal 模块:精确的浮点运算
- 理解 datetime 和时区:正确处理时间
- 掌握日期运算:timedelta、relativedelta
1.2 为什么本章如此重要
浮点精度和时区是编程中最容易出错的两个领域。Python 提供了专门的模块来处理这些问题。
1.3 核心问题引导
为什么 0.1 + 0.2 ≠ 0.3?如何解决?
如何处理不同时区的时间转换?
如何计算两个日期之间的工作日数?
二、核心概念详解
2.1 精确浮点运算
python
from decimal import Decimal, getcontext
# 浮点精度问题
print(0.1 + 0.2) # 0.30000000000000004
print(0.1 + 0.2 == 0.3) # False
# 使用 Decimal
a = Decimal('0.1')
b = Decimal('0.2')
print(a + b) # 0.3
print(a + b == Decimal('0.3')) # True
# 设置精度
getcontext().prec = 50
print(Decimal(1) / Decimal(7)) # 0.14285714285714285714285714285714285714285714285714
# 金融计算
price = Decimal('19.99')
tax_rate = Decimal('0.0825')
total = price * (1 + tax_rate)
print(f"Total: ${total:.2f}") # Total: $21.642.2 日期与时间
python
from datetime import datetime, timedelta, timezone
import zoneinfo
# 当前时间
now = datetime.now()
utc_now = datetime.now(timezone.utc)
# 时区转换
tokyo_tz = zoneinfo.ZoneInfo('Asia/Tokyo')
tokyo_time = utc_now.astimezone(tokyo_tz)
print(f"Tokyo: {tokyo_time}")
# 日期运算
tomorrow = now + timedelta(days=1)
next_week = now + timedelta(weeks=1)
diff = tomorrow - now
print(f"Diff: {diff.days} days")
# 日期解析
from dateutil import parser
dt = parser.parse("March 15, 2024 3:30 PM")
print(dt) # 2024-03-15 15:30:00
# 格式化
print(now.strftime("%Y-%m-%d %H:%M:%S"))
print(now.isoformat())2.3 工作日计算
python
from datetime import date, timedelta
def workdays_between(start, end):
"""计算两个日期之间的工作日数"""
days = 0
current = start
while current <= end:
if current.weekday() < 5: # 周一到周五
days += 1
current += timedelta(days=1)
return days
start = date(2024, 1, 1)
end = date(2024, 1, 31)
print(f"Workdays: {workdays_between(start, end)}") # 23三、实战案例
3.1 案例一:时区安全的日程管理
python
from datetime import datetime
import zoneinfo
class Scheduler:
def __init__(self, default_tz='UTC'):
self.default_tz = zoneinfo.ZoneInfo(default_tz)
self.events = []
def add_event(self, title, start_str, tz_str=None):
tz = zoneinfo.ZoneInfo(tz_str) if tz_str else self.default_tz
start = datetime.fromisoformat(start_str).replace(tzinfo=tz)
self.events.append({'title': title, 'start': start})
def list_events(self, tz_str='UTC'):
tz = zoneinfo.ZoneInfo(tz_str)
for event in sorted(self.events, key=lambda e: e['start']):
local_start = event['start'].astimezone(tz)
print(f"{event['title']}: {local_start.strftime('%Y-%m-%d %H:%M %Z')}")
scheduler = Scheduler()
scheduler.add_event("Team Meeting", "2024-03-15 10:00:00", "America/New_York")
scheduler.add_event("Code Review", "2024-03-15 14:00:00", "Asia/Tokyo")
print("New York time:")
scheduler.list_events("America/New_York")
print("\nTokyo time:")
scheduler.list_events("Asia/Tokyo")四、本章小结
Decimal 提供精确的浮点运算,适合金融计算
datetime + zoneinfo 正确处理时区
timedelta 支持日期运算
五、思考与练习
为什么应该总是使用带时区的 datetime?
如何处理夏令时(DST)的转换?