You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何计算扣除周末后的工作日有效时长TIME_SPENT_WORKING_DAYS

计算扣除周末的工作日有效时长(TIME_SPENT_WORKING_DAYS)

嘿,我来帮你搞定这个需求!先把你提供的示例数据整理成清晰的表格,方便咱们参考:

IDSTART_TIME_END_TIME_TIME_DIFFTIME_SPENT_WORKING_DAYS
12022-04-18 09:58:38.9062022-04-18 12:50:27.2041030829810308298(当天是周一,无周末扣除)
22022-04-18 21:26:25.6712022-04-18 21:26:36.3131064210642
32022-04-18 21:27:12.3882022-04-18 21:27:27.2271483914839
42022-04-19 09:57:40.4532022-04-19 09:59:07.6128715987159

核心逻辑拆解

要算出扣除周六/周日的有效时长,核心思路很简单:总时长(也就是你已经算出的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

火山引擎 最新活动