很多统计/考核场景会遇到这种需求:一天里上班不是连续的,比如上午一段、下午一段。我们希望输入这些"上班时间段",自动算出当天总工作时长(单位:小时)。
比如某单位作息:
上午:08:30--12:00
下午:14:30--18:00
那么当天工作时长应该是:3.5 + 3.5 = 7.0 小时。
下面用 Python 标准库 datetime 来实现,优点是:严谨、可扩展、不会因为手算出错。
1.思路说明(为什么不用 time 直接相减?)
我们在代码里会用到 datetime、date、time:
time(8,30):只表示"08:30",没有日期
date(2000,1,1):只表示"2000-01-01",没有时分秒
datetime:日期 + 时间,比如 "2000-01-01 08:30:00"
关键点:time 不能直接相减,例如:
time(12, 0) - time(8, 30) # ❌ 不允许
因为它们没有日期,跨天怎么处理并不明确。
解决办法是:给 time 搭配一个固定的日期(随便哪天都行,只要不跨午夜),用 datetime.combine() 拼成 datetime,然后就可以相减得到时间差了。
2代码实现
python
from datetime import datetime, date, time
## ① 定义上班时间段(可以有多段)
工作时段列表 = [
(time(8, 30), time(12, 0)),
(time(14, 30), time(18, 0)),
]
def 计算单日工作小时(时段列表):
"""
输入:时段列表,例如 [(08:30, 12:00), (14:30, 18:00)]
输出:当天工作总时长(小时,float)
"""
base_day = date(2000, 1, 1) # 随便选一天作为基准(占位用)
total = 0.0
# ② 逐个时间段计算时长并累加
for start_t, end_t in 时段列表:
# 把 time 拼到同一天上,得到 datetime(这样才能做减法)
start_dt = datetime.combine(base_day, start_t)
end_dt = datetime.combine(base_day, end_t)
# ③ 做个保护:如果结束时间 <= 开始时间,说明这个时间段写错了
if end_dt <= start_dt:
raise ValueError(f"时间段有问题:{start_t} ~ {end_t},结束时间必须晚于开始时间")
# ④ datetime 相减得到 timedelta,再转成小时
hours = (end_dt - start_dt).total_seconds() / 3600
total += hours
return total
# ⑤ 计算并输出结果
单个工作日小时数 = 计算单日工作小时(工作时段列表)
print(单个工作日小时数) # 7.0
3. 逐行解释
(1)工作时段列表是什么?
python
工作时段列表 = [
(time(8, 30), time(12, 0)),
(time(14, 30), time(18, 0)),
]
这是一个列表,里面有多个"时间段"。每个时间段用 (开始时间, 结束时间) 表示。
你可以随时增加第三段、第四段,比如晚上加班:
工作时段列表 = [
(time(8, 30), time(12, 0)),
(time(14, 30), time(18, 0)),
(time(19, 0), time(21, 0)),
]
函数不需要改,照样能算。
(2)为什么要 datetime.combine(base_day, start_t)?
start_t 只是一个 time,不能相减。
我们用 combine 把它拼到同一天 base_day 上:
08:30 变成 2000-01-01 08:30:00
12:00 变成 2000-01-01 12:00:00
这样就能:
end_dt - start_dt
得到时间差。
(3)total_seconds()/3600 为啥这么写?
end_dt - start_dt 得到的是 timedelta(时间差对象),它里面存的是"多少天、多少秒"等信息。
.total_seconds() 得到总秒数
除以 3600 把"秒"转成"小时"
举个例子:
08:30--12:00 是 3.5 小时
3.5 * 3600 = 12600 秒
所以 total_seconds()/3600 = 3.5
- 输出结果验证
用你这个作息:
上午:08:30--12:00 = 3.5 小时
下午:14:30--18:00 = 3.5 小时
合计 = 7.0 小时
所以输出:
7.0
5. 常见坑提醒
时间段写反了(例如 18:00--14:30),代码会直接报错提醒你。
跨天时段(例如 22:00--02:00)这段代码不支持;如果真有夜班跨天,需要另外处理(可以把它拆成两段:22:00--24:00 + 00:00--02:00)。
午休不算工作时间:我们通过把上午、下午分成两段自然解决了。