Подсчет дней между двумя датами, исключая выходные (только MySQL) - PullRequest
3 голосов
/ 18 марта 2012

Мне нужно рассчитать разницу (в днях) между двумя датами в MySQL, исключая выходные (суббота и воскресенье).То есть разница в днях минус число субботы и воскресенья между ними.

В данный момент я просто считаю дни, используя:

SELECT DATEDIFF('2012-03-18', '2012-03-01')

Это возвращение 17, ноЯ хочу исключить выходные, поэтому я хочу 12 (потому что 3-й и 4-й, 10-й и 11-й и 17-й - выходные дни).

Я не знаю, с чего начать.Я знаю о функции WEEKDAY() и всех связанных с ней, но я не знаю, как использовать их в этом контексте.

Ответы [ 5 ]

8 голосов
/ 13 октября 2014

Просто попробуйте, используя простую функцию:

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 |
4 голосов
/ 18 марта 2012

Иллюстрация:

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 )

Псевдокод:

@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
1 голос
/ 09 декабря 2014

Это полезно для вас

В приведенной ниже логике показано только сколько дней, например

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;

Запрос на основе таблицы

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` ) 
1 голос
/ 07 мая 2014
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
0 голосов
/ 18 августа 2015

Вы также можете сделать это с помощью запросов, но вам понадобится таблица дат, которая охватывает диапазоны дат. В любом случае, рекомендуется создавать таблицы дат для использования во всех ваших проектах.

Чтобы создать таблицу дат, все, что вам нужно сделать, это создать длинный список дат (EXCEL - удобный метод, но есть другие способы) и импортировать их в таблицу. Затем используйте эти даты в сочетании с различными функциями даты, чтобы получить «день недели», «месяц», «год» и т. Д. И сохранить все это в таблице с датами, например:

tbl_dates

dates table

Доу - это «день недели» в моей таблице. Тогда ваш запрос выглядит так:

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

В этом случае 1 и 7 - воскресенье, суббота соответственно (что является значением по умолчанию), и, конечно, вы можете вложить это в другой запрос, если вам нужно вычислить это для многих startDate (s) и endDate (s) ).

...