如何计算扣除周末后的工作日有效时长TIME_SPENT_WORKING_DAYS
计算扣除周末的工作日有效时长(TIME_SPENT_WORKING_DAYS)
嘿,我来帮你搞定这个需求!先把你提供的示例数据整理成清晰的表格,方便咱们参考:
| ID | START_TIME_ | END_TIME_ | TIME_DIFF | TIME_SPENT_WORKING_DAYS |
|---|---|---|---|---|
| 1 | 2022-04-18 09:58:38.906 | 2022-04-18 12:50:27.204 | 10308298 | 10308298(当天是周一,无周末扣除) |
| 2 | 2022-04-18 21:26:25.671 | 2022-04-18 21:26:36.313 | 10642 | 10642 |
| 3 | 2022-04-18 21:27:12.388 | 2022-04-18 21:27:27.227 | 14839 | 14839 |
| 4 | 2022-04-19 09:57:40.453 | 2022-04-19 09:59:07.612 | 87159 | 87159 |
核心逻辑拆解
要算出扣除周六/周日的有效时长,核心思路很简单:总时长(也就是你已经算出的TIME_DIFF)减去时间段内覆盖的所有周末时间。这里分两种情况处理最稳妥:
- 如果时间段完全在同一个工作日内,那有效时长就等于TIME_DIFF,毕竟没碰到周末
- 如果时间段跨天甚至包含周末,就得精准算出覆盖的周末时长,再从总时长里扣掉
具体实现方案(覆盖Python和SQL两种常用场景)
1. Python实现(适合脚本/数据处理场景)
我写了一个实用的函数,用datetime库就能搞定,直接拿去用:
from datetime import datetime, timedelta def calculate_working_time(start_str, end_str): # 把字符串转成datetime对象,注意匹配你的时间格式 start = datetime.strptime(start_str, "%Y-%m-%d %H:%M:%S.%f") end = datetime.strptime(end_str, "%Y-%m-%d %H:%M:%S.%f") # 先算总时长(转成毫秒,和你的TIME_DIFF单位一致) total_diff_ms = (end - start).total_seconds() * 1000 # 同一天的情况直接返回,不用折腾 if start.date() == end.date(): return int(total_diff_ms) # 跨天的情况:逐个日期检查是不是周末,统计要扣除的时长 current_date = start.date() weekend_deduct_ms = 0 while current_date <= end.date(): # weekday()返回0=周一,5=周六,6=周日 if current_date.weekday() in (5, 6): if current_date == start.date(): # 当天是周末,只扣从start到当天结束的时间 day_end = datetime.combine(current_date, datetime.max.time()) weekend_deduct_ms += (day_end - start).total_seconds() * 1000 elif current_date == end.date(): # 当天是周末,只扣从当天开始到end的时间 day_start = datetime.combine(current_date, datetime.min.time()) weekend_deduct_ms += (end - day_start).total_seconds() * 1000 else: # 完整的周末日,扣全天24小时的毫秒数(86400*1000) weekend_deduct_ms += 86400000 current_date += timedelta(days=1) # 有效时长=总时长-周末扣除时长 return int(total_diff_ms - weekend_deduct_ms)
给你测试个跨周末的例子:
# 比如从周五20点到周一8点 start = "2022-04-22 20:00:00.000" end = "2022-04-25 08:00:00.000" print(calculate_working_time(start, end)) # 总时长是2天12小时=259200000毫秒,扣除周六周日全天172800000毫秒,剩余86400000毫秒(刚好24小时)
2. SQL实现(适合数据库直接计算)
如果你的数据存在MySQL里,直接用内置函数就能算,不用导出到脚本里折腾:
SELECT ID, START_TIME_, END_TIME_, TIMESTAMPDIFF(MICROSECOND, START_TIME_, END_TIME_) / 1000 AS TIME_DIFF, -- 计算扣除周末后的有效时长(毫秒) TIMESTAMPDIFF(MICROSECOND, START_TIME_, END_TIME_) / 1000 - ( -- 先算时间段内完整周末日的总毫秒数 ( TIMESTAMPDIFF(DAY, START_TIME_, END_TIME_) + 1 -- 总天数 - ( -- 计算工作日天数 DATEDIFF(END_TIME_, START_TIME_) + 1 - FLOOR((DATEDIFF(ADDDATE(START_TIME_, INTERVAL(5 - WEEKDAY(START_TIME_)) DAY), START_TIME_) + 1)/7)*2 - FLOOR((DATEDIFF(END_TIME_, ADDDATE(END_TIME_, INTERVAL(1 - WEEKDAY(END_TIME_)) DAY)) + 1)/7)*2 ) ) * 86400000 -- 调整首尾两天的部分周末时长(如果首尾是周末) - CASE WHEN WEEKDAY(START_TIME_) >=5 THEN TIMESTAMPDIFF(MICROSECOND, START_TIME_, DATE(START_TIME_) + INTERVAL 1 DAY)/1000 ELSE 0 END - CASE WHEN WEEKDAY(END_TIME_) >=5 THEN TIMESTAMPDIFF(MICROSECOND, DATE(END_TIME_), END_TIME_)/1000 ELSE 0 END ) AS TIME_SPENT_WORKING_DAYS FROM your_table_name;
这个SQL的逻辑是:先算出总时长,再减去所有完整周末日的时长,最后调整首尾两天如果是周末的部分时长,确保扣的是精准覆盖的周末时间。
小提醒
- 确保你的时间字段是
datetime类型,别存成字符串,不然解析容易出错 - 如果还要扣除法定节假日,得额外加个节假日列表,在判断的时候一起排除
- 不同语言/数据库的时间差函数返回单位可能不一样,要注意转成毫秒(和你的TIME_DIFF单位对齐)
内容的提问来源于stack exchange,提问作者vik




