【问题标题】:How do you exclude weekends from a date_sub?你如何从 date_sub 中排除周末?
【发布时间】:2015-04-16 14:26:13
【问题描述】:

我正在尝试使用 date_sub 减去当前日期 - 11 天。我想排除周末..这是我到目前为止的:

DATE_SUB(now(), INTERVAL 11 day)

不确定如何排除周末...感谢任何帮助。

【问题讨论】:

标签: mysql date


【解决方案1】:

这个问题是关于减去工作日的。假设周末是周六-周日,我们可以写出如下解决方案:

我们知道:

  • 每个整周有 5 个工作日。
  • 因此,
    • num_of_weeks = floor(@num_working_days / 5)
    • delta_days = @num_working_days % 5

所以,第一个近似值可以是:

SET @num_working_days = 4; -- pick any integer
SET @num_days = 7 * FLOOR(@num_working_days / 5) - @num_working_days % 5;     
SELECT DATE_SUB(NOW(), INTERVAL @num_days DAY)

但是,这不适用于以下和类似情况:

如果今天是Mondaynum_working_days % 5 是1,上面将错误地给你Sunday,而它应该给你Friday

一般情况下会失败:

WEEKDAY(NOW()) - @num_working_days % 5 < 0

为此,只要满足此条件,就必须额外减去 2 天。

  • overflow_days = 2 * (WEEKDAY(NOW()) - @num_working_days % 5 &lt; 0)

因此,第二个近似值是:

SET @num_working_days = 4;
SET @overflow_days = 2 * (WEEKDAY(NOW()) - @num_working_days % 5 < 0)
SET @num_days = 7 * FLOOR(@num_working_days / 5) - @num_working_days % 5;

SELECT DATE_SUB(NOW(), INTERVAL @num_days DAY)

最后,

只要now() 不在week-end 天,这将起作用。对于这种情况,您需要将上述公式中的 now() 替换为上一周结束日期:

  • weekend_correction = DATE_SUB(NOW(), INTERVAL WEEKDAY(NOW()) % 5 DAY)

这导致看起来很糟糕但功能齐全:

SET @num_working_days = 4;
SET @weekend_correction = DATE_SUB(NOW(), INTERVAL WEEKDAY(NOW()) % 5 DAY);
SET @overflow_days = 2 * (WEEKDAY(@weekend_correction) - @num_working_days % 5 < 0);
SET @num_days = 7 * FLOOR(@num_working_days / 5) - @num_working_days % 5;

SELECT DATE_SUB(@weekend_correction, INTERVAL @num_days DAY); 

现在,在生产中,我建议你在你的 MySQL 服务器上创建一个函数来封装这个逻辑,你可以在需要减去工作日时调用这个函数。

【讨论】:

    【解决方案2】:
    SET @date = '2015.07.25';
    SET @n =6;
    
    SELECT DATE_SUB(
                  @date,INTERVAL CASE 
                      WHEN DAYOFWEEK(@date)=1 THEN (@n +(FLOOR((@n-0.5)/5)+1)*2 - 1) 
                      WHEN DAYOFWEEK(@date)=2 THEN (@n +(FLOOR((@n-0.5)/5)+1)*2)
                      WHEN DAYOFWEEK(@date)=3 THEN (@n-1 +(FLOOR(((@n-1)-0.5)/5)+1)*2 + 1)
                      WHEN DAYOFWEEK(@date)=4 THEN (@n-2 +(FLOOR(((@n-2)-0.5)/5)+1)*2 + 2)
                      WHEN DAYOFWEEK(@date)=5 THEN (@n-3 +(FLOOR(((@n-3)-0.5)/5)+1)*2 + 3)
                      WHEN DAYOFWEEK(@date)=6 THEN (@n-4 +(FLOOR(((@n-4)-0.5)/5)+1)*2 + 4)
                      WHEN DAYOFWEEK(@date)=7 THEN (@n-5 +(FLOOR(((@n-5)-0.5)/5)+1)*2 + 5) 
                 END DAY
    );
    

    @date 是日期。您可以给出任何日期。

    @n 是您要减去的工作日数。

    这里给出的答案对我不起作用,它有时会返回未来的日期,或者给出的结果是星期天,这不是工作日,所以我做了这个SELECT。 例如,如果给定的日期是星期一,并且您想减去 1 个工作日,它将返回上星期五的日期。在此代码中,非工作日被视为周六和周日。

    它应该适用于任何日期和给定的任何工作日数。

    【讨论】:

      【解决方案3】:

      这是相同的计算方法,只是简化了代码:

      SET @date = '2015.07.25';
      SET @n =6;
      
      SELECT DATE_SUB(
                @date,INTERVAL CASE
                          WHEN DAYOFWEEK(@date)=1 THEN (@n +(FLOOR((@n-0.5)/5)+1)*2 - 1)
                          WHEN DAYOFWEEK(@date)=2 THEN (@n +(FLOOR((@n-0.5)/5)+1)*2)
                          WHEN DAYOFWEEK(@date)>=3 THEN (@n-DAYOFWEEK(@date)-2 +(FLOOR(((@n-DAYOFWEEK(@date)-2)-0.5)/5)+1)*2 + DAYOFWEEK(@date)-2)
                          END DAY
      );
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-17
        • 2017-07-23
        • 2017-01-03
        • 1970-01-01
        • 1970-01-01
        • 2019-04-02
        相关资源
        最近更新 更多