百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程文章 > 正文

mysql 工作时工作日函数 计算两个时间间隔分钟数

qiyuwang 2025-03-11 20:54 6 浏览 0 评论

前言

最近小编在项目中遇到需要查询某个工单还有多少剩余处理时间的需求,并且要按照工作时的计算方式,对剩余处理时间按升序排列,如果是对查询出来的工单进行剩余时间计算,那么在程序中就能够完成,但偏偏要求需要进行排序,这可就难了,因为数据表内记录超过百万,放在程序中处理肯定会溢出,最终还是选择加个mysql函数,让数据库帮忙处理,但找遍各大论坛也没有找到在mysql中计算工作时的方法,无奈只能自己来写个,在这里分享给大家!

不说废话,直接上代码!

说明

这里要说明一下函数中使用的 frame_workingday 这个表,这是一张日历表,记录了哪天是工作日,跟百度搜索的万年历一样的

表结构

完整代码

drop function if exists getworkminute;
create function getworkminute(starttime datetime, endtime datetime) returns integer
begin
    -- 声明变量 --
    -- 最终结果
    declare interval_minute integer default 0;
    -- 开始时间是否工作日
    declare startiswork integer default 0;
    -- 结束时间是否工作日
    declare endiswork integer default 0;
    -- 开始时间与结束时间之间的工作日天数,包含自身
    declare workdaynum integer default 0;

    -- 定义上午、下午 上下班时间 --
    set @monworkstart = '08:00:00';
    set @monworkend = '12:00:00';
    set @noonworkstart = '14:00:00';
    set @noonworkend = '18:00:00';

    set @startdate = date_format(starttime,'%Y-%m-%d');
    set @enddate = date_format(endtime,'%Y-%m-%d');
    set @timestart = date_format(starttime, '%H:%i:%s');
    set @timeend = date_format(endtime, '%H:%i:%s');

    -- 查询
    select count((@startdate = wdate and isworkingday = 1) or null)
         , count((@enddate = wdate and isworkingday = 1) or null)
         , count(isworkingday = 1 or null)
    into startiswork,endiswork,workdaynum
    from frame_workingday
    where wdate between @startdate and @enddate;

    -- 如果开始和结束时间是同一天,且是工作日
    if @startdate = @enddate and startiswork = 1 and endiswork = 1 then
        set workdaynum = 0;
        -- 开始时间小于上午上班时间
        if @timestart < monworkstart then -- if timeend> @monworkstart and @timeend < monworkend then set interval_minute='interval_minute' timestampdiffminute concatstartdate monworkstart concatstartdate timeend -- elseif timeend>= @monworkend and @timeend <= noonworkstart then set interval_minute='interval_minute' 240 -- elseif timeend>= @noonworkstart and @timeend <= noonworkend then set interval_minute='interval_minute' 240 timestampdiffminute concatstartdate noonworkstart concatstartdate timeend -- elseif timeend>= @noonworkend then
                set interval_minute = interval_minute + 480;
            end if;
        -- 开始时间小于上午下班时间
        elseif @timestart < @monworkend then
            -- 结束时间小于上午下班时间,计算 开始时间与结束时间间隔
            if @timeend < monworkend then set interval_minute='interval_minute' timestampdiffminute starttime concatstartdate timeend -- elseif timeend>= @monworkend and @timeend <= noonworkstart then set interval_minute='interval_minute' timestampdiffminute starttime concatstartdate monworkend -- elseif timeend>= @noonworkstart and @timeend <= noonworkend then set interval_minute='interval_minute' timestampdiffminute starttime concatstartdate monworkend timestampdiffminute concatstartdate noonworkstart concatstartdate timeend -- elseif timeend>= @noonworkend then
                set interval_minute = interval_minute + timestampdiff(minute, starttime, concat(@startdate,' ', @monworkend)) + 240;
            end if;
        -- 开始时间小于下午上班时间,即处于午休时间
        elseif @timestart < @noonworkstart then
            -- 结束时间小于下午上班时间,计算 0
            if @timeend < noonworkstart then set interval_minute='interval_minute' 0 -- elseif timeend>= @noonworkstart and @timeend <= noonworkend then set interval_minute='interval_minute' timestampdiffminute concatstartdate noonworkstart concatstartdate timeend -- elseif timeend>= @noonworkend then
                set interval_minute = interval_minute + 240;
            end if;
        -- 开始时间小于下午下班时间
        elseif @timestart < @noonworkend then
            -- 结束时间小于下午下班时间,计算 开始时间与结束时间间隔
            if @timeend < noonworkend then set interval_minute='interval_minute' timestampdiffminute concatstartdate timestart concatstartdate timeend -- elseif timeend>= @noonworkend then
                set interval_minute = interval_minute + timestampdiff(minute, concat(@startdate,' ',@timestart), concat(@startdate,' ', @noonworkend));
            end if;
        end if;
    else
        -- 不是同一天的情况
        if startiswork = 1 then
            -- 工作日减去1天
            set workdaynum = workdaynum - 1;
            -- 小于上午上班时间,计算 一天
            if @timestart <= @monworkstart then
                set interval_minute = interval_minute + 480;
            -- 处于上午工作时间,计算 开始时间与上午下班时间间隔+半天
            elseif @timestart <= @monworkend then
                set interval_minute = interval_minute + timestampdiff(minute, starttime, concat(@startdate,' ', @monworkend)) + 240;
            -- 处于午休区间,计算 半天
            elseif @timestart <= @noonworkstart then
                set interval_minute = interval_minute + 240;
            -- 处于下午工作时间,计算 开始时间与下午下班时间间隔
            elseif @timestart <= @noonworkend then
                set interval_minute = interval_minute + timestampdiff(minute, starttime, concat(@startdate,' ', @noonworkend));
            end if;
        end if;

        if endiswork = 1 then
            -- 工作日减去1天
            set workdaynum = workdaynum - 1;
            -- 小于上午上班时间,计算 0
            if @timeend <= @monworkstart then
                set interval_minute = interval_minute + 0;
            -- 处于上午工作时间,计算 上午上班时间与结束时间间隔
            elseif @timeend <= @monworkend then
                set interval_minute = interval_minute + timestampdiff(minute, concat(@enddate,' ', @monworkstart), endtime);
            -- 处于午休时间,计算 半天
            elseif @timeend <= @noonworkstart then
                set interval_minute = interval_minute + 240;
            -- 处于下午工作时间,计算 半天+下午上班时间与结束时间间隔
            elseif @timeend <= noonworkend then set interval_minute='interval_minute' 240 timestampdiffminute concatenddate noonworkstart endtime -- elseif timeend> @noonworkend then
                set interval_minute = interval_minute + 480;
            end if;
        end if;
    end if;

    -- 计算得到最终的工作分钟数
    return interval_minute + workdaynum * 480;
end;

效果检查

我们使用4月的日历进行测试,测试结果如下:

性能检查

实测5万5千条记录,耗时1分10秒,当然这是在本机docker上的mysql跑的结果,本机的配置比较低,CPU为i5-8250U,mysql最大内存1G

结束语

函数在数据量少的情况下还是可以使用,多了就会占用宝贵的数据库资源,得不偿失,如果大家有更好的办法,欢迎留言讨论!

相关推荐

PayPal严重漏洞可通过不安全的JAVA反序列化对象

在2015年12月,我在PayPal商业网站(manager.paypal.com)中发现了一个严重的漏洞,这个漏洞的存在,使得我可以通过不安全的JAVA反序列化对象,在PayPal的网站服务器上远程...

提醒:Apache Dubbo存在反序列化漏洞

背景:近日监测到ApacheDubbo存在反序列化漏洞(CVE-2019-17564),此漏洞可导致远程代码执行。ApacheDubbo是一款应用广泛的高性能轻量级的JavaRPC分布式服务框架...

【预警通报】关于WebLogicT3存在反序列化高危漏洞的预警通报

近日,我中心技术支撑单位监测到WebLogicT3存在反序列化0day高危漏洞,攻击者可利用T3协议进行反序列化漏洞实现远程代码执行。...

Apache dubbo 反序列化漏洞(CVE-2023-23638)分析及利用探索

在对Apachedubbo的CVE-2023-23638漏洞分析的过程中,通过对师傅们对这个漏洞的学习和整理,再结合了一些新学的技巧运用,从而把这个漏洞的利用向前推了一步。整个过程中的研究思路以及...

案例|WebLogic反序列化漏洞攻击分析

目前网络攻击种类越来越多,黑客的攻击手段也变得层出不穷,常规的防护手段通常是对特征进行识别,一旦黑客进行绕过等操作,安全设备很难发现及防御。通过科来网络回溯分析系统可以全景还原各类异常网络行为,记录所...

【预警通报】关于ApacheOFBizRMI反序列化远程代码 执行高危漏洞的预警通报

近日,我中心技术支撑单位监测发现ApacheOFBiz官方发布安全更新,修复了一处远程代码执行漏洞。成功利用该漏洞的攻击者可造成任意代码执行,控制服务器。该漏洞编号:CVE-2021-26295,安...

关于OracleWebLogic wls9-async组件存在反序列化远程命令执行高危漏洞的预警通报

近日,国家信息安全漏洞共享平台(CNVD)公布了OracleWebLogicwls9-async反序列化远程命令执行漏洞。攻击者利用该漏洞,可在未授权的情况下远程执行命令。该漏洞安全级别为“高危”。现...

Rust语言从入门到精通系列 - Serde序列化/反序列化模块入门指北

Serde是一个用于序列化和反序列化Rust数据结构的库。它支持JSON、BSON、YAML等多种格式,并且可以自定义序列化和反序列化方式。Serde的特点是代码简洁、易于使用、性能高效。...

Java反序列化漏洞详解(java反序列化漏洞利用)

Java反序列化漏洞从爆出到现在快2个月了,已有白帽子实现了jenkins,weblogic,jboss等的代码执行利用工具。本文对于Java反序列化的漏洞简述后,并对于Java反序列化的Poc进行详...

关于Oracle WebLogic Server存在反序列化远程代码执行漏洞的安全公告

安全公告编号:CNTA-2018-00222018年7月18日,国家信息安全漏洞共享平台(CNVD)收录了OracleWebLogicServer反序列化远程代码执行漏洞(CNVD-2018-13...

CVE-2020-9484 Apache Tomcat反序列化漏洞浅析

本文是i春秋论坛作家「Ybwh」表哥原创的一篇技术文章,浅析CVE-2020-9484ApacheTomcat反序列化漏洞。01漏洞概述这次是因为错误配置和org.apache.catalina....

告别脚本小子系列丨JAVA安全(8)——反序列化利用链(下)

0x01前言...

关于WebLogic反序列化高危漏洞的紧急预警通报

近日,WebLogic官方发布WebLogic反序列化漏洞的紧急预警通告,利用该漏洞可造成远程代码执行并直接控制Weblogic服务器,危害极大。该漏洞编号为:CVE-2019-2890,安全级别为“...

高危!Fastjson反序列化漏洞风险通告

漏洞描述...

学习Vulhub的Java RMI Registry 反序列化漏洞

这个实验,我们先通过dnslog演示命令执行,然后通过反弹shell获得root权限。JavaRemoteMethodInvocation用于在Java中进行远程调用。RMI存在远程bind的...

取消回复欢迎 发表评论: