Skip to content

Python 日期与时间

处理日期和时间是编程中的常见需求。Python 提供了强大的模块来处理日期、时间以及时间间隔。

主要的内置模块是:

  • time:提供与系统时间相关的函数,包括时间测量和休眠。通常是更底层的操作。
  • datetime:以更面向对象的方式提供用于处理日期和时间的类。通常是大多数日期/时间计算和表示的首选。
  • calendar:提供与日历相关的函数,例如生成文本日历。

纪元(Epoch)与时间刻度(Ticks)

Section titled “纪元(Epoch)与时间刻度(Ticks)”

许多系统将时间测量为自一个特定起点(称为纪元,Epoch)以来经过的秒数。对于基于 Unix 的系统(包括 Linux 和 macOS),纪元通常是 1970 年 1 月 1 日 00:00:00 (UTC)。Windows 可能对某些系统函数使用不同的纪元,但 Python 的 time 模块始终使用 Unix 纪元。

函数 time.time() 返回当前时间,它是一个浮点数,表示自纪元以来的秒数。这个值有时被称为“Unix 时间戳”(Unix timestamp)或“时间刻度”(ticks)(尽管 ‘ticks’ 在不同上下文中可能具有其他含义)。

#!/usr/bin/env python3
import time
seconds_since_epoch = time.time()
print(f"Seconds since epoch: {seconds_since_epoch}") # 打印自纪元以来的秒数

这会产生如下输出:

Seconds since epoch: 1678886400.123456

直接使用纪元秒数对于简单的时差计算很有用,但表示特定的日期和时间通常需要更结构化的格式。

time 模块中的几个函数处理或返回一个名为 time.struct_time 的类似元组的对象。它表示一个特定的时间点,包含年、月、日、时、分等组件。

该结构包含以下属性(可通过索引或名称访问):

索引属性值
0tm_year年(例如 2023)
1tm_mon月(1-12)
2tm_mday月中的日期(1-31)
3tm_hour时(0-23)
4tm_min分(0-59)
5tm_sec秒(0-61;包含闰秒)
6tm_wday星期几(0=周一 到 6=周日)
7tm_yday一年中的第几天(1-366)
8tm_isdst夏令时标志(0、1,未知时为 -1)

time.localtime() 将自纪元以来的秒数(如果没有提供参数,则为当前时间)转换为表示本地时间的 struct_time 对象。

#!/usr/bin/env python3
import time
local_time_struct = time.localtime() # 使用当前时间
print(f"Local time struct: {local_time_struct}") # 打印本地时间结构
# 访问元素
print(f"Year: {local_time_struct.tm_year}") # 打印年份
print(f"Hour: {local_time_struct.tm_hour}") # 打印小时

time.gmtime() 工作方式类似,但返回的是协调世界时 (UTC) 的 struct_time。

虽然 struct_time 是结构化的,但它不是非常易读。Python 提供了将时间格式化为字符串的函数。

time.asctime():将 struct_time(如果没有参数,则为当前本地时间)转换为标准的 24 个字符的字符串格式。

#!/usr/bin/env python3
import time
# 使用当前本地时间
ascii_time_now = time.asctime()
print(f"Formatted time (asctime): {ascii_time_now}") # 打印格式化后的时间 (asctime)
# 使用特定的 struct_time
local_time_struct = time.localtime()
ascii_time_local = time.asctime(local_time_struct)
print(f"Formatted time from struct: {ascii_time_local}") # 打印从 struct_time 格式化的时间

输出可能看起来像:Formatted time (asctime): Wed Mar 15 12:30:00 2023

time.strftime():通过允许使用自定义格式代码,提供了更大的灵活性。

#!/usr/bin/env python3
import time
local_time_struct = time.localtime()
# 示例格式代码:
# %Y - 带世纪的年份(例如 2023)
# %m - 月份,带前导零的十进制数(01-12)
# %d - 月份中的日期,带前导零的十进制数(01-31)
# %H - 小时(24 小时制),带前导零的十进制数(00-23)
# %M - 分钟,带前导零的十进制数(00-59)
# %S - 秒,带前导零的十进制数(00-61)
# %a - 星期的缩写名称(Sun, Mon, ...)
# %A - 星期的完整名称(Sunday, Monday, ...)
# %b - 月份的缩写名称(Jan, Feb, ...)
# %B - 月份的完整名称(January, February, ...)
formatted_string = time.strftime("%Y-%m-%d %H:%M:%S", local_time_struct)
print(f"Custom format 1: {formatted_string}") # 打印自定义格式 1
formatted_string_verbose = time.strftime("%A, %B %d, %Y (%I:%M:%S %p %Z)", local_time_struct)
# %I - 小时(12 小时制),%p - AM/PM,%Z - 时区名称
print(f"Custom format 2: {formatted_string_verbose}") # 打印自定义格式 2

strftime 对于创建各种格式的易读日期/时间字符串非常有用。

time 模块中的关键函数:

函数描述
time.time()返回当前时间,为自纪元以来的秒数(浮点数)。
time.sleep(secs)暂停执行指定的秒数(可以是浮点数)。
time.localtime([secs])将自纪元以来的秒数转换为本地 struct_time。
time.gmtime([secs])将自纪元以来的秒数转换为 UTC struct_time。
time.mktime(t)将本地 struct_time 对象 t 转换回自纪元以来的秒数。
time.asctime([t])将 struct_time 对象 t 转换为标准格式的字符串。
time.strftime(format[, t])根据 format 代码将 struct_time 对象 t 格式化为字符串。
time.strptime(string, format)根据 format 代码解析表示时间的 string 字符串,返回 struct_time。
time.perf_counter()返回高精度性能计数器的值(用于测量短时间间隔)。绝对值未定义,只有两次调用之间的差值有效。
time.process_time()返回当前进程的系统和用户 CPU 时间总和。用于基准测试 CPU 使用情况。

注意:time.clock() 在 Python 3.3 中已弃用,并在 3.8 中移除。请改用 time.perf_counter() 或 time.process_time(),取决于你需要测量性能的“墙上时钟”时间还是 CPU 时间。

虽然 time 模块很有用,但 datetime 模块提供了更强大、更面向对象的方式来处理日期和时间。它通常推荐用于大多数应用。

datetime 中的关键类:

  • datetime.date:表示一个日期(年、月、日)。
  • datetime.time:表示一个时间(时、分、秒、微秒)。
  • datetime.datetime:表示日期和时间。
  • datetime.timedelta:表示两个日期或时间之间的时间段或差值。
  • datetime.timezone:表示时区信息(更强大的时区处理通常需要外部库如 pytz 或在 Python 3.9+ 中使用 zoneinfo)。
#!/usr/bin/env python3
from datetime import datetime, date, timedelta
# 获取当前日期和时间
now = datetime.now()
print(f"Current datetime: {now}") # 打印当前日期时间
# 获取当前日期
today = date.today()
print(f"Current date: {today}") # 打印当前日期
# 创建特定的日期和日期时间对象
d1 = date(2024, 7, 20)
dt1 = datetime(2024, 7, 20, 15, 30, 0)
print(f"Specific date: {d1}") # 打印特定日期
print(f"Specific datetime: {dt1}") # 打印特定日期时间
# 使用 strftime 格式化(也适用于 datetime 对象)
print(f"Formatted datetime: {now.strftime('%Y/%m/%d %H:%M')}") # 打印格式化后的日期时间
# 使用 timedelta 进行日期算术运算
yesterday = today - timedelta(days=1)
next_week = today + timedelta(weeks=1)
print(f"Yesterday was: {yesterday}") # 打印昨天日期
print(f"Next week is: {next_week}") # 打印下周日期
# 计算日期时间差
diff = now - dt1
print(f"Difference between now and dt1: {diff}") # 打印 now 和 dt1 之间的时间差
print(f"Difference in seconds: {diff.total_seconds()}") # 打印以秒为单位的时间差
# 将字符串解析为 datetime 对象
date_string = "2023-01-15 10:00:00"
parsed_dt = datetime.strptime(date_string, "%Y-%m-%d %H:%M:%S")
print(f"Parsed datetime: {parsed_dt}") # 打印解析后的日期时间

与 time.struct_time 相比,datetime 模块提供了更简洁的接口用于日期和时间的算术运算及操作。

calendar 模块提供了与日历相关的函数,例如生成月度或年度文本日历以及判断闰年。

#!/usr/bin/env python3
import calendar
# 获取 2024 年 3 月的文本日历
cal_text = calendar.month(2024, 3)
print("Calendar for March 2024:") # 打印 "Calendar for March 2024:"
print(cal_text) # 打印日历文本
# 检查是否为闰年
is_leap = calendar.isleap(2024)
print(f"Is 2024 a leap year? {is_leap}") # 打印 "Is 2024 a leap year? {is_leap}"
# 获取特定日期的星期几代码(0=周一)
weekday_code = calendar.weekday(2024, 3, 15)
print(f"Weekday code for 2024-03-15: {weekday_code} (Friday)") # 打印 "Weekday code for 2024-03-15: {weekday_code} (Friday)"
# 设置每周的第一天(例如,周日 = 6)
# calendar.setfirstweekday(calendar.SUNDAY)
# cal_text_sun_start = calendar.month(2024, 3)
# print("\nCalendar starting on Sunday:")
# print(cal_text_sun_start)

对于更高级的日期/时间处理,特别是涉及时区或解析复杂日期字符串的情况,可以考虑以下流行的第三方库:

  • pytz:提供全面的时区支持(使用 Olson 时区数据库)。对于准确的时区感知应用至关重要。
  • python-dateutil:提供 datetime 的强大扩展,包括解析各种格式的日期字符串的更高级功能。
  • zoneinfo(内置,Python 3.9+):提供访问系统 IANA 时区数据库的功能,对于许多用例来说是 pytz 的标准库替代方案。