例如:审批开始时间是2020-02-07 20:09:57,结束时间是2020-02-10 22:30:30,请问审批共耗时多少秒?(扣除所有的法定节假日和周六日)
在mysql中进行测试
数据准备
节假日表数据
DROP TABLE IF EXISTS holiday_table;
CREATE TABLE holiday_table (
DATE_ID date,
DAY_WORK int,
isWork varchar(50)
) ;
插入数据
INSERT INTO holiday_table VALUES ('2018-03-30 00:00:00',1,'工作日');
INSERT INTO holiday_table VALUES ('2018-03-31 00:00:00',2,'放假' );
INSERT INTO holiday_table VALUES ('2018-04-01 00:00:00',2,'放假' );
INSERT INTO holiday_table VALUES ('2018-04-02 00:00:00',1,'工作日');
INSERT INTO holiday_table VALUES ('2018-04-03 00:00:00',1,'工作日');
INSERT INTO holiday_table VALUES ('2018-04-04 00:00:00',1,'工作日');
INSERT INTO holiday_table VALUES ('2018-04-05 00:00:00',2,'放假' );
INSERT INTO holiday_table VALUES ('2018-04-06 00:00:00',2,'放假' );
INSERT INTO holiday_table VALUES ('2018-04-07 00:00:00',2,'放假' );
INSERT INTO holiday_table VALUES ('2018-04-08 00:00:00',1,'工作日');
INSERT INTO holiday_table VALUES ('2018-04-09 00:00:00',1,'工作日');
INSERT INTO holiday_table VALUES ('2018-04-10 00:00:00',1,'工作日');
INSERT INTO holiday_table VALUES ('2018-04-11 00:00:00',1,'工作日');
DATE_ID | DAY_WORK | isWork |
---|---|---|
2018-03-30 00:00:00 | 1 | 工作日 |
2018-03-31 00:00:00 | 2 | 放假 |
2018-04-01 00:00:00 | 2 | 放假 |
2018-04-02 00:00:00 | 1 | 工作日 |
2018-04-03 00:00:00 | 1 | 工作日 |
2018-04-04 00:00:00 | 1 | 工作日 |
2018-04-05 00:00:00 | 2 | 放假 |
2018-04-06 00:00:00 | 2 | 放假 |
2018-04-07 00:00:00 | 2 | 放假 |
2018-04-08 00:00:00 | 1 | 工作日 |
2018-04-09 00:00:00 | 1 | 工作日 |
2018-04-10 00:00:00 | 1 | 工作日 |
审批时间表数据
app_info 表存放审批信息的数据
DROP TABLE IF EXISTS app_info ;
CREATE TABLE app_info (
ID int,
start_date TIMESTAMP,
end_date TIMESTAMP
) ;
插入三条数据
INSERT INTO app_info VALUES (1,'2018-03-30 12:10:00','2018-04-02 17:10:00');
INSERT INTO app_info VALUES (2,'2018-04-02 11:00:05','2018-04-03 10:40:05');
INSERT INTO app_info VALUES (3,'2018-04-03 17:20:00','2018-04-11 11:10:05');
方法1
将日期表中的数据去关联假日表的数据,把非工作日的去除,剩下的条数就是工作日的天数。
1. 关联表取时间
SELECT
A.id,
A.start_date,
A.end_date,
B.DATE_ID AS Interval_date
from app_info A
join holiday_table B
on B.DATE_ID BETWEEN date(A.start_date) AND date(A.end_date)
and B.DAY_WORK=1
id | start_date | end_date | Interval_date |
---|---|---|---|
1 | 2018/3/30 12:10 | 2018/4/2 17:10 | 2018/3/30 |
1 | 2018/3/30 12:10 | 2018/4/2 17:10 | 2018/4/2 |
2 | 2018/4/2 11:00 | 2018/4/3 10:40 | 2018/4/2 |
2 | 2018/4/2 11:00 | 2018/4/3 10:40 | 2018/4/3 |
3 | 2018/4/3 17:20 | 2018/4/11 11:10 | 2018/4/3 |
3 | 2018/4/3 17:20 | 2018/4/11 11:10 | 2018/4/4 |
3 | 2018/4/3 17:20 | 2018/4/11 11:10 | 2018/4/8 |
3 | 2018/4/3 17:20 | 2018/4/11 11:10 | 2018/4/9 |
3 | 2018/4/3 17:20 | 2018/4/11 11:10 | 2018/4/10 |
3 | 2018/4/3 17:20 | 2018/4/11 11:10 | 2018/4/11 |
2. 统计天数
SELECT
A.id,
A.start_date,
A.end_date,
count(1) AS Interval_num
from app_info A
join holiday_table B
on B.DATE_ID BETWEEN date(A.start_date) AND date(A.end_date)
and B.DAY_WORK=1
group by
A.id,
A.start_date,
A.end_date
id | start_date | end_date | Interval_num |
---|---|---|---|
1 | 2018/3/30 12:10 | 2018/4/2 17:10 | 2 |
2 | 2018/4/2 11:00 | 2018/4/3 10:40 | 2 |
3 | 2018/4/3 17:20 | 2018/4/11 11:10 | 5 |
3.时间间隔的时间
所得的相差秒数应为 时间相差的秒数 减去 多算的工作日的天数对应的描述(即天数*24*60*60)
select
id,
start_date,
end_date,
TIMESTAMPDIFF(SECOND,start_date,end_date)-(DATEDIFF(end_date,start_date)+1-Interval_num)*24*60*60 AS Interval_sec
from
(SELECT
A.id,
A.start_date,
A.end_date,
count(1) as Interval_num
from app_info A
join holiday_table B
on B.DATE_ID BETWEEN date(A.start_date) AND date(A.end_date)
and B.DAY_WORK=1
group by
A.id,
A.start_date,
A.end_date) t
最终结果
id | start_date | end_date | Interval_sec |
---|---|---|---|
1 | 2018-03-30 12:10:00 | 2018-04-02 17:10:00 | 104400 |
2 | 2018-04-02 11:00:05 | 2018-04-03 10:40:05 | 85200 |
3 | 2018-04-03 17:20:00 | 2018-04-11 11:10:05 | 409805 |
4. 如果提交审批是休息日
上述代码对于审批日是休息日,计算会有差错
插入例子
INSERT INTO app_info VALUES (4,'2018-04-01 09:20:00','2018-04-02 11:10:05');
INSERT INTO app_info VALUES (5,'2018-04-04 20:20:00','2018-04-05 11:10:05');
id为4不考虑休息日应为 39600+600+5=40205秒,用之前代码的得出的结果为6605秒 结果存在误差
id为5不考虑休息日应为10800+2400=13200秒
对代码进行进一步的处理
SELECT
id,
start_date,
end_date,
TIMESTAMPDIFF(SECOND,start_date_new,end_date_new)-(DATEDIFF(end_date_new,start_date_new)+1-Interval_num_new)*24*60*60 AS Interval_sec
FROM
(SELECT
id,
start_date,
end_date,
case when date(start_date) = first_workday then start_date else date_format(first_workday,'%Y-%m-%d %H:%i:%s') end AS start_date_new ,
case when date(end_date) = last_workday then end_date else date_format(last_workday,'%Y-%m-%d %H:%i:%s') end AS end_date_new,
case when date(end_date) <> last_workday then Interval_num + 1 else Interval_num end AS Interval_num_new
FROM
(SELECT
A.id,
A.start_date,
A.end_date,
count(1) AS Interval_num,
MIN(DATE_ID) AS first_workday,
MAX(DATE_ID) AS last_workday
FROM app_info A
JOIN holiday_table B
ON B.DATE_ID BETWEEN date(A.start_date) AND date(A.end_date)
AND B.DAY_WORK=1
GROUP BY
A.id,
A.start_date,
A.end_date
) t1
) t2
id为4的结果为40205
id | start_date | end_date | Interval_sec |
---|---|---|---|
1 | 2018-03-30 12:10:00 | 2018-04-02 17:10:00 | 104400 |
2 | 2018-04-02 11:00:05 | 2018-04-03 10:40:05 | 85200 |
3 | 2018-04-03 17:20:00 | 2018-04-11 11:10:05 | 409805 |
4 | 2018-04-01 09:20:00 | 2018-04-02 11:10:05 | 40205 |
5 | 2018/4/4 20:20 | 2018/4/5 11:10 | 13200 |
方法2
自定义函数
create function getWorkDay
(
beginday date,
endday date
)
returns int
begin
declare Interval_num int;
SELECT COUNT(1) from holiday_table WHERE DATE_ID BETWEEN beginday AND endday AND DAY_WORK=1 into Interval_num;
return Interval_num;
end;
测试
select getWorkDay('2018-03-30 12:10:00','2018-04-02 17:10:00');
结果为2天,还需将天换算成对应的时分秒再进行其他的转换,暂时未写完此方法。