Python 日期时间

处理时间是编程里绕不开的需求——日志时间戳、生日计算、定时任务、日期格式化。Python 标准库 datetime 模块设计得相当优雅,这一章把常用功能讲全:当前时间、格式化、时间戳、时间差、时区。

1. 三个核心类:date / time / datetime

Python 把日期时间分成三个类,组合使用:

from datetime import datetime, date, time

# 1. 当前日期时间
now = datetime.now()           # 本地日期时间
print(now)                     # 2024-08-05 14:30:25.123456
print(type(now))               # <class 'datetime.datetime'>

# 2. 当前日期
today = date.today()
print(today)                   # 2024-08-05

# 3. 当前时间(只有时分秒,不含日期)
current_time = datetime.now().time()
print(current_time)            # 14:30:25.123456

# 4. 协调世界时(UTC)
utc_now = datetime.utcnow()
print(utc_now)                 # 2024-08-05 06:30:25.123456 (比北京时间少 8 小时)

# 5. 访问各个字段
print(now.year)                # 2024
print(now.month)               # 8
print(now.day)                 # 5
print(now.hour)                # 14
print(now.minute)              # 30
print(now.second)              # 25
print(now.weekday())           # 0(周一)~ 6(周日)

2. 创建指定时间

from datetime import datetime, date, time

# 1. 创建指定日期时间
dt = datetime(2024, 8, 5, 14, 30, 0)
print(dt)                      # 2024-08-05 14:30:00

# 2. 创建日期
d = date(2024, 8, 5)
print(d)                       # 2024-08-05

# 3. 创建时间
t = time(14, 30, 0)
print(t)                       # 14:30:00

# 4. 从 date 和 time 组合成 datetime
combined = datetime.combine(d, t)
print(combined)                # 2024-08-05 14:30:00

# 5. 拆分 datetime 为 date 和 time
dt = datetime.now()
print(dt.date())               # 2024-08-05
print(dt.time())               # 14:30:25.123456

3. 格式化:strftime / strptime

这是日期时间最常用的两个方法,名字很怪但极有用:

from datetime import datetime

dt = datetime(2024, 8, 5, 14, 30, 45)

# 1. strftime:datetime -> 字符串(格式化输出)
# 常用占位符:
# %Y 四位年    %m 月(01-12)   %d 日(01-31)
# %H 时(00-23) %M 分(00-59)   %S 秒(00-59)
# %A 星期全名   %a 星期简写      %B 月份全名
# %p AM/PM     %w 数字星期(0=周日)

print(dt.strftime("%Y-%m-%d"))             # 2024-08-05
print(dt.strftime("%Y年%m月%d日"))           # 202408月05日
print(dt.strftime("%H:%M:%S"))             # 14:30:45
print(dt.strftime("%Y-%m-%d %H:%M:%S"))    # 2024-08-05 14:30:45
print(dt.strftime("%A, %B %d, %Y"))        # Monday, August 05, 2024
print(dt.strftime("%Y/%m/%d %I:%M %p"))    # 2024/08/05 02:30 PM(12 小时制)

# 2. strptime:字符串 -> datetime(解析输入)
date_str = "2024-08-05 14:30:45"
parsed = datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S")
print(parsed)                  # 2024-08-05 14:30:45
print(type(parsed))            # <class 'datetime.datetime'>

# 解析各种格式
print(datetime.strptime("08/05/2024", "%m/%d/%Y"))
print(datetime.strptime("Aug 5, 2024", "%b %d, %Y"))

常用占位符(记这几个就够 90% 场景):

4. 时间戳 timestamp

时间戳是"自 1970-01-01 00:00:00 UTC 起的秒数",是计算机存储时间的标准方式。数据库、日志、网络传输几乎都用时间戳。

from datetime import datetime

# 1. 时间戳(timestamp):自 1970-01-01 00:00:00 UTC 起的秒数
# 计算机存储时间的标准方式

now = datetime.now()
ts = now.timestamp()           # datetime -> 时间戳
print(ts)                      # 1722832225.123456 (浮点数)

# 2. 时间戳 -> datetime
dt = datetime.fromtimestamp(ts)
print(dt)                      # 2024-08-05 14:30:25

# 3. 当前时间戳(常用)
import time
print(time.time())             # 1722832225.123456  和上面一样

# 4. 实用例子:测量代码执行时间
start = time.time()

# 模拟一段耗时操作
total = sum(range(1_000_000))

end = time.time()
print(f"耗时 {end - start:.4f} 秒")

# 5. 更精确的计时(推荐用 time.perf_counter)
start = time.perf_counter()
sum(range(1_000_000))
elapsed = time.perf_counter() - start
print(f"耗时 {elapsed:.6f} 秒")

测量代码执行时间用 time.perf_counter()time.time() 更精确(它是专门为计时设计的)。

5. timedelta:时间差

timedelta 表示一段"时间长度",可以和 datetime 做加减,得到新时间。这是处理"几天后""几小时前"的标准方式。

from datetime import datetime, timedelta

now = datetime.now()

# 1. 创建时间差
delta = timedelta(days=7)
print(delta)                   # 7 days, 0:00:00

# 2. 时间 +/- 时间差 = 新时间
future = now + timedelta(days=7)         # 一周后
past = now - timedelta(days=1)           # 昨天
print(future)
print(past)

# timedelta 支持的单位:days, seconds, microseconds, milliseconds, minutes, hours, weeks
print(now + timedelta(hours=3))          # 3 小时后
print(now + timedelta(weeks=2))          # 两周后
print(now - timedelta(minutes=30))       # 半小时前

# 3. 两个时间相减 = 时间差
dt1 = datetime(2024, 8, 5)
dt2 = datetime(2024, 8, 1)
diff = dt1 - dt2
print(diff)                    # 4 days, 0:00:00
print(diff.days)               # 4
print(diff.total_seconds())    # 345600.0   总秒数

# 4. 实用例子:计算年龄
def age(birth_date):
    today = datetime.now().date()
    years = today.year - birth_date.year
    # 如果生日还没到,年龄减 1
    if (today.month, today.day) < (birth_date.month, birth_date.day):
        years -= 1
    return years

print(age(date(2000, 5, 15)))  # 24 (取决于当前日期)

记住:datetime + timedelta = 新 datetime,datetime - datetime = timedelta

6. 时区处理

处理全球用户的应用必须考虑时区。Python 3.9+ 引入了 zoneinfo 模块(基于 IANA 时区数据库),更推荐使用。下面是基础用法:

from datetime import datetime, timezone, timedelta

# 1. 时区对象:timezone(timedelta(hours=N))
utc = timezone.utc                  # UTC 协调世界时
beijing = timezone(timedelta(hours=8))   # 东八区(北京时间)
ny = timezone(timedelta(hours=-5))       # 美国东部时间

# 2. 给时间附加时区信息
now_utc = datetime.now(utc)
print(now_utc)                  # 2024-08-05 06:30:25+00:00  (末尾 +00:00 是 UTC)
print(now_utc.tzinfo)           # UTC

now_bj = datetime.now(beijing)
print(now_bj)                   # 2024-08-05 14:30:25+08:00

# 3. 时区转换:astimezone
# 把 UTC 时间转成北京时间
utc_to_bj = now_utc.astimezone(beijing)
print(utc_to_bj)                # 2024-08-05 14:30:25+08:00  (加 8 小时)

# 4. 不带时区的时间(_naive datetime)
naive = datetime.now()          # 本地时间,但没有时区信息
print(naive.tzinfo)             # None

# naive 和 aware 时间不能直接比较,会报错
# aware 时间可以跨时区正确比较

# 5. 实用:数据库/网络传输统一用 UTC,显示时转本地
# 这是处理全球用户的最佳实践

时区最佳实践:存储、传输统一用 UTC,显示时再转用户本地时区。这能避免绝大多数时间混乱问题。

7. calendar 模块

需要"闰年判断""月历打印""某月天数"时,calendar 模块很方便。

import calendar

# 1. 打印月历
print(calendar.month(2024, 8))
#      August 2024
# Mo Tu We Th Fr Sa Su
#           1  2  3  4
#  5  6  7  8  9 10 11
# ...

# 2. 是否闰年
print(calendar.isleap(2024))    # True  (能被 4 整除且不被 100 整除,或能被 400 整除)
print(calendar.isleap(2023))    # False
print(calendar.isleap(2000))    # True  (能被 400 整除)

# 3. 某月有多少天
print(calendar.monthrange(2024, 2))   # (3, 29)
# 第一个数:该月 1 号是星期几(0=周一)
# 第二个数:该月总天数(2024 是闰年,2 月有 29 天)

# 4. 某月所有天的二维列表(周为行)
weeks = calendar.monthcalendar(2024, 8)
print(weeks)
# [[0, 0, 0, 1, 2, 3, 4], [5, 6, 7, 8, 9, 10, 11], ...]

8. 实用代码片段

from datetime import datetime, timedelta

# 1. 本月第一天
first_day = datetime.now().replace(day=1).date()
print(first_day)

# 2. 上月同一天
now = datetime.now()
if now.month == 1:
    last_month = now.replace(year=now.year - 1, month=12)
else:
    last_month = now.replace(month=now.month - 1)
print(last_month)

# 3. 友好显示:几分钟前 / 几小时前
def time_ago(dt):
    diff = datetime.now() - dt
    seconds = diff.total_seconds()
    if seconds < 60:
        return f"{int(seconds)} 秒前"
    elif seconds < 3600:
        return f"{int(seconds // 60)} 分钟前"
    elif seconds < 86400:
        return f"{int(seconds // 3600)} 小时前"
    else:
        return f"{int(seconds // 86400)} 天前"

print(time_ago(datetime.now() - timedelta(minutes=30)))

小结

日期时间是程序的基础设施。重点掌握:date/time/datetime 三个类strftime/strptime 格式化(常用占位符)、时间戳 timestamptimedelta 时间差(加减天数/小时)、时区处理(UTC 存储、本地显示)、calendar 工具

恭喜!你已经完成了 Python 17 篇入门系列的最后一篇。从语法、数据结构、控制流、函数到面向对象、文件、异常、时间,你已经具备独立写 Python 程序的全部基础。接下来挑一个方向(Web 后端 / 数据分析 / AI / 自动化)做个真实项目,边做边学,进步最快。

← 上一篇 Python 异常处理

返回 Python 教程目录

✈️💬