【问题标题】:Calculate difference between 2 dates in SQL, excluding weekend days计算 SQL 中 2 个日期之间的差异,不包括周末
【发布时间】:2011-11-30 19:44:39
【问题描述】:

我想构建一个 SQL 查询来计算两个日期之间的差异,而不计算结果中的周末天数。

有没有办法格式化日期以获得这个结果?以 Oracle 数据库为例:

select sysdate - creation_dttm from the_table

【问题讨论】:

  • 我找到了另一种计算差异的方法:select sysdate - creation_dttm - 2 * (to_char(sysdate, 'WW') - to_char(creation_dttm, 'WW')) from the_table
  • 是的,当sysdatecreation_dttm 都没有返回周末日期时,它可能会起作用。
  • 你说得对,这是我没有提到的约束。

标签: sql date


【解决方案1】:

你应该尝试一个函数:

CREATE FUNCTION TOTAL_WEEKDAYS(date1 DATE, date2 DATE)
RETURNS INT
RETURN ABS(DATEDIFF(date2, date1)) + 1
     - ABS(DATEDIFF(ADDDATE(date2, INTERVAL 1 - DAYOFWEEK(date2) DAY),
                    ADDDATE(date1, INTERVAL 1 - DAYOFWEEK(date1) DAY))) / 7 * 2
     - (DAYOFWEEK(IF(date1 < date2, date1, date2)) = 1)
     - (DAYOFWEEK(IF(date1 > date2, date1, date2)) = 7);

测试:

SELECT TOTAL_WEEKDAYS('2013-08-03', '2013-08-21') weekdays1,
       TOTAL_WEEKDAYS('2013-08-21', '2013-08-03') weekdays2;

结果:

| WEEKDAYS1 | WEEKDAYS2 |
-------------------------
|        13 |        13 |

【讨论】:

    【解决方案2】:

    我找到了另一种计算差异的方法,只使用 SQL:

    select sysdate - creation_dttm
    - 2 * (to_char(sysdate, 'WW') - to_char(creation_dttm, 'WW'))
    from the_table

    【讨论】:

    • 其实to_char不仅仅是SQL。这是一个 Oracle 函数。
    【解决方案3】:

    我在这个线程上找到了几个不做他们声称的事情的答案。经过一些实验、测试和调整,我有这个贡献。

    declare @firstdate Date
    declare @seconddate Date
    
    set @firstDate = convert(date, '2016-03-07')
    set @seconddate = convert(date, '2016-04-04')
    
    
    select (datediff(dd, @firstDate, @secondDate)) - 
        (( DateDiff(wk, @firstDate, @secondDate) * 2) - 
          case when datepart(dw, @FirstDate) = 7 then 1 else 0 end -
          case when datepart(dw, @secondDate) = 7 then -1 else 0 end)
    

    包括测试工具 - 您可以调整两个日期并运行自己的测试。这假设两个相邻工作日日期之间的差异为 1。如果您所在的国家/地区使用不同的日期来表示周末,那么您将必须相应地设置日期基准,以便您的“星期六”为 7,而您的“星期日”为 1。

    【讨论】:

      【解决方案4】:

      来自previous post

      DECLARE @StartDate DATETIME
      DECLARE @EndDate DATETIME
      SET @StartDate = '2008/10/01'
      SET @EndDate = '2008/10/31'
      
      
      SELECT
         (DATEDIFF(dd, @StartDate, @EndDate) + 1)
        -(DATEDIFF(wk, @StartDate, @EndDate) * 2)
        -(CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END)
        -(CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END)
      

      【讨论】:

        【解决方案5】:

        这是一个例子:
        有四个变量,前两个是不言自明的,只需输入YYYYMMDD格式的日期,第三个是设置给定一周的正常工作日数,所以如果一个站点每周工作6天,设置它到 6,每周 5 天输入 5,以此类推。最后, 当针对 Oracle 运行时,DATE_SEQ_NORML_FACTOR 应该为 1。这是为了在应用 MOD 7 时将 Julian 日期排成 1 星期一,2 等

        以下是限制: 1. 这个公式假设一周的第一天是星期一。 2. 这个公式假设同一周内的所有天都是连续的。 3. 此公式仅适用于计算中涉及的两个日期在工作日或工作日,例如。当该位置仅在周一至周五有效时,周六的“开始日期”将不起作用。

        SELECT
        
          &&START_DATE_YYYYMMDD "Start Date", --in YYYYMMDD format
        
          &&END_DATE_YYYYMMDD "End Date", --in YYYYMMDD format
        
          &&WK_WORK_DAY_CNT "Week Work Day Count", --Number of work day per week
        
          &&DATE_SEQ_NORML_FACTOR "Normalization Factor", --set to 1 when run in Oracle
        
          CASE
        
          WHEN
        
            FLOOR( TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR / 7 ) =
        
            FLOOR( TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR / 7 )
        
          THEN(
        
            TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) -
        
            TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + 1
        
          )
        
          ELSE(
        
            (
        
              &&WK_WORK_DAY_CNT - MOD( TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR , 7 ) + 1
        
            ) +
        
            MOD( TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR , 7 ) +
        
            (
        
              (
        
                (
        
                  TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) -
        
                  MOD( TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR , 7 )
        
                ) -
        
                (
        
                  TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) +
        
                  (
        
                    7 -
        
                    (
        
                      MOD( TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR , 7 )
        
                    )
        
                  )
        
                )
        
              ) / 7 * &&WK_WORK_DAY_CNT
        
            )
        
          ) END "Week Day Count"
        
        FROM DUAL
        

        【讨论】:

          【解决方案6】:

          我们已将以下逻辑整合到几份报告中,并取得了巨大成功。对不起,我不再记得这个脚本的来源来给他们功劳了。

          DECLARE @range INT;
          
          SET @range = DATEDIFF(DAY, @FirstDate, @SecondDate); 
          SET @NumWorkDays = (
              SELECT  
              @range / 7 * 5 + @range % 7 - ( 
                  SELECT COUNT(*)  
                  FROM ( 
                      SELECT 1 AS d 
                      UNION ALL SELECT 2  
                      UNION ALL SELECT 3  
                      UNION ALL SELECT 4  
                      UNION ALL SELECT 5  
                      UNION ALL SELECT 6  
                      UNION ALL SELECT 7 
                      ) weekdays 
                  WHERE d <= @range % 7  
                  AND DATENAME(WEEKDAY, @SecondDate - d) IN ('Saturday', 'Sunday'))
              );
          

          【讨论】:

            【解决方案7】:

            我更新了@JOpuckman 的函数,以考虑到不同地区并不总是有周六和周日的周末。这是其他人需要全局应用的代码;

            DECLARE @FirstDate DateTime
            DECLARE @SecondDate DateTime
            
            SET @FirstDate = '08-20-2012'
            SET @SecondDate = '08-24-2012'
            
            DECLARE @range INT;
            DECLARE @WeekendDayNameStart VARCHAR(50) 
            DECLARE @WeekendDayNameEnd VARCHAR(50)
            
            SET @WeekendDayNameStart = 'FRIDAY'
            SET @WeekendDayNameEnd = (
                SELECT CASE @WeekendDayNameStart
                    WHEN 'SUNDAY' THEN 'MONDAY'
                    WHEN 'MONDAY' THEN 'TUESDAY'
                    WHEN 'TUESDAY' THEN 'WEDNESDAY'
                    WHEN 'WEDNESDAY' THEN 'THURSDAY'
                    WHEN 'THURSDAY' THEN 'FRIDAY'
                    WHEN 'FRIDAY' THEN 'SATURDAY'
                    WHEN 'SATURDAY' THEN 'SUNDAY'
                END
            )
            
            DECLARE @NumWorkDays INT
            
            SET @range = DATEDIFF(DAY, @FirstDate, @SecondDate); 
            SET @NumWorkDays = (
            SELECT  
            @range / 7 * 5 + @range % 7 - ( 
                SELECT COUNT(*)  
                FROM ( 
                    SELECT 1 AS d 
                    UNION ALL SELECT 2  
                    UNION ALL SELECT 3  
                    UNION ALL SELECT 4  
                    UNION ALL SELECT 5  
                    UNION ALL SELECT 6  
                    UNION ALL SELECT 7 
                    ) weekdays 
                WHERE d <= @range % 7  
                AND DATENAME(WEEKDAY, @SecondDate - d) IN (@WeekendDayNameStart, @WeekendDayNameEnd))
            );
            
            -- Calculate whether the current date is a working day
            DECLARE @CurDateExtra INT
            SET @CurDateExtra = 
            (
                CASE DATENAME(WEEKDAY, @SecondDate)
                WHEN @WeekendDayNameStart THEN 0
                WHEN @WeekendDayNameEnd THEN 0
                ELSE 1
                END
            )
            
            SET @NumWorkDays = @NumWorkDays + @CurDateExtra
            SELECT @NumWorkDays
            

            【讨论】:

              【解决方案8】:
              • 计算两个日期之间的天数差
              • 计算周数和年数的差,减去周数,然后将结果乘以 2 以计算两个日期之间的非工作日数。如果年数不同,则计算 52 * 年差 + 周数。

              ((sysdate - ced.created_dt) + ((((to_char(ced.created_dt,'IW') - ((to_char(sysdate,'YY') - to_char(ced.created_dt,'YY'))* 52)) - to_char(to_char(sysdate,'IW')))) * 2)) duration_in_weekdays

              【讨论】:

                【解决方案9】:

                你可以试试这个:

                SELECT
                    Id,
                    DATEDIFF(d, datefrom, dateto) AS TotDays,
                    DATEDIFF(wk, datefrom, dateto) AS Wkds,
                    DATEDIFF(d, datefrom, dateto) - DATEDIFF(wk, datefrom, dateto) AS Days
                FROM
                    YOURTABLE
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2019-12-03
                  • 1970-01-01
                  • 2021-06-20
                  • 1970-01-01
                  • 2019-04-15
                  • 1970-01-01
                  相关资源
                  最近更新 更多