我有一个计算两个日期之间工作日的函数。问题是它必须从开始日期后的第二天开始计算。如果开始日期是周末(周六或周日)或周五,则必须从周一开始计算。
目前,此代码会计算在周末开始的日期,但如果开始日期是在工作日,那么它会计算 1天太多因为它还会计算开始日应该从第二天开始。
CREATE DEFINER=`root`@`localhost` FUNCTION `BusinessDaysBetweenDates`(d1 DATE, d2 DATE) RETURNS int(11)
BEGIN
DECLARE bDaysInPeriod INT;
SET bDaysInPeriod=0;
WHILE d1<=d2 DO
IF DAYOFWEEK(d1) BETWEEN 2 AND 6 THEN
SET bDaysInPeriod=bDaysInPeriod+1;
END IF;
SET d1=d1+INTERVAL 1 day;
END WHILE;
RETURN bDaysInPeriod;
END
测试用例:使用开始日期 01-01-2014
和结束日期 03-01-2014
它将生成{{1什么时候它应该产生3 days
。如果您通过简单地从结果中减去1天来修复它,那么2 days
的开始日期和04-01-2014
的结束日期将产生{{1而不是08-01-2014
。
答案 0 :(得分:1)
您解决此问题的方法似乎可行。当您向应用程序添加任意假期表时,它将特别有用。
我相信你的计算中有一个简单的逐个错误。尝试更改逻辑来执行此操作:
SET bDaysInPeriod=0;
SET d1=d1+INTERVAL 1 DAY; /* start counting the day after start date */
WHILE d1<=d2 DO
IF DAYOFWEEK(d1) BETWEEN 2 AND 6 THEN
SET bDaysInPeriod=bDaysInPeriod+1;
END IF;
SET d1=d1+INTERVAL 1 DAY;
END WHILE;
RETURN bDaysInPeriod;
以下是一些潜在的测试用例:
start date end date returned value
Mon Tues 1
Sun Mon 1
Fri Mon 1
Fri Tues 2
Sat Sun 0
Sat Mon 1
Sun Tues 2
我认为这就是你想要的。
答案 1 :(得分:0)
在调用该函数之前,在开始日中添加一天。
如果开始日是星期五,你会得到星期六,这不会被计算在内,因为它不是工作日。如果开始日是星期天,那么你最终会在星期一结束,这将是第一天被计算在内。
或者您可以跳过该功能并在查询中执行此操作。
WITH days AS (
SELECT TRUNC(:start_date) + LEVEL AS my_day
FROM dual
CONNECT BY TRUNC(:start_date) + LEVEL <= TRUNC(:end_date)
)
SELECT COUNT(*) AS workdays
FROM days
WHERE TO_CHAR(my_day, 'D') NOT IN ('1', '7');
您需要排除的天数取决于您要排除的实际天数以及您的NLS设置,确切地说是NLS_TERRITORY
。在这里,我假设您想要排除周末,并设置1 =星期日和7 =星期六。