Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to count date difference excluding weekend and holidays in MySQL

Tags:

I need to count days (business days) between two dates excluding weekend (most important) and holidays

SELECT DATEDIFF(end_date, start_date) from accounts

But, I don't know how am I supposed to do it in MySQL, I found this article Count days between two dates, excluding weekends (MySQL only). I cannot figure out how to functional query in mysql, Can you give some information of how can achieve this with mysql query. If I am missing anything let me know.

[EDIT]

CREATE TABLE `candidatecase` (
  `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Unique ID',
  `CreatedBy` int(11) NOT NULL,
  `UseraccountID` int(11) NOT NULL COMMENT 'User Account ID',
  `ReportReadyID` int(11) DEFAULT NULL COMMENT 'Report Ready ID',
  `DateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Date Created',
  `InitiatedDate` timestamp NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Date Initiated',
  `ActualCompletedDate` timestamp NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Date Completed Case',
  `ProjectedCompletedDate` timestamp NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Date Projected Finish',
  `CheckpackagesID` int(11) DEFAULT NULL COMMENT 'Default Check Package Auto Assign Once Initiate Start',
  `Alacartepackage1` int(11) DEFAULT NULL COMMENT 'Ala carte Request #2',
  `Alacartepackage2` int(11) DEFAULT NULL COMMENT 'Ala carte Request #3',
  `OperatorID` int(11) NOT NULL COMMENT 'User Account - Operator',
  `Status` int(11) NOT NULL COMMENT 'Status',
  `caseRef` varchar(100) NOT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=293 ;

--
-- Dumping data for table `candidatecase`
--

INSERT INTO `candidatecase` (`ID`, `CreatedBy`, `UseraccountID`, `ReportReadyID`, `DateCreated`, `InitiatedDate`, `ActualCompletedDate`, `ProjectedCompletedDate`, `CheckpackagesID`, `Alacartepackage1`, `Alacartepackage2`, `OperatorID`, `Status`, `caseRef`) VALUES
(1, 43, 70, NULL, '2011-07-22 02:29:31', '2011-07-07 07:27:44', '2011-07-22 02:29:31', '2011-07-17 06:53:52', 11, NULL, NULL, 44, 6, ''),
(2, 43, 74, NULL, '2012-04-03 04:17:15', '2011-07-11 07:07:23', '2011-07-13 05:32:58', '2011-07-21 07:01:34', 20, 0, 0, 51, 0, ''),
(3, 43, 75, NULL, '2011-07-29 04:10:07', '2011-07-11 07:27:12', '2011-07-29 04:10:07', '2011-07-21 07:02:14', 20, NULL, NULL, 45, 6, ''),
(4, 43, 78, NULL, '2011-07-18 03:32:27', '2011-07-11 07:51:31', '2011-07-13 02:18:34', '2011-07-21 07:37:53', 20, NULL, NULL, 45, 6, ''),
(5, 43, 76, NULL, '2011-07-29 04:09:19', '2011-07-11 07:51:11', '2011-07-29 04:09:19', '2011-07-21 07:38:30', 20, NULL, NULL, 45, 6, ''),
(6, 43, 77, NULL, '2011-07-18 03:32:49', '2011-07-11 07:51:34', '2011-07-18 02:18:46', '2011-07-21 07:39:00', 20, NULL, NULL, 45, 6, ''),
(7, 43, 79, NULL, '2011-07-18 03:33:02', '2011-07-11 07:53:24', '2011-07-18 01:50:12', '2011-07-21 07:42:57', 20, NULL, NULL, 45, 6, ''),
(8, 43, 80, NULL, '2011-07-29 04:10:38', '2011-07-11 07:53:58', '2011-07-29 04:10:38', '2011-07-21 07:43:14', 20, NULL, NULL, 45, 6, ''),
(9, 43, 81, NULL, '2011-07-18 03:31:54', '2011-07-11 07:53:49', '2011-07-13 02:17:02', '2011-07-21 07:43:43', 20, NULL, NULL, 45, 6, ''),
(11, 43, 88, NULL, '2011-07-18 03:15:53', '2011-07-13 04:57:38', '2011-07-15 08:57:15', '2011-07-23 04:39:14', 12, NULL, NULL, 44, 6, ''),
(13, 43, 90, NULL, '2011-07-26 07:39:24', '2011-07-13 12:16:48', '2011-07-26 07:39:24', '2011-07-23 12:13:50', 15, NULL, NULL, 51, 6, ''),
(63, 43, 176, NULL, '2011-09-13 08:23:13', '2011-08-26 10:00:32', '2011-09-13 08:23:13', '2011-09-05 09:58:47', 41, NULL, NULL, 45, 6, ''),
(62, 43, 174, NULL, '2011-08-24 03:54:30', '2011-08-24 03:53:13', '2011-08-24 03:54:30', '2011-08-29 03:52:48', 17, NULL, NULL, 51, 6, ''),
(61, 43, 173, NULL, '2011-08-24 03:55:05', '2011-08-24 03:53:39', '2011-08-24 03:55:05', '2011-08-29 03:52:36', 17, NULL, NULL, 51, 6, ''),
(60, 43, 172, NULL, '2011-08-24 03:22:41', '2011-08-24 03:21:50', '2011-08-24 03:22:41', '2011-08-29 03:21:11', 17, NULL, NULL, 51, 6, ''),
(59, 43, 171, NULL, '2011-08-24 03:23:19', '2011-08-24 03:22:00', '2011-08-24 03:23:19', '2011-08-29 03:20:57', 17, NULL, NULL, 51, 6, '');
like image 898
Akram Avatar asked Apr 26 '12 09:04

Akram


People also ask

How do you calculate working days in SQL excluding weekends and holidays?

You Can simply use datediff function of sql. and then you can subtract weekends between those dates if any. For example check below query. And If You want to exclude holiday's too, then, You also can calculate holidays between start/end date and can subtract that from final selection.

How do you find the difference between two dates excluding weekends in SQL?

The statement DATEDIFF(dd,@fromdate,@todate) + 1 gives the number of dates between the two dates. The statement DATEDIFF(wk,@fromdate,@todate) gives the number of weeks between dates and * 2 gives us the weekend (Saturday and Sunday) count. The next two statements excludes the day if it's a Saturday or Sunday.


2 Answers

You might want to try this:

  1. Count the number of working days (took it from here)

    SELECT 5 * (DATEDIFF('2012-12-31', '2012-01-01') DIV 7) + MID('0123444401233334012222340111123400012345001234550', 7 * WEEKDAY('2012-01-01') + WEEKDAY('2012-12-31') + 1, 1)

    This gives you 261 working days for 2012.

  2. Now you need to know your holidays that are not on a weekend

    SELECT COUNT(*) FROM holidays WHERE DAYOFWEEK(holiday) < 6

    The result of this depends on your holiday table.

  3. We need to get that in one query:

    SELECT 5 * (DATEDIFF('2012-12-31', '2012-01-01') DIV 7) + MID('0123444401233334012222340111123400012345001234550', 7 * WEEKDAY('2012-01-01') + WEEKDAY('2012-12-31') + 1, 1) - (SELECT COUNT(*) FROM holidays WHERE DAYOFWEEK(holiday) < 6)

    This should be it.

Edit: Please be aware that this only works properly if your end date is higher than your start date.

like image 128
Thorsten Avatar answered Oct 07 '22 11:10

Thorsten


Create a table that contains all the weekends and holidays for the next 100whatever years.

You need to be able to specify when a day is a 'holiday' given that no one knows what the holidays will be for 2052 yet, you will not be able to make an accurate function at this time anyway. just update your non-work day table each year when the holidays become known (but you will always know the weekends).

Then your query becomes:

SELECT DATEFIFF(end_date, start_date) - COALESCE((SELECT COUNT(1) FROM nonWorkDays WHERE nonWorkDays.date BETWEEN start_date AND end_date), 0)
FROM accounts

If you really need to write a DATEDIFFWITHOUTWEEKENDSORHOLIDAYS function then just use the above and create a function (there's plenty of resources on how to make functions in each RDBMS).. just be sure to give it a better name. ^_^

One thing you will need to fix is I think there's a +1 missing somewhere in the above, for example DATEDIFF(today, today) if today is a weekend will return -1 instead of returning 0.

like image 22
Seph Avatar answered Oct 07 '22 11:10

Seph