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天后是
Sat
或Sun
时,必须额外增加2天。
试试这个,应该很好用,基本上循环遍历每一天并检查它们是星期六还是星期日,忽略它们。
我确实尝试过您的解决方案,但在较长时间间隔(例如 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
我想给提供的日期加上 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天后是
Sat
或Sun
时,必须额外增加2天。
试试这个,应该很好用,基本上循环遍历每一天并检查它们是星期六还是星期日,忽略它们。
我确实尝试过您的解决方案,但在较长时间间隔(例如 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