MYSQL 添加工作日到现在

MYSQL Add working days to date

我想给提供的日期加上 5 天,但计算必须跳过周末。

我已经知道如何在不跳过周末的情况下增加 5 天:

SELECT DATE_ADD(`date_field`, INTERVAL 5 DAY) As FinalDate
FROM `table_name`;

现在我希望返回值跳过周末。

目前如果 date_field = 2016-07-22 结果将是 2016-07-27
但我希望结果是 2016-07-29

试试这个:

SELECT DATE_ADD(
    date_field,
    INTERVAL 5 + 
    IF(
        (WEEK(date_field) <> WEEK(DATE_ADD(date_field, INTERVAL 5 DAY)))
        OR (WEEKDAY(DATE_ADD(date_field, INTERVAL 5 DAY)) IN (5, 6)),
        2,
        0)
    DAY
    ) AS FinalDate
FROM `table_name`;

工作原理:

  • 首先,它会在你的日期上增加 5 天。
  • 其次,当date_field和5天后在两个不同的星期内时,必须额外增加2天。
  • 第三,当5天后是SatSun时,必须额外增加2天。

试试这个,应该很好用,基本上循环遍历每一天并检查它们是星期六还是星期日,忽略它们。

https://social.technet.microsoft.com/wiki/contents/articles/30877.t-sql-extending-dateadd-function-to-skip-weekend-days.aspx

我确实尝试过您的解决方案,但在较长时间间隔(例如 20 天)使用它时遇到问题。不过,它在很小的间隔内就可以完美地工作。

示例:对于“2017-10-04”+ 20 天,您的算法 return“2017-10-26”。它应该是“2017-11-01”,因为我们跳过了 4 个周末。

您添加的天数不是根据 2 周 # 之间的差异计算的,因此您可以添加的最大天数是 2,在我的情况下,它应该是 8 (4x2)。

我把你的代码修改成这样(我也加了变量,修改起来方便多了)

SELECT 
@ID:='2017-10-04' as initial_date, -- the initial date in the right format to manipulate (add x day)
@DTA:=20 as days_to_add, -- number of days to add
@DA:= DATE_ADD(@ID, INTERVAL @DTA DAY) as date_add,
@LASTDAY := WEEKDAY(@DA) as last_day, -- the day (Monday, Tuesday...) corresponding to the initial date + number of days to add
@WEEK1 := DATE_FORMAT(@ID, '%v') as initial_date_week, -- format the initial date to match week mode 3 (Monday 1-53)
@WEEK2 := DATE_FORMAT(@DA, '%v') as added_date_week_nbr, -- the week # of the initial_date + number of days to add
@WEEKDIFF := @WEEK2 - @WEEK1 as week_difference, -- the difference between week 2 and week 1
DATE_ADD(@ID,
        INTERVAL @DTA + 
            if ( @WEEKDIFF > 0 or @LASTDAY in (5,6),
              2,
              0
              ) + 
             if (@WEEKDIFF > 1,
             @WEEKDIFF*2,
             0
             ) DAY
    ) AS FinalDate

我获取周数的方式似乎很奇怪,但这是因为我 运行 在法国,而且我的数据库似乎以一种方式配置,即周自然地从星期日开始,“% v" 代表 'mode 3' 周,您可以在此处查看 MySQL 文档以获取更多详细信息:https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html (ctrl + F > '%v')

我还没有实施 public 假期,但我正在考虑在计算中每次添加 X 天,因为这一天中的一天在我们正在查看的时间段内。

根据我的(少数)测试,这应该有效。如果没有请告诉我

WHERE datefield BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL 7 DAY
AND WEEKDAY(datefield) NOT IN (5,6);

加上 hollydays 1 或 2

select GREATEST(WEEKDAY(NOW()) - 4, 0) 'hollydays'

我的解决方案是创建一个 returns 计算日期的函数,它将考虑连续的周末:

DELIMITER $$
CREATE FUNCTION `add_working_days_to_current_month`(ndays INT) RETURNS DATE
NO SQL 
BEGIN

    declare finalDate, startDate, originalFinalDate DATE;
    declare weekNumberStartDate, weekNumberEndDate, weekDiff INT;
    
    set startDate = DATE(CONCAT(YEAR(DATE_SUB(current_date(), INTERVAL 1 MONTH)),"-",MONTH(DATE_SUB(current_date(), INTERVAL 1 MONTH)),"-",DAY(LAST_DAY(DATE_SUB(current_date(), INTERVAL 1 MONTH)))));
    set weekNumberStartDate = WEEK(startDate);
    set finalDate = DATE_ADD(startDate, INTERVAL ndays DAY);
    set originalFinalDate = finalDate;
    set weekNumberEndDate = WEEK(finalDate);
    
    IF(weekNumberEndDate != weekNumberStartDate) THEN
        set weekDiff = (weekNumberEndDate - weekNumberStartDate) * 2;
        set finalDate = DATE_ADD(finalDate, INTERVAL weekDiff DAY);
    END IF;
    
    set weekNumberStartDate = WEEK(originalFinalDate);
    set weekNumberEndDate = WEEK(finalDate);
    IF(weekNumberEndDate != weekNumberStartDate) THEN
        set weekDiff = (weekNumberEndDate - weekNumberStartDate) * 2;
        set finalDate = DATE_ADD(finalDate, INTERVAL weekDiff DAY);
    END IF;
    
    IF(WEEKDAY(finalDate) IN (5, 6)) THEN
        set finalDate = DATE_ADD(finalDate, INTERVAL 2 DAY);
    END IF;
    
    
return finalDate;
END$$
DELIMITER ;

基本上我使用的逻辑与已接受的答案相同,但累积了周末。因此,对于每个周末,我将添加 2 天,最后,如果结果日期是在周末,我将再添加 2 天

这可以通过 recursive CTE:

轻松完成任意天数
WITH RECURSIVE a AS (
    SELECT
        CURRENT_DATE date,  -- Start date
        0 days
    UNION
    SELECT
        -- Always increment the date
        a.date + INTERVAL 1 DAY AS date,
        -- Increment the work day count only if it's not a weekend day
        a.days + (WEEKDAY(a.date + INTERVAL 1 DAY) < 5) AS days
    FROM a
    WHERE
        -- Keep going until the week day count reaches 10
        a.days < 10  -- Amount of days to add
)
SELECT MAX(date)
FROM a

在示例情况下,您将使用子查询:

SELECT
    (
        WITH RECURSIVE a AS (
            SELECT
                date_field date,
                0 days
            UNION
            SELECT
                a.date + INTERVAL 1 DAY AS date,
                a.days + (WEEKDAY(a.date + INTERVAL 1 DAY) < 5) AS days
            FROM a
            WHERE a.days < 5
        )
        SELECT MAX(date)
        FROM a
    ) AS final_date
FROM table_name