datetime 模块通关攻略:10 个逆天场景 + 30 道送命题,通关解锁时间掌控者称号
内容简介
本系列文章是为 Python3 学习者精心设计的一套全面、实用的学习指南,旨在帮助读者从基础入门到项目实战,全面提升编程能力。文章结构由 5 个版块组成,内容层层递进,逻辑清晰。
- 基础速通:n 个浓缩提炼的核心知识点,夯实编程基础;
- 经典范例:10 个贴近实际的应用场景,深入理解 Python3 的编程技巧和应用方法;
- 避坑宝典:10 个典型错误解析,提供解决方案,帮助读者避免常见的编程陷阱;
- 水平考试:10 道测试题目,检验学习成果,附有标准答案,以便自我评估;
- 实战案例:3 个迷你项目开发,带领读者从需求分析到代码实现,掌握项目开发的完整流程。
无论你是 Python3 初学者,还是希望提升实战能力的开发者,本系列文章都能为你提供清晰的学习路径和实用的编程技巧,助你快速成长为 Python3 编程高手。
阅读建议
- 初学者:建议从 “基础速通” 开始,系统学习 Python3 的基础知识,然后通过 “经典范例” 和 “避坑宝典” 加深理解,最后通过 “水平考试” 和 “实战案例” 巩固所学内容;
- 有经验的开发者:可以直接跳转到 “经典范例” 和 “避坑宝典”,快速掌握 Python3 的高级应用技巧和常见错误处理方法,然后通过 “实战案例” 提升项目开发能力;
- 选择性学习:如果读者对某个特定主题感兴趣,可以直接选择相应版块学习。各版块内容既相互独立又逻辑关联,方便读者根据自身需求灵活选择;
- 测试与巩固:完成每个版块的学习后,建议通过 “水平考试” 检验学习效果,并通过 “实战案例” 将理论知识转化为实际技能;
- 项目实战优先:如果你更倾向于实战学习,可以直接从 “实战案例” 入手,边做边学,遇到问题再回溯相关知识点。
一、基础速通
Python 的 datetime
模块是标准库中用于处理日期和时间的核心模块。它提供了多种类和工具,方便开发者操作日期、时间、时间间隔以及时区信息。以下是其主要功能及组件:
1. 主要类及用途
1.1 datetime.date
- 功能:处理日期(年、月、日)。
- 示例:
from datetime import date today = date.today() # 获取当前日期 print(today) # 输出格式:2023-10-05
1.2 datetime.time
- 功能:处理时间(时、分、秒、微秒),不包含日期。
- 示例:
from datetime import time t = time(14, 30, 15) # 14点30分15秒 print(t) # 输出:14:30:15
1.3 datetime.datetime
- 功能:同时处理日期和时间(最常用)。
- 示例:
from datetime import datetime now = datetime.now() # 当前日期和时间 print(now) # 输出:2023-10-05 14:30:15.123456
1.4 datetime.timedelta
- 功能:表示时间间隔(如天数、秒数),用于日期/时间的加减运算。
- 示例:
from datetime import datetime, timedelta now = datetime.now() tomorrow = now + timedelta(days=1) # 当前时间加1天
1.5 datetime.tzinfo
(抽象基类)
- 功能:处理时区信息。需结合第三方库(如
pytz
)实现具体时区操作。
2. 核心功能
2.1 日期/时间的创建与操作
from datetime import datetime, date
# 创建特定日期或时间
dt = datetime(2023, 10, 5, 14, 30) # 2023年10月5日 14:30:00
d = date(2023, 10, 5) # 仅日期
# 获取当前时间
current_time = datetime.now()
2.2 日期/时间的格式化与解析
- 格式化输出(
strftime
):将日期时间转为字符串。formatted = dt.strftime("%Y-%m-%d %H:%M:%S") # 输出:2023-10-05 14:30:00
- 解析字符串(
strptime
):将字符串转为日期时间对象。parsed = datetime.strptime("2023-10-05", "%Y-%m-%d")
2.3 时间间隔计算
delta = timedelta(days=7, hours=3)
new_date = dt + delta # 加7天3小时
2.4 时区处理
- 默认
datetime
对象是“无时区”(naive),需借助pytz
库处理时区:import pytz utc_time = datetime.now(pytz.utc) # UTC时间 local_time = utc_time.astimezone(pytz.timezone("Asia/Shanghai")) # 转为上海时区
3. 小结内容
datetime
模块是 Python 处理日期和时间的标准工具,覆盖了从简单日期操作到复杂时区管理的需求。结合第三方库(如 pytz
、dateutil
)可进一步扩展其功能。
二、经典范例
本节展示 10 个Python datetime
模块的经典应用范例,附带代码示例和详细解释。
1. 计算年龄(精确到天)
场景:根据出生日期计算用户的年龄(精确到天数)。
from datetime import date
def calculate_age(birth_date: date) -> tuple:
today = date.today()
years = today.year - birth_date.year
months = today.month - birth_date.month
days = today.day - birth_date.day
# 调整未过生日的情况
if (months < 0) or (months == 0 and days < 0):
years -= 1
months += 12
# 计算剩余天数
if days < 0:
last_month = today.replace(month=today.month - 1)
days_in_last_month = (today - last_month).days
days += days_in_last_month
months -= 1
return years, months, days
birthday = date(1995, 8, 20)
age = calculate_age(birthday)
print(f"年龄:{age[0]}岁 {age[1]}月 {age[2]}天")
# 输出示例:年龄:28岁 1月 15天
2. 时间戳与日期互转
场景:将 Unix 时间戳转换为可读日期,或反向操作。
from datetime import datetime
# 时间戳 -> 日期
timestamp = 1696521600 # 2023-10-05 00:00:00 UTC
dt = datetime.fromtimestamp(timestamp)
print(f"时间戳转日期:{dt.strftime('%Y-%m-%d %H:%M:%S')}") # 输出:2023-10-05 00:00:00
# 日期 -> 时间戳
dt_obj = datetime(2023, 10, 5, 0, 0)
timestamp = int(dt_obj.timestamp())
print(f"日期转时间戳:{timestamp}") # 输出:1696521600
3. 生成日期范围
场景:生成两个日期之间的所有日期列表。
from datetime import datetime, timedelta
def date_range(start: str, end: str) -> list:
start_date = datetime.strptime(start, "%Y-%m-%d")
end_date = datetime.strptime(end, "%Y-%m-%d")
delta = end_date - start_date
dates = []
for i in range(delta.days + 1):
current_date = start_date + timedelta(days=i)
dates.append(current_date.strftime("%Y-%m-%d"))
return dates
date_list = date_range("2023-10-01", "2023-10-05")
print(date_list) # 输出:['2023-10-01', '2023-10-02', ..., '2023-10-05']
4. 判断闰年
场景:检查某年是否为闰年。
from datetime import date
def is_leap_year(year: int) -> bool:
try:
date(year, 2, 29) # 尝试创建2月29日
return True
except ValueError:
return False
print(is_leap_year(2024)) # 输出:True
print(is_leap_year(2023)) # 输出:False
5. 倒计时功能
场景:计算距离某个未来时间点的剩余时间。
from datetime import datetime, timedelta
def countdown(target: str) -> timedelta:
now = datetime.now()
target_time = datetime.strptime(target, "%Y-%m-%d %H:%M:%S")
remaining = target_time - now
return remaining
remaining_time = countdown("2024-01-01 00:00:00")
print(f"距离2024年元旦还有:{remaining_time.days}天 {remaining_time.seconds//3600}小时")
6. 统计代码执行时间
场景:测量某段代码的运行耗时。
from datetime import datetime
start = datetime.now()
# 模拟耗时操作
for _ in range(1000000):
pass
end = datetime.now()
elapsed = end - start
print(f"代码执行耗时:{elapsed.total_seconds():.4f}秒")
# 输出示例:代码执行耗时:0.1234秒
7. 时区转换
场景:将本地时间转换为其他时区的时间。
from datetime import datetime
import pytz
# 本地时间 -> UTC时间
local_time = datetime.now()
utc_time = local_time.astimezone(pytz.utc)
print(f"UTC时间:{utc_time.strftime('%Y-%m-%d %H:%M:%S')}")
# UTC时间 -> 纽约时间
ny_tz = pytz.timezone("America/New_York")
ny_time = utc_time.astimezone(ny_tz)
print(f"纽约时间:{ny_time.strftime('%Y-%m-%d %H:%M:%S')}")
8. 获取月末日期
场景:计算某个月份的最后一天。
from datetime import date
import calendar
def last_day_of_month(year: int, month: int) -> date:
_, last_day = calendar.monthrange(year, month)
return date(year, month, last_day)
print(last_day_of_month(2023, 2)) # 输出:2023-02-28
print(last_day_of_month(2024, 2)) # 输出:2024-02-29
9. 解析 ISO 8601 格式日期
场景:处理符合国际标准的日期字符串。
from datetime import datetime
iso_date_str = "2023-10-05T14:30:45+08:00"
dt = datetime.fromisoformat(iso_date_str)
print(dt) # 输出:2023-10-05 14:30:45+08:00
# 反向生成 ISO 格式
print(dt.isoformat()) # 输出原字符串
10. 时间差统计(精确到分钟)
场景:计算两个时间点之间的分钟数差值。
from datetime import datetime
def minutes_diff(start: str, end: str) -> int:
fmt = "%Y-%m-%d %H:%M:%S"
start_time = datetime.strptime(start, fmt)
end_time = datetime.strptime(end, fmt)
delta = end_time - start_time
return delta.total_seconds() // 60
diff = minutes_diff("2023-10-05 09:30:00", "2023-10-05 11:45:00")
print(f"时间差:{diff} 分钟") # 输出:135 分钟
小结内容
这些范例覆盖了 datetime
模块的常见需求:
- 时间计算:年龄、倒计时、月末日期
- 格式转换:时间戳、ISO 8601、时区
- 实用工具:日期范围生成、闰年判断、代码计时
- 业务逻辑:用户年龄验证、数据分析周期统计
通过组合这些方法,可以解决绝大多数日期时间处理问题。进阶场景可结合 dateutil
或 pandas
库进一步扩展。
三、避坑宝典
本节介绍 10 种Python datetime
模块使用中的常见错误、原因分析及纠错方法,涵盖开发中高频踩坑场景。
1. 时区处理不当(Naive vs Aware 对象)
错误示例
from datetime import datetime
import pytz
# 错误:混合 naive 和 aware 对象
dt_utc = datetime.now(pytz.utc) # aware(有时区)
dt_local = datetime.now() # naive(无时区)
diff = dt_utc - dt_local # 抛出 TypeError
原因
- Naive 对象:无时区信息的时间对象(如默认的
datetime.now()
)。 - Aware 对象:有时区信息的时间对象(如
datetime.now(pytz.utc)
)。 - 直接混合运算会导致类型错误。
纠错方法
统一时区处理:
dt_local = datetime.now(pytz.timezone("Asia/Shanghai")) # 转为 aware
diff = dt_utc - dt_local # 合法
2. 日期格式字符串混淆(如 %m 与 %M)
错误示例
from datetime import datetime
# 错误:将分钟格式符 %M 误写为月份 %m
dt = datetime.strptime("2023-10-05 14:30", "%Y-%m-%d %H:%m")
# 输出:datetime(2023, 10, 5, 14, 10)(错误解析)
原因
- 格式符
%m
表示月份,%M
表示分钟。 - 错误使用会导致解析结果混乱。
纠错方法
明确区分格式符:
dt = datetime.strptime("2023-10-05 14:30", "%Y-%m-%d %H:%M") # 正确
3. 月份和天数顺序错误(如 2023-13-1)
错误示例
from datetime import datetime
# 错误:将日期字符串中的月和日顺序写反
dt = datetime.strptime("2023-13-05", "%Y-%d-%m") # 误解析为 13月(不存在)
# 抛出 ValueError: month must be in 1..12
原因
- 某些日期格式(如
%Y-%d-%m
)容易混淆月和日的位置。 - 输入数据不符合实际日期规则(如月份 >12)。
纠错方法
- 统一使用 ISO 格式(
YYYY-MM-DD
)解析:dt = datetime.strptime("2023-05-13", "%Y-%m-%d") # 明确年月日顺序
- 对用户输入做严格验证。
4. 未处理夏令时(DST)导致时间错误
错误示例
import pytz
from datetime import datetime
tz = pytz.timezone("America/New_York")
dt = datetime(2023, 3, 12, 2, 30) # 夏令时切换时刻
dt_aware = tz.localize(dt) # 可能抛出 AmbiguousTimeError 或 NonExistentTimeError
原因
- 夏令时切换时,某些时间点不存在或重复(如时钟从 2:00 跳到 3:00)。
- 直接创建时间对象可能导致歧义。
纠错方法
使用 localize
的 is_dst
参数处理歧义:
dt_aware = tz.localize(dt, is_dst=False) # 明确指定是否为夏令时
# 或使用 normalize 调整
dt_aware = tz.normalize(dt_aware)
5. 日期越界(如 2月30日)
错误示例
from datetime import date
# 错误:创建不存在的日期
d = date(2023, 2, 30) # 抛出 ValueError: day is out of range for month
原因
- 未验证日期的有效性(如 2 月没有 30 天)。
纠错方法
- 使用
calendar.monthrange
验证月份最大天数:import calendar year, month = 2023, 2 max_day = calendar.monthrange(year, month)[1] if day > max_day: raise ValueError(f"{year}-{month} 最大天数为 {max_day}")
6. 时间差计算忽略负数(如过去时间减未来时间)
错误示例
from datetime import datetime
start = datetime(2023, 10, 5)
end = datetime(2023, 10, 1)
delta = end - start # 结果为负时间差(timedelta(days=-4))
days = delta.days # 输出 -4(可能导致后续逻辑错误)
原因
- 未处理时间差为负数的情况,导致后续计算错误(如显示“剩余天数-4”)。
纠错方法
取绝对值或明确判断方向:
days = abs(delta.days) # 输出 4
# 或检查方向
if delta.days < 0:
print("时间已过期")
7. 误用 replace
方法修改时区
错误示例
import pytz
from datetime import datetime
dt_utc = datetime.now(pytz.utc)
dt_shanghai = dt_utc.replace(tzinfo=pytz.timezone("Asia/Shanghai")) # 错误!
# 时区转换错误,时间数值未调整
原因
replace
仅修改时区信息,不转换时间数值(如 UTC+8 时区直接替换为 UTC 时区会错误)。
纠错方法
使用 astimezone
方法正确转换时区:
dt_shanghai = dt_utc.astimezone(pytz.timezone("Asia/Shanghai")) # 正确
8. 字符串解析时未处理毫秒/微秒
错误示例
from datetime import datetime
dt_str = "2023-10-05 14:30:45.123456"
dt = datetime.strptime(dt_str, "%Y-%m-%d %H:%M:%S") # 忽略微秒部分
# 抛出 ValueError: unconverted data remains: .123456
原因
- 格式字符串未包含微秒占位符
%f
。
纠错方法
明确解析微秒:
dt = datetime.strptime(dt_str, "%Y-%m-%d %H:%M:%S.%f") # 正确
9. 时间差计算单位混淆(如 days 与 total_seconds)
错误示例
from datetime import timedelta
delta = timedelta(days=1, hours=3)
total_hours = delta.days * 24 + delta.seconds // 3600 # 错误:结果为 24 + 3 = 27
# 正确方法应使用 total_seconds()
原因
timedelta.seconds
只包含不足1天的秒数(0~86399),days
是整数天数。
纠错方法
统一用 total_seconds()
计算总时间:
total_hours = delta.total_seconds() // 3600 # (86400 + 10800) / 3600 = 27
10. 忽略闰年影响日期计算
错误示例
from datetime import date, timedelta
# 错误:假设每年都是365天
d = date(2020, 2, 28)
next_year = d + timedelta(days=365) # 2021-02-28(正确应为 2021-02-28)
# 但 2020 是闰年,实际应为 366 天
原因
- 闰年(366 天)的存在影响跨年计算。
纠错方法
使用 dateutil.relativedelta
处理跨年:
from dateutil.relativedelta import relativedelta
next_year = d + relativedelta(years=1) # 2021-02-28(自动处理闰年)
小结内容
错误类型 | 关键点 |
---|---|
时区混淆 | 区分 naive/aware 对象,用 astimezone 转换时区 |
格式符误用 | 熟记 strftime /strptime 格式符(如 %Y 、%m 、%d ) |
夏令时和闰年 | 使用 pytz 和 dateutil 处理复杂时间逻辑 |
输入验证 | 始终检查日期有效性(如月份 ≤12、天数 ≤31) |
时间差计算 | 优先用 total_seconds() 替代手动计算 |
避免这些错误的最佳实践:
- 始终明确时区,优先使用 aware 对象。
- 严格验证输入日期,避免越界。
- 使用第三方库(如
pytz
、dateutil
)处理复杂逻辑。 - 编写单元测试覆盖边界条件(如闰年、夏令时)。
四、水平考试
为了测试 “Python datetime 模块” 的学习效果,请自行完成以下测试试卷。试卷共计30道试题,满分100。其中:选择题15题、填空题10题、编程题5题。每题后提供正确答案,供参考使用。
(一)选择题(每题2分,共30分)
-
以下哪个类用于处理“日期+时间”?
A.datetime.date
B.datetime.time
C.datetime.datetime
D.datetime.tzinfo
答案:C -
strftime("%Y-%m-%d")
输出的格式是?
A.05-10-2023
B.2023/10/05
C.2023-10-05
D.10-05-2023
答案:C -
以下代码会抛出什么错误?
from datetime import datetime datetime.strptime("2023-13-01", "%Y-%m-%d")
A.
TypeError
B.ValueError
C.KeyError
D. 无错误
答案:B -
datetime.timedelta
不能表示以下哪个时间单位?
A. 天
B. 小时
C. 分钟
D. 月
答案:D -
如何获取当前时间的 Unix 时间戳?
A.datetime.now().timestamp()
B.datetime.timestamp()
C.datetime.now().time()
D.datetime.utcnow()
答案:A -
以下哪个格式符表示“12小时制的小时”?
A.%H
B.%I
C.%M
D.%p
答案:B -
将
datetime
对象转为时区无关的 UTC 时间,应使用哪个方法?
A.replace(tzinfo=pytz.utc)
B.astimezone(pytz.utc)
C.datetime.utcnow()
D.localize(pytz.utc)
答案:B -
以下代码的输出是?
from datetime import timedelta delta = timedelta(days=2, hours=3) print(delta.total_seconds())
A. 183600
B. 194400
C. 180000
D. 190800
答案:D -
判断闰年的正确方法是?
A. 年份能被4整除
B. 年份能被400整除,或能被4整除但不能被100整除
C. 年份能被100整除
D. 年份能被2整除
答案:B -
以下哪个方法用于解析字符串为
datetime
对象?
A.strftime()
B.fromisoformat()
C.strptime()
D.parse()
答案:C -
以下代码的输出是?
from datetime import datetime dt = datetime(2023, 10, 5, 14, 30) print(dt.weekday()) # 2023-10-05 是星期四
A. 3
B. 4
C. 5
D. 6
答案:A -
datetime.now()
返回的对象是?
A. Naive(无时区)
B. Aware(有时区)
C. 取决于系统设置
D. 总是 UTC 时间
答案:A -
以下代码的功能是?
from datetime import datetime datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
A. 生成 ISO 8601 格式字符串
B. 生成带时区的时间字符串
C. 生成 Unix 时间戳
D. 解析时间字符串
答案:A -
计算两个日期相差的工作日天数,需要用到哪个模块?
A.time
B.calendar
C.pytz
D.dateutil
答案:B 或 D(两种方法均可) -
以下代码会抛出什么错误?
from datetime import datetime dt = datetime(2023, 2, 29)
A.
TypeError
B.ValueError
C.KeyError
D. 无错误
答案:B
(二)填空题(每题3分,共30分)
-
获取当前日期和时间的代码是:
datetime._________()
。
答案:now -
表示时间间隔的类是
_________
。
答案:timedelta -
将字符串
"2023-10-05"
解析为date
对象的代码是:date._________("2023-10-05", "%Y-%m-%d")
。
答案:strptime -
计算
2023-02-28
加1天的结果是_________
。
答案:2023-03-01 -
判断
2024
年是否为闰年的代码:datetime(2024, 2, 29)._________()
。
答案:无(直接创建成功即为闰年) -
将
datetime
对象转换为 ISO 8601 字符串的方法是_________
。
答案:isoformat() -
获取某个月最后一天的代码需要用到
_________
模块的monthrange
函数。
答案:calendar -
创建一个表示“3小时30分钟”的
timedelta
对象:timedelta(hours=3, minutes=30)
或timedelta(seconds=_________ )
。
答案:12600 -
将 UTC 时间转换为北京时间(东八区)的方法是
astimezone(_________)
。
**答案:pytz.timezone(“Asia/Shanghai”)` -
计算
datetime1
和datetime2
之间相差的总秒数的代码是:(datetime2 - datetime1)._________
。
答案:total_seconds()
(三)编程题(每题8分,共40分)
-
编写函数,计算某人的出生天数。
from datetime import date def days_since_birth(birth_year, birth_month, birth_day): today = date.today() birth_date = date(birth_year, birth_month, birth_day) delta = today - birth_date return delta.days print(days_since_birth(2000, 1, 1))
-
编写代码,生成2023年12月的所有日期列表。
from datetime import datetime, timedelta start_date = datetime(2023, 12, 1) dates = [] for i in range(31): current_date = start_date + timedelta(days=i) if current_date.month != 12: break dates.append(current_date.strftime("%Y-%m-%d")) print(dates)
-
将字符串
"2023-10-05 14:30:00+08:00"
转换为纽约时间(UTC-5)。import pytz from datetime import datetime dt_str = "2023-10-05 14:30:00+08:00" dt = datetime.fromisoformat(dt_str) ny_tz = pytz.timezone("America/New_York") dt_ny = dt.astimezone(ny_tz) print(dt_ny.strftime("%Y-%m-%d %H:%M:%S"))
-
编写函数,判断两个日期是否在同一周(假设周一到周日为一周)。
from datetime import datetime def is_same_week(date1, date2): week1 = date1.isocalendar()[1] week2 = date2.isocalendar()[1] return week1 == week2 and date1.year == date2.year d1 = datetime(2023, 10, 2) # 周一 d2 = datetime(2023, 10, 6) # 周五 print(is_same_week(d1, d2)) # True
-
编写代码,计算当前时间距离下一个元旦的剩余天数。
from datetime import datetime now = datetime.now() next_year = now.year + 1 next_new_year = datetime(next_year, 1, 1) delta = next_new_year - now print(f"剩余天数:{delta.days} 天"))
五、实战案例
本节内容展示 3 个 Python datetime
模块实战项目,提供了完整代码及详细解释。
项目1:智能工作日倒计时工具
目标:计算当天剩余的有效工作时间(例如 9:00-18:00,排除午休),适用于工作效率管理。
from datetime import datetime, timedelta
def work_time_remaining():
now = datetime.now()
today = now.date()
work_start = datetime(today.year, today.month, today.day, 9, 0) # 9:00 上班
work_end = datetime(today.year, today.month, today.day, 18, 0) # 18:00 下班
lunch_start = datetime(today.year, today.month, today.day, 12, 0) # 12:00 午休
lunch_end = datetime(today.year, today.month, today.day, 13, 30) # 13:30 结束午休
# 判断当前时间段
if now < work_start:
return "还未到工作时间!"
elif now >= work_end:
return "今天的工作时间已结束!"
elif lunch_start <= now < lunch_end:
remaining = (work_end - lunch_end).seconds // 60
return f"午休中,剩余有效工作时间:{remaining} 分钟"
else:
if now < lunch_start:
end = lunch_start
else:
end = work_end
remaining = (end - now).seconds // 60
return f"剩余有效工作时间:{remaining} 分钟"
# 测试案例
print(work_time_remaining())
执行结果示例(假设当前时间为 14:00):
剩余有效工作时间:240 分钟
项目2:生日倒计时与年龄计算
目标:输入生日,自动计算年龄及距离下次生日的天数,支持闰年。
from datetime import date
def birthday_countdown(birth_year, birth_month, birth_day):
today = date.today()
next_birthday = date(today.year, birth_month, birth_day)
# 处理已过生日的情况
if next_birthday < today:
next_birthday = date(today.year + 1, birth_month, birth_day)
# 计算年龄和剩余天数
age = today.year - birth_year - ((today.month, today.day) < (birth_month, birth_day))
days_left = (next_birthday - today).days
return age, days_left
# 测试案例
age, days = birthday_countdown(2000, 2, 29)
print(f"年龄:{age}岁,距离下次生日还有:{days}天(自动处理闰年)")
执行结果示例(假设当前日期为 2023-10-05):
年龄:23岁,距离下次生日还有:147天(自动处理闰年)
项目3:考勤异常检测系统
目标:分析员工打卡记录,标记迟到(晚于9:15)、早退(早于18:00)和缺卡。
from datetime import datetime, time
def check_attendance(records: dict):
# 定义考勤标准时间
late_time = time(9, 15)
early_leave_time = time(18, 0)
result = {}
for emp_id, times in records.items():
status = []
# 检查上午打卡
if 'am' not in times:
status.append("缺上午卡")
else:
am_time = datetime.strptime(times['am'], "%H:%M").time()
if am_time > late_time:
status.append(f"迟到 {am_time.strftime('%H:%M')}")
# 检查下午打卡
if 'pm' not in times:
status.append("缺下午卡")
else:
pm_time = datetime.strptime(times['pm'], "%H:%M").time()
if pm_time < early_leave_time:
status.append(f"早退 {pm_time.strftime('%H:%M')}")
result[emp_id] = "正常" if not status else " | ".join(status)
return result
# 测试数据
records = {
"001": {"am": "09:16", "pm": "17:59"},
"002": {"am": "08:30", "pm": "18:30"},
"003": {"am": "09:00"}
}
print(check_attendance(records))
执行结果:
{
'001': '迟到 09:16 | 早退 17:59',
'002': '正常',
'003': '缺下午卡'
}