Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mysql : how to calculate business hrs between two timestamps and neglect weekends

Tags:

date

sql

mysql

My table has sample data and I need to calculate business hrs between two timestamps in two columns. Business hrs : 9:00am to 5:00pm and neglect Saturday and Sunday, I am not considering public holidays. Can someone please provide some guidelines on how to achieve this? I want desired output as stated in column 3 , date is in format of : yyyy-mm-dd

    Created date             Updated date         Business hrs
    2012-03-05 9:00am   2012-03-05 3:00pm             6
    2012-03-05 10:00am  2012-03-06 10:00am            9
    2012-03-09 4:00pm   2012-03-19 10:00am            2
like image 797
yokoyoko Avatar asked Nov 17 '12 00:11

yokoyoko


People also ask

How can I calculate hours between two dates in MySQL?

TIMEDIFF() function MySQL TIMEDIFF() returns the differences between two time or datetime expressions. It is to be noted that two expressions must be the same type. A datetime value.

How can I calculate days difference between two dates in MySQL?

MySQL DATEDIFF() Function The DATEDIFF() function returns the number of days between two date values.

How does datediff work in MySQL?

DATEDIFF() returns expr1 − expr2 expressed as a value in days from one date to the other. expr1 and expr2 are date or date-and-time expressions. Only the date parts of the values are used in the calculation. This function returns NULL if expr1 or expr2 is NULL .

Does MySQL have datediff?

Description. The MySQL DATEDIFF function returns the difference in days between two date values.


1 Answers

The question says that public holidays should not be considered, so this answer does just that - calculates business hours taking weekends into account, but ignoring possible public holidays.

If you need to take public holidays into account you'd need to have a separate table which would list dates for public holidays, which may differ from year to year and from state to state or country to country. The main formula may stay the same, but you'd need to subtract from its result hours for public holidays that fall within the given range of dates.

Let's create a table with some sample data that covers various cases:

CREATE TABLE T (CreatedDate datetime, UpdatedDate datetime);

INSERT INTO T VALUES
('2012-03-05 09:00:00', '2012-03-05 15:00:00'), -- simple part of the same day
('2012-03-05 10:00:00', '2012-03-06 10:00:00'), -- full day across the midnight
('2012-03-05 11:00:00', '2012-03-06 10:00:00'), -- less than a day across the midnight
('2012-03-05 10:00:00', '2012-03-06 15:00:00'), -- more than a day across the midnight
('2012-03-09 16:00:00', '2012-03-12 10:00:00'), -- over the weekend, less than 7 days
('2012-03-06 16:00:00', '2012-03-15 10:00:00'), -- over the weekend, more than 7 days
('2012-03-09 16:00:00', '2012-03-19 10:00:00'); -- over two weekends

In MS SQL Server I use the following formula:

SELECT
    CreatedDate,
    UpdatedDate,
    DATEDIFF(minute, CreatedDate, UpdatedDate)/60.0 -
    DATEDIFF(day,    CreatedDate, UpdatedDate)*16 -
    DATEDIFF(week,   CreatedDate, UpdatedDate)*16 AS BusinessHours
FROM T

Which produces the following result:

+-------------------------+-------------------------+---------------+
|       CreatedDate       |       UpdatedDate       | BusinessHours |
+-------------------------+-------------------------+---------------+
| 2012-03-05 09:00:00     | 2012-03-05 15:00:00     | 6             |
| 2012-03-05 10:00:00     | 2012-03-06 10:00:00     | 8             |
| 2012-03-05 11:00:00     | 2012-03-06 10:00:00     | 7             |
| 2012-03-05 10:00:00     | 2012-03-06 15:00:00     | 13            |
| 2012-03-09 16:00:00     | 2012-03-12 10:00:00     | 2             |
| 2012-03-06 16:00:00     | 2012-03-15 10:00:00     | 50            |
| 2012-03-09 16:00:00     | 2012-03-19 10:00:00     | 42            |
+-------------------------+-------------------------+---------------+

It works, because in SQL Server DATEDIFF returns the count of the specified datepart boundaries crossed between the specified startdate and enddate.

Each day has 8 business hours. I calculate total number of hours between two dates, then subtract the number of midnights multiplied by 16 non-business hours per day, then subtract the number of weekends multiplied by 16 (8+8 business hours for Sat+Sun).

It also assumes that the given start and end date/times are during the business hours.

In MySQL the closest equivalent is TIMESTAMPDIFF, but it works differently. It effectively calculates the difference in seconds and divides (discarding the fractional part) by the number of seconds in the chosen unit.

So, to get results that we need we can calculate the TIMESTAMPDIFF between some anchor datetime and CreatedDate and UpdatedDate instead of calculating the difference between CreatedDate and UpdatedDate directly.

I've chosen 2000-01-03 00:00:00, which is a Monday. You can choose any other Monday (or Sunday, if your week starts on Sunday) midnight for the anchor date.

The MySQL query becomes (see SQL Fiddle):

SELECT
    CreatedDate,
    UpdatedDate,

    TIMESTAMPDIFF(MINUTE, CreatedDate, UpdatedDate)/60.0 -

    16*(
        TIMESTAMPDIFF(DAY,    '2000-01-03',UpdatedDate)-
        TIMESTAMPDIFF(DAY,    '2000-01-03',CreatedDate)
    ) -

    16*(
        TIMESTAMPDIFF(WEEK,   '2000-01-03',UpdatedDate)-
        TIMESTAMPDIFF(WEEK,   '2000-01-03',CreatedDate)
    ) AS BusinessHours

FROM T
like image 163
Vladimir Baranov Avatar answered Oct 03 '22 20:10

Vladimir Baranov