69_Python时间日期处理

Python时间日期处理:datetime库完全指南

文章目录

前言

时间日期处理是编程中最常见的需求之一------无论是记录日志时间戳、计算日期差、格式化输出,还是处理时区转换,都离不开时间和日期操作。Python提供了 datetimetimecalendar 三个核心模块来应对这些需求。

时间处理的常见坑 :很多开发者在处理时间时踩过"时区"的坑------服务器在UTC时区,数据库存的是本地时间,前端又显示用户时区,三种时间混在一起调试时让人抓狂。此外,strftimestrptime 的格式化代码容易混淆,闰年、月末、夏令时等边界条件也常常导致bug。本文将以 datetime 模块为主线,带你全面掌握Python时间日期处理的核心技巧,并特别强调那些容易出错的"暗坑"。

一、datetime 模块核心类

datetime 模块主要包含四个类:

python 复制代码
from datetime import date, time, datetime, timedelta

# 1. date:只包含日期(年、月、日)
d = date(2024, 1, 15)
print(f"date: {d}")  # 2024-01-15

# 2. time:只包含时间(时、分、秒、微秒)
t = time(14, 30, 45, 500000)
print(f"time: {t}")  # 14:30:45.500000

# 3. datetime:日期 + 时间
dt = datetime(2024, 1, 15, 14, 30, 45)
print(f"datetime: {dt}")  # 2024-01-15 14:30:45

# 4. timedelta:时间间隔(两个日期/时间之间的差值)
delta = timedelta(days=7, hours=3, minutes=30)
print(f"timedelta: {delta}")  # 7 days, 3:30:00

二、获取当前时间

python 复制代码
from datetime import datetime, date, time

# 当前日期时间
now = datetime.now()
print(f"当前日期时间: {now}")

# 当前日期
today = date.today()
print(f"当前日期: {today}")

# UTC时间(世界协调时)
utc_now = datetime.utcnow()
print(f"UTC时间: {utc_now}")

# 获取年月日时分秒等属性
print(f"年: {now.year}, 月: {now.month}, 日: {now.day}")
print(f"时: {now.hour}, 分: {now.minute}, 秒: {now.second}")
print(f"微秒: {now.microsecond}")
print(f"星期几 (0=周一): {now.weekday()}")
print(f"星期几 (1=周日): {now.isoweekday()}")

三、创建指定日期时间

python 复制代码
from datetime import datetime, date, time

# 直接构造
dt1 = datetime(2025, 6, 1, 9, 0, 0)
print(dt1)  # 2025-06-01 09:00:00

# 只提供日期部分
dt2 = datetime(2025, 12, 31)
print(dt2)  # 2025-12-31 00:00:00

# 从时间戳创建
timestamp = 1705315200  # 2024-01-15 12:00:00 UTC
dt3 = datetime.fromtimestamp(timestamp)
print(f"从时间戳: {dt3}")

# 从ISO格式字符串创建
dt4 = datetime.fromisoformat("2024-06-15T09:30:00")
print(f"从ISO格式: {dt4}")

# 合并date和time
d = date(2025, 1, 1)
t = time(12, 30, 0)
dt5 = datetime.combine(d, t)
print(f"合并: {dt5}")  # 2025-01-01 12:30:00

四、strftimestrptime:格式化与解析

这是实际开发中使用频率最高的两个方法。两者的方向相反strftime(format time)将 datetime 对象转换为字符串;strptime(parse time)将字符串解析为 datetime 对象。记住它们的区别有一个简单方法:f 代表 format(格式化输出),p 代表 parse(解析输入)。

4.1 strftime:日期时间 → 字符串

python 复制代码
from datetime import datetime

now = datetime.now()

# 常用格式
print(now.strftime("%Y-%m-%d"))            # 2024-01-15
print(now.strftime("%Y年%m月%d日"))         # 2024年01月15日
print(now.strftime("%Y/%m/%d %H:%M:%S"))   # 2024/01/15 14:30:45
print(now.strftime("%Y-%m-%d %I:%M %p"))   # 2024-01-15 02:30 PM
print(now.strftime("%A, %B %d, %Y"))       # Monday, January 15, 2024
print(now.strftime("%j"))                  # 015 (一年中的第几天)
print(now.strftime("%U"))                  # 03  (一年中的第几周)

4.2 strptime:字符串 → 日期时间

python 复制代码
from datetime import datetime

# 解析各种格式的日期字符串
date_str1 = "2024-01-15"
dt1 = datetime.strptime(date_str1, "%Y-%m-%d")
print(dt1)  # 2024-01-15 00:00:00

date_str2 = "2024年01月15日 14:30:45"
dt2 = datetime.strptime(date_str2, "%Y年%m月%d日 %H:%M:%S")
print(dt2)  # 2024-01-15 14:30:45

date_str3 = "15/Jan/2024:14:30:45"
dt3 = datetime.strptime(date_str3, "%d/%b/%Y:%H:%M:%S")
print(dt3)  # 2024-01-15 14:30:45

# 解析中文日期
date_str4 = "2024年1月15日"
dt4 = datetime.strptime(date_str4, "%Y年%m月%d日")
print(dt4)

4.3 格式化代码速查表

代码 含义 示例
%Y 4位年份 2024
%m 月份 (01-12) 01
%d 日期 (01-31) 15
%H 24小时 (00-23) 14
%I 12小时 (01-12) 02
%M 分钟 (00-59) 30
%S 秒 (00-59) 45
%p AM/PM PM
%A 完整星期名 Monday
%B 完整月份名 January
%j 一年中第几天 015

五、timedelta:日期计算

timedelta 是日期运算的核心工具,它表示两个日期/时间之间的差值 。你可以用它对日期进行加减操作,也可以计算两个日期之间的间隔。常见陷阱timedelta 只支持 days、seconds 和 microseconds,不支持 months 和 years------因为月份和年份的长度不是固定的(28-31天,365/366天)。如果需要按月或按年进行计算,推荐使用第三方库 dateutilrelativedelta

python 复制代码
from datetime import datetime, timedelta

now = datetime.now()

# 日期加减
tomorrow = now + timedelta(days=1)
yesterday = now - timedelta(days=1)
next_week = now + timedelta(weeks=1)
three_hours_later = now + timedelta(hours=3)
half_hour_ago = now - timedelta(minutes=30)

print(f"明天: {tomorrow.strftime('%Y-%m-%d')}")
print(f"昨天: {yesterday.strftime('%Y-%m-%d')}")
print(f"下周: {next_week.strftime('%Y-%m-%d')}")
print(f"3小时后: {three_hours_later.strftime('%H:%M')}")
print(f"半小时前: {half_hour_ago.strftime('%H:%M')}")

# 计算两个日期的差值
birthday = datetime(1995, 8, 22)
age_delta = now - birthday
print(f"自出生已过: {age_delta.days} 天")
print(f"约 {age_delta.days // 365} 年")

# 计算项目截止时间
deadline = datetime(2024, 12, 31, 23, 59, 59)
remaining = deadline - now
print(f"距离截止还有: {remaining.days}天 {remaining.seconds // 3600}小时")

六、time 模块补充

time 模块提供更底层的操作,主要处理时间戳程序休眠timedatetime 的分工是:time 模块处理底层的时间戳和系统时钟操作,datetime 模块提供高级的面向对象的日期时间接口。在实际开发中,你可以根据需求灵活选择:需要处理人类可读的日期和时间时用 datetime,需要操作时间戳或高精度计时时用 time

python 复制代码
import time

# 当前时间戳(自1970-01-01以来的秒数)
timestamp = time.time()
print(f"当前时间戳: {timestamp}")

# 休眠
print("等待3秒...")
time.sleep(3)
print("继续执行!")

# 时间戳 ↔ 结构化时间
local_time = time.localtime(timestamp)
print(f"本地时间: {time.strftime('%Y-%m-%d %H:%M:%S', local_time)}")

# UTC结构化时间
utc_time = time.gmtime(timestamp)
print(f"UTC时间: {time.strftime('%Y-%m-%d %H:%M:%S', utc_time)}")

# 结构化时间 → 时间戳
new_timestamp = time.mktime(local_time)
print(f"转回时间戳: {new_timestamp}")

# 性能计时(高精度)
start = time.perf_counter()
result = sum(range(1000000))
end = time.perf_counter()
print(f"计算耗时: {end - start:.6f}秒")

七、实战案例

理论知识最终要落地到实际场景。以下四个案例覆盖了时间日期处理最常见的工作场景------日期范围生成、日志时间戳解析、倒计时器和工作日计算。每个案例都可以作为模板代码直接使用。

7.1 日期范围生成器

python 复制代码
from datetime import datetime, timedelta


def date_range(start_date, end_date):
    """生成两个日期之间的所有日期"""
    current = start_date
    while current <= end_date:
        yield current
        current += timedelta(days=1)


# 生成某月所有日期
start = datetime(2024, 1, 1)
end = datetime(2024, 1, 31)

for d in date_range(start, end):
    if d.weekday() < 5:  # 仅工作日
        weekday_name = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
        print(f"{d.strftime('%Y-%m-%d')} {weekday_name[d.weekday()]}")

7.2 日志时间戳解析工具

python 复制代码
from datetime import datetime
import re


LOG_PATTERNS = [
    # 常见日志格式
    r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}",           # 2024-01-15 14:30:45
    r"\d{2}/\w{3}/\d{4}:\d{2}:\d{2}:\d{2}",           # 15/Jan/2024:14:30:45
    r"\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}",           # 2024/01/15 14:30:45
]


def parse_log_timestamp(line):
    """尝试多种格式解析日志中的时间戳"""
    for pattern in LOG_PATTERNS:
        match = re.search(pattern, line)
        if match:
            ts_str = match.group()
            # 尝试多种格式
            for fmt in [
                "%Y-%m-%d %H:%M:%S",
                "%d/%b/%Y:%H:%M:%S",
                "%Y/%m/%d %H:%M:%S",
            ]:
                try:
                    return datetime.strptime(ts_str, fmt)
                except ValueError:
                    continue
    return None


# 测试
log_lines = [
    '2024-01-15 14:30:45 INFO Server started',
    '15/Jan/2024:14:31:20 ERROR Connection refused',
    '2024/01/15 14:32:00 WARN Disk usage 90%',
]

for line in log_lines:
    ts = parse_log_timestamp(line)
    if ts:
        print(f"{ts} -> {line}")

7.3 简易倒计时器

python 复制代码
from datetime import datetime, timedelta
import time


def countdown(target_desc, target_datetime):
    """显示活动倒计时"""
    while True:
        now = datetime.now()
        remaining = target_datetime - now

        if remaining.total_seconds() <= 0:
            print(f"\r{target_desc} 已到来!" + " " * 20)
            break

        days = remaining.days
        hours, remainder = divmod(remaining.seconds, 3600)
        minutes, seconds = divmod(remainder, 60)

        display = f"\r距离{target_desc}还有: {days}天 {hours:02d}时 {minutes:02d}分 {seconds:02d}秒"
        print(display, end="", flush=True)
        time.sleep(1)

    print()


# 使用示例(设置一个未来时间点)
# target = datetime(2025, 1, 1, 0, 0, 0)
# countdown("2025年元旦", target)
print("倒计时器已就绪(取消注释上方代码运行)")

7.4 工作日计算器

python 复制代码
from datetime import datetime, timedelta


def add_business_days(start_date, days):
    """在start_date基础上增加days个工作日"""
    current = start_date
    remaining = days

    while remaining > 0:
        current += timedelta(days=1)
        # weekday(): 0=周一, 6=周日
        if current.weekday() < 5:  # 周一至周五
            remaining -= 1

    return current


def business_days_between(start, end):
    """计算两个日期之间的工作日天数"""
    current = start
    count = 0
    while current <= end:
        if current.weekday() < 5:
            count += 1
        current += timedelta(days=1)
    return count


# 使用示例
today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)

deadline = add_business_days(today, 10)
print(f"今天: {today.strftime('%Y-%m-%d')}")
print(f"10个工作日后: {deadline.strftime('%Y-%m-%d')}")

start = datetime(2024, 1, 1)
end = datetime(2024, 1, 31)
working_days = business_days_between(start, end)
print(f"2024年1月工作日: {working_days}天")

总结

Python时间日期处理的核心要点:

需求 推荐方案
获取当前时间 datetime.now()
格式化输出 使用 strftime()
解析日期字符串 使用 strptime()
日期加减计算 使用 timedelta
时间戳处理 使用 time.time() / datetime.fromtimestamp()
程序休眠 使用 time.sleep()
高精度计时 使用 time.perf_counter()

掌握 datetime 模块能让你轻松应对90%以上的时间日期处理需求。下一篇我们将学习数据序列化(JSON与Pickle),看看如何持久化和传输Python对象。

✅ 亮点总结

  • 清晰梳理 datetimedatetimetimedelta 四大核心类的职责与关系
  • strftime()strptime() 的格式化速查表,覆盖日期时间字符串的转换全场景
  • 时间戳(timestamp)与时区(timezone)处理,解决跨时区应用的常见问题
  • 实战案例:工作日计算器,演示 timedelta 累计、日期范围判断、节假日排除

适用场景

  • 日志系统:为每条日志添加高精度时间戳,用于问题追踪和性能分析
  • 定时任务:计算下一次执行的精确时间,如每日报表生成、定时数据清理
  • 业务系统:计算合同期限、会员有效期、倒计时等时间相关的业务逻辑

扩展方向

  • 学习 dateutil 第三方库,支持更灵活的日期解析(如"下周三"、"3天后"等自然语言)
  • 探索 pytz 库处理全球时区,结合 datetime 实现真正的跨时区时间计算
  • 掌握 arrow / pendulum 等新一代时间库,获得更人性化的 API 体验