Count days between two dates, excluding weekends (MySQL only)

…衆ロ難τιáo~ 提交于 2019-11-26 23:06:26
biziclop

Illustration:

mtwtfSSmtwtfSS
  123456712345   one week plus 5 days, you can remove whole weeks safely
  12345-------   you can analyze partial week's days at start date
  -------12345   or at ( end date - partial days )

Pseudocode:

@S          = start date
@E          = end date, not inclusive
@full_weeks = floor( ( @E-@S ) / 7)
@days       = (@E-@S) - @full_weeks*7   OR (@E-@S) % 7

SELECT
  @full_weeks*5 -- not saturday+sunday
 +IF( @days >= 1 AND weekday( S+0 )<=4, 1, 0 )
 +IF( @days >= 2 AND weekday( S+1 )<=4, 1, 0 )
 +IF( @days >= 3 AND weekday( S+2 )<=4, 1, 0 )
 +IF( @days >= 4 AND weekday( S+3 )<=4, 1, 0 )
 +IF( @days >= 5 AND weekday( S+4 )<=4, 1, 0 )
 +IF( @days >= 6 AND weekday( S+5 )<=4, 1, 0 )
 -- days always less than 7 days

Simply try it using a simple function :

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);

Test :

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

Result :

| WEEKDAYS1 | WEEKDAYS2 |
-------------------------
|        13 |        13 |
Below function will give you the Weekdays, Weekends, Date difference with proper results:

You can call the below function like,
select getWorkingday('2014-04-01','2014-05-05','day_diffs');
select getWorkingday('2014-04-01','2014-05-05','work_days');
select getWorkingday('2014-04-01','2014-05-05','weekend_days');




    DROP FUNCTION IF EXISTS PREPROCESSOR.getWorkingday;
    CREATE FUNCTION PREPROCESSOR.`getWorkingday`(d1 datetime,d2 datetime, retType varchar(20)) RETURNS varchar(255) CHARSET utf8
    BEGIN
     DECLARE dow1, dow2,daydiff,workdays, weekenddays, retdays,hourdiff INT;
        declare newstrt_dt datetime;
       SELECT dd.iDiff, dd.iDiff - dd.iWeekEndDays AS iWorkDays, dd.iWeekEndDays into daydiff, workdays, weekenddays
      FROM (
       SELECT
         dd.iDiff,
         ((dd.iWeeks * 2) + 
          IF(dd.iSatDiff >= 0 AND dd.iSatDiff < dd.iDays, 1, 0) + 
          IF (dd.iSunDiff >= 0 AND dd.iSunDiff < dd.iDays, 1, 0)) AS iWeekEndDays
           FROM (
          SELECT  dd.iDiff, FLOOR(dd.iDiff / 7) AS iWeeks, dd.iDiff % 7 iDays, 5 - dd.iStartDay AS iSatDiff,  6 - dd.iStartDay AS iSunDiff
         FROM (
          SELECT
            1 + DATEDIFF(d2, d1) AS iDiff,
            WEEKDAY(d1) AS iStartDay
          ) AS dd
        ) AS dd
      ) AS dd ;
      if(retType = 'day_diffs') then
      set retdays = daydiff; 
     elseif(retType = 'work_days') then
      set retdays = workdays; 
     elseif(retType = 'weekend_days') then  
      set retdays = weekenddays; 
     end if; 
        RETURN retdays; 
        END;


Thank You.
Vinod Cyriac.
Bangalore

IT my helpful to you

The bellow logic only show the how many days like

sun   mon

1      2 .....................

DELIMITER $$
DROP FUNCTION IF EXISTS `xx`.`get_weekday` $$
CREATE FUNCTION `xx`.`get_weekday` (first_date date, last_date date, curr_week_day int) RETURNS INT
BEGIN
DECLARE days_tot int;
DECLARE whole_weeks int;
DECLARE first_day int;
DECLARE last_day int;
SET whole_weeks = FLOOR(DATEDIFF(last_date,first_date)/7) ;
SET first_day = WEEKDAY(first_date) ;
SET last_day = WEEKDAY(last_date)  ;
IF curr_week_day  BETWEEN first_day AND  last_day
           AND  last_day > first_day
           OR ( curr_week_day BETWEEN last_day AND first_day
           AND  last_day <  first_day  )
THEN SET days_tot = whole_weeks + 1;
ELSE SET days_tot = whole_weeks ;
END IF;
RETURN  days_tot;
END $$
DELIMITER ;

    SELECT
      `xx`.`get_weekday` ('2009-01-01', '2009-07-20', 0) as mo,
      `xx`.`get_weekday` ('2009-01-01', '2009-07-20', 1) as tu,
      `xx`.`get_weekday` ('2009-01-01', '2009-07-20', 2) as we,
      `xx`.`get_weekday` ('2009-01-01', '2009-07-20', 3) as th,
      `xx`.`get_weekday` ('2009-01-01', '2009-07-20', 4) as fr,
      `xx`.`get_weekday` ('2009-01-01', '2009-07-20', 5) as sa,
      `xx`.`get_weekday` ('2009-01-01', '2009-07-20', 6) as su;

Table based query

ip:

Weekday count
2        10
3         5


SELECT WEEKDAY( `req_date_time` ) AS weekday, COUNT( id ) AS id
FROM `ddd`
WHERE (
`req_date_time` >= '2014-12-01'
AND `req_date_time` <= '2014-12-31'
)
AND WEEKDAY( `req_date_time` ) != '1'
GROUP BY WEEKDAY( `req_date_time` ) 

You can also do this with Queries, but you will need a dates table that covers the date ranges. It's good practice to create a dates tables for use in all your projects, anyways.

To create the dates table, all you do is generate a long list of dates (EXCEL is convenient method, but there are other ways) and import them into a table. Then, use those dates in conjunction with various date functions to derive the 'day of week', 'month', 'year', etc, and save all that into the table with the dates, like so:

tbl_dates

dow is 'day of week' in my table. Then your query looks like this:

SELECT Count(theDate) AS numWeekDays
FROM tbl_dates
WHERE theDate >[startDate] And theDate <=[endDate] AND dow <> 1 AND dow <> 7;

In this case, 1 and 7 are Sunday, Saturday, respectively (which is the default) and, of course, you can nest that into another query if you need to calculate this for many startDate(s) and endDate(s).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!