This question already has answers here:
Finding the number of days between two dates
(34 answers)
Closed 3 months ago.
I want to do is to count the days between two dates excluding the weekends and i;m done doing that using the function below. But whenever the $startDate is greater than the $endDate i can't get the proper result. I try to use if ($startDate>$endDate) and i'm stock with that condition and honestly don't know what is the next step.
function getWorkingDays($startDate,$endDate){
// do strtotime calculations just once
$startDate = strtotime($startDate);
$endDate = strtotime($endDate);
//The total number of days between the two dates. We compute the no. of seconds and divide it to 60*60*24
//We add one to inlude both dates in the interval.
$days = ($endDate - $startDate) / 86400 + 0;
$no_full_weeks = floor($days / 7);
$no_remaining_days = fmod($days, 7);
//It will return 1 if it's Monday,.. ,7 for Sunday
$the_first_day_of_week = date("N", $startDate);
$the_last_day_of_week = date("N", $endDate);
// If one of the value is empty it will return "0"
if ($startDate == '' || $endDate == '')
return "0"; // Default value
//---->The two can be equal in leap years when february has 29 days, the equal sign is added here
//In the first case the whole interval is within a week, in the second case the interval falls in two weeks.
if ($the_first_day_of_week <= $the_last_day_of_week) {
if ($the_first_day_of_week <= 6 && 6 <= $the_last_day_of_week) $no_remaining_days--;
if ($the_first_day_of_week <= 7 && 7 <= $the_last_day_of_week) $no_remaining_days--;
}
else {
// (edit by Tokes to fix an edge case where the start day was a Sunday
// and the end day was NOT a Saturday)
// the day of the week for start is later than the day of the week for end
if ($the_first_day_of_week == 7) {
// if the start date is a Sunday, then we definitely subtract 1 day
$no_remaining_days--;
if ($the_last_day_of_week == 6) {
// if the end date is a Saturday, then we subtract another day
$no_remaining_days--;
}
}
else {
// the start date was a Saturday (or earlier), and the end date was (Mon..Fri)
// so we skip an entire weekend and subtract 2 days
$no_remaining_days -= 2;
}
}
//The no. of business days is: (number of weeks between the two dates) * (5 working days) + the remainder
//---->february in none leap years gave a remainder of 0 but still calculated weekends between first and last day, this is one way to fix it
$workingDays = $no_full_weeks * 5;
if ($no_remaining_days > 0 )
{
$workingDays += $no_remaining_days;
}
return $workingDays;
}
$startTimeStamp = strtotime("2011/07/01");
$endTimeStamp = strtotime("2011/07/17");
$timeDiff = abs($endTimeStamp - $startTimeStamp);
$numberDays = $timeDiff/86400; // 86400 seconds in one day
// and you might want to convert to integer
$numberDays = intval($numberDays);
OR
function dateDiff($start, $end) {
$start_ts = strtotime($start);
$end_ts = strtotime($end);
$diff = $end_ts - $start_ts;
return round($diff / 86400);
}
echo dateDiff("2011-02-15", "2012-01-16").'days';
//Get number of days deference between current date and given date.
echo dateDiff("2011-02-15", date('Y-m-d')).'days';
For Count days excluding use below code
$start = new DateTime('7/17/2017');
$end = new DateTime('7/24/2017');
$oneday = new DateInterval("P1D");
$daysName = array('Mon', 'Tue', 'Wed', 'Thu', 'Fri');
$days = array();
foreach(new DatePeriod($start, $oneday, $end->add($oneday)) as $day) {
$day_num = $day->format("N"); /* 'N' number days 1 (mon) to 7 (sun) */
if($day_num < 6) { /* weekday */
$days[$day->format("Y-m-d")] = date('D', strtotime($day->format("Y-m-d")));;
}
}
echo "<pre>";
print_r($days);
echo count($days);
This will check whether start date is less than end date. If yes, then it will display the days.
<?php
if($days = getWorkingDays("2017-05-01","2018-01-01")){
echo $days;
}
function getWorkingDays($startDate,$endDate){
$startDate = strtotime($startDate);
$endDate = strtotime($endDate);
if($startDate <= $endDate){
$datediff = $endDate - $startDate;
return floor($datediff / (60 * 60 * 24));
}
return false;
}
?>
Output: 245
Functions Used:
strtotime(): The strtotime() function parses an English textual datetime into a Unix timestamp
floor(): The floor() function rounds a number DOWN to the nearest integer
Edit-1: Getting Days After Excluding Weekends (saturdays & sundays)
//getWorkingDays(start_date, end_date)
if($days = getWorkingDays("2017-05-01","2018-01-01")){
echo $days;
}
function getWorkingDays($startDate,$endDate){
$days = false;
$startDate = strtotime($startDate);
$endDate = strtotime($endDate);
if($startDate <= $endDate){
$datediff = $endDate - $startDate;
$days = floor($datediff / (60 * 60 * 24)); // Total Nos Of Days
$sundays = intval($days / 7) + (date('N', $startDate) + $days % 7 >= 7); // Total Nos Of Sundays Between Start Date & End Date
$saturdays = intval($days / 7) + (date('N', $startDate) + $days % 6 >= 6); // Total Nos Of Saturdays Between Start Date & End Date
$days = $days - ($sundays + $saturdays); // Total Nos Of Days Excluding Weekends
}
return $days;
}
?>
Sources:
calculate sundays between two dates
The intval() function is used to get the integer value of a variable.
See Description date('N', $date) : N - The ISO-8601 numeric representation of a day (1 for Monday, 7 for Sunday)
There is the script of code for do this.
<?php
$now = time(); // or your date as well
$your_date = strtotime("2010-01-01");
$datediff = $now - $your_date;
echo floor($datediff / (60 * 60 * 24));
?>
or
$datetime1 = new DateTime("2010-06-20");
$datetime2 = new DateTime("2011-06-22");
$difference = $datetime1->diff($datetime2);
echo 'Difference: '.$difference->y.' years, '
.$difference->m.' months, '
.$difference->d.' days';
print_r($difference);
try this
public function datediff($sdate,$edate){
$diffformat='%a';
$date1 = date_create($sdate);
$date2 = date_create($edate);
$diff12 = date_diff($date2, $date1);
$days = $diff12->format($diffformat) + 1;}
EDIT: I noticed in the comment you want to exclude the weekend day/days (however you didn't mention that in your post !)
you can add the number of days you want to exclude from the week
you can use DateTime::diff and use the option for absolute result (positive difference always)
<?php
function daysBetween2Dates($date1, $date2, $execludedDaysFromWeek = 0)
{
try{
$datetime1 = new \DateTime($date1);
$datetime2 = new \DateTime($date2);
}catch (\Exception $e){
return false;
}
$interval = $datetime1->diff($datetime2,true);
$days = $interval->format('%a');
if($execludedDaysFromWeek < 0 || $execludedDaysFromWeek > 7){
$execludedDaysFromWeek = 0 ;
}
return ceil($days * (7-$execludedDaysFromWeek) / 7);
}
Usage Example
// example 1 : without weekend days, start date is the first one
$days = daysBetween2Dates('2016-12-31','2017-12-31');
echo $days;
// example 2 : without weekend days, start date is the second one
$days = daysBetween2Dates('2017-12-31', '2016-12-31');
echo "<br>\n" .$days;
// example 3 : with weekend days, it returns 6 days for the week
$days = daysBetween2Dates('2017-12-31', '2017-12-24',-1);
echo "<br>\n" .$days;
exit;
this outputs
365
365
6
live demo (https://eval.in/835862)
use date_diff() which returns the difference between two DateTime objects.
$diff=date_diff($startDate,$endDate);
Related
This question already has answers here:
Calculate business days
(33 answers)
Closed 9 months ago.
I am trying to find the total working days by specifying the first and end date and also the number of working days in a week. But unfortunately, the final result is coming wrong.
Below is my script
echo getWorkingDays("2022-04-01","2022-04-30",6)
function getWorkingDays($startDate,$endDate,$working_days_in_a_week){
// do strtotime calculations just once
$endDate = strtotime($endDate);
$startDate = strtotime($startDate);
//The total number of days between the two dates. We compute the no. of seconds and divide it to 60*60*24
//We add one to inlude both dates in the interval.
$days = ($endDate - $startDate) / 86400 + 1;
$no_full_weeks = floor($days / 7);
$no_remaining_days = fmod($days, 7);
//It will return 1 if it's Monday,.. ,7 for Sunday
$the_first_day_of_week = date("N", $startDate);
$the_last_day_of_week = date("N", $endDate);
//---->The two can be equal in leap years when february has 29 days, the equal sign is added here
//In the first case the whole interval is within a week, in the second case the interval falls in two weeks.
if ($the_first_day_of_week <= $the_last_day_of_week) {
if ($the_first_day_of_week <= 6 && 6 <= $the_last_day_of_week) $no_remaining_days--;
if ($the_first_day_of_week <= 7 && 7 <= $the_last_day_of_week) $no_remaining_days--;
}
else {
// (edit by Tokes to fix an edge case where the start day was a Sunday
// and the end day was NOT a Saturday)
// the day of the week for start is later than the day of the week for end
if($working_days_in_a_week !=7) {
if ($the_first_day_of_week == 7) {
// if the start date is a Sunday, then we definitely subtract 1 day
$no_remaining_days--;
if ($the_last_day_of_week == 6) {
// if the end date is a Saturday, then we subtract another day
$no_remaining_days--;
}
} else {
// the start date was a Saturday (or earlier), and the end date was (Mon..Fri)
// so we skip an entire weekend and subtract 2 days
$no_remaining_days -= 2;
}
}
}
//The no. of business days is: (number of weeks between the two dates) * (5 working days) + the remainder
//---->february in none leap years gave a remainder of 0 but still calculated weekends between first and last day, this is one way to fix it
$workingDays = $no_full_weeks * $working_days_in_a_week;
if ($no_remaining_days > 0 )
{
$workingDays += $no_remaining_days;
}
//We subtract the holidays
/*foreach($holidays as $holiday){
$time_stamp=strtotime($holiday);
//If the holiday doesn't fall in weekend
if ($startDate <= $time_stamp && $time_stamp <= $endDate && date("N",$time_stamp) != 6 && date("N",$time_stamp) != 7)
$workingDays--;
}*/
return $workingDays;
}
The final result is coming 25 when in fact the result should be 26 as there are only 4 Sundays in April and the number of business days in the week is 6 which means only Sunday is the weekend. What I am doing here? please help?
The below should do what you're looking for.
The difference with this function and yours is that the third parameter can be an array of days or an integer. For example, if you have working days that are:
Monday
Tuesday
Friday
You would set the third parameter as [1, 2, 5].
/**
* #param string $start_date Pass the start date in `Y-m-d` format.
* #param string $end_date Pass the end date in `Y-m-d` format.
* #param array|int $working_days Pass an array of working days where 1 is Monday and 7 is Sunday. Or pass the number of working days.
* #return float|int
*/
function get_working_days( string $start_date, string $end_date, array|int $working_days = [ 1, 2, 3, 4, 5 ] ) {
$start = DateTime::createFromFormat( 'Y-m-d', $start_date );
$end = DateTime::createFromFormat( 'Y-m-d', $end_date );
// Get numeric representation of the day of the week.
// 1 (for Monday) through 7 (for Sunday)
$start_day = $start->format( 'w' ) + 1;
$end_day = $end->format( 'w' ) + 1;
// Convert int into array of days
if ( is_int( $working_days ) ) {
$working_int = $working_days;
$working_days = [];
for ( $i = 0; $i < $working_int; $i++ ) {
if ( $i >= 7 ) break;
$working_days[] = $i + 1;
}
}
$counts = [];
foreach ( $working_days as $day_num ) {
$day_count = 0;
if ( $start_day < $end_day ) {
$is_partial = $day_num >= $start_day && $day_num <= $end_day;
} else if ( $start_day === $end_day ) {
$is_partial = $start_day === $day_num;
} else {
$is_partial = $day_num >= $start_day || $day_num <= $end_day;
}
$complete_weeks = floor( ( $end->getTimestamp() - $start->getTimestamp() ) / 60 / 60 / 24 / 7 );
$patial_weeks = $is_partial ? 1 : 0;
$counts[ $day_num ] = $complete_weeks + $patial_weeks;
}
return array_sum( $counts );
}
echo get_working_days( '2022-04-01', '2022-04-30', 6 );
check this solution:
echo getWorkingDays("2022-04-01","2022-04-30",6);
function getWorkingDays($startDate,$endDate,$working_days_in_a_week){
// do strtotime calculations just once
$endDate = strtotime($endDate);
$startDate = strtotime($startDate);
$start_day = date("N", $startDate);
//The total number of days between the two dates. We compute the no. of seconds and divide it to 60*60*24
//We add one to inlude both dates in the interval.
$days = ($endDate - $startDate) / 86400 + 1;
$fullweeks = floor($days/7);
$restofdays = $days%7;
$workingDays=$fullweeks*$working_days_in_a_week;
for($x=0;$x<$restofdays;$x++){
if((($start_day+$x)%7)<=$working_days_in_a_week)$workingDays++;
}
return $workingDays;
}
how can i stop calling the function if one of my fields are empty? Because i have a function that count the days between two fields, So if one my field is empty the result of count is showing "12,000" something like that.
Example:
$start = ("");
$end =("2017-10-19");
$date = getWorkingDays($start, $end);
This is the function that is used, But whenever the $start is greater than $end i get a wrong result. how can i fix it?
function getWorkingDays($startDate,$endDate ){
// do strtotime calculations just once
$startDate = strtotime($startDate);
$endDate = strtotime($endDate);
//The total number of days between the two dates. We compute the no. of seconds and divide it to 60*60*24
//We add one to inlude both dates in the interval.
$days = ($endDate - $startDate) / 86400 + 0;
$no_full_weeks = floor($days / 7);
$no_remaining_days = fmod($days, 7);
//It will return 1 if it's Monday,.. ,7 for Sunday
$the_first_day_of_week = date("N", $startDate);
$the_last_day_of_week = date("N", $endDate);
// If one of the value is empty it will return "0"
if ($startDate == '' || $endDate == '')
return "0"; // Default value
//---->The two can be equal in leap years when february has 29 days, the equal sign is added here
//In the first case the whole interval is within a week, in the second case the interval falls in two weeks.
if ($the_first_day_of_week <= $the_last_day_of_week) {
if ($the_first_day_of_week <= 6 && 6 <= $the_last_day_of_week) $no_remaining_days--;
if ($the_first_day_of_week <= 7 && 7 <= $the_last_day_of_week) $no_remaining_days--;
}
else {
// (edit by Tokes to fix an edge case where the start day was a Sunday
// and the end day was NOT a Saturday)
// the day of the week for start is later than the day of the week for end
if ($the_first_day_of_week == 7) {
// if the start date is a Sunday, then we definitely subtract 1 day
$no_remaining_days--;
if ($the_last_day_of_week == 6) {
// if the end date is a Saturday, then we subtract another day
$no_remaining_days--;
}
}
else {
// the start date was a Saturday (or earlier), and the end date was (Mon..Fri)
// so we skip an entire weekend and subtract 2 days
$no_remaining_days -= 2;
}
}
//The no. of business days is: (number of weeks between the two dates) * (5 working days) + the remainder
//---->february in none leap years gave a remainder of 0 but still calculated weekends between first and last day, this is one way to fix it
$workingDays = $no_full_weeks * 5;
if ($no_remaining_days > 0 )
{
$workingDays += $no_remaining_days;
}
return $workingDays;
}
$start = ("2017-04-21");
$end = ("2017-04-17");
$date = getWorkingDays($start, $end);
echo $date;
You just need to check if $start and $end are not empty.
Either when calling your function :
$start = ("");
$end =("2017-10-19");
if ($start != '' && $end != '') {
$date = getWorkingDays($start, $end);
} else {
$date = 0; // Default value
}
Or in your function declaration :
function getWorkingDays($start, $end) {
if ($start == '' || $end == '')
return 0; // Default value
/* Here is the rest of your function */
}
I want to calculate total working days between two dates by using custom off day. I inserted Monday,Saturday and Sunday is off days into table. But,when I calculate from start date 2015-07-26 and end date 2015-08-26,the result is correct. However,if start date 2015-08-01 and end date 2015-08-31,the result is incorrect.
How can I do that?
Here is my code
<?php
include 'connect.php';
error_reporting(E_ALL ^ E_NOTICE);
if (isset($_POST['startdate']) && isset($_POST['enddate']))
{
$startdate=$_POST['startdate'];
$enddate=$_POST['enddate'];
$no = 0;
$daysdiff = floor(((strtotime($enddate) -strtotime($startdate)) / 86400)+1);
echo "total day is".$daysdiff;
$startdate = new DateTime($startdate);
$enddate= new DateTime($enddate);
$interval = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($startdate, $interval, $enddate);
$res=mysql_query("SELECT * From working_day") or die(mysql_error());
while ($row = mysql_fetch_assoc($res))
{
$id=$row['id'];
$name_value=$row['off_days'];
foreach ($period as $dt)
{
if (($dt->format('N')== $id ))
{
$no++;
//$result=$daysdiff-$no;
}
}
$result=$daysdiff-$no;
}
echo "<input class='form-control' type='text' name='working_day' value='$result' />";
}
?>
I use a function that I believe I got from this site a long time ago to calculate time off for employees in my web app. Here's the full function, where I also take into account custom holidays from a table called "holiday_dates":
function countWorkingDays($startDate,$endDate)
{
$pdoCore = Core::getInstance();
// Build the holiday array
$holidays_q = $pdoCore->dbh->prepare("SELECT holidayDate FROM holiday_dates");
$holidays_q->execute();
while($holidays_a = $holidays_q->fetch(PDO::FETCH_ASSOC))
{
$holidays[] = $holidays_a['holidayDate'];
}
// do strtotime calculations just once
$endDate = strtotime($endDate);
$startDate = strtotime($startDate);
//The total number of days between the two dates. We compute the no. of seconds and divide it to 60*60*24
//We add one to inlude both dates in the interval.
$days = ($endDate - $startDate) / 86400 + 1;
$no_full_weeks = floor($days / 7);
$no_remaining_days = fmod($days, 7);
//It will return 1 if it's Monday,.. ,7 for Sunday
$the_first_day_of_week = date("N", $startDate);
$the_last_day_of_week = date("N", $endDate);
//---->The two can be equal in leap years when february has 29 days, the equal sign is added here
//In the first case the whole interval is within a week, in the second case the interval falls in two weeks.
if($the_first_day_of_week <= $the_last_day_of_week)
{
if($the_first_day_of_week <= 6 and 6 <= $the_last_day_of_week)
{
$no_remaining_days--;
}
if($the_first_day_of_week <= 7 and 7 <= $the_last_day_of_week)
{
$no_remaining_days--;
}
}
else
{
// (edit by Tokes to fix an edge case where the start day was a Sunday
// and the end day was NOT a Saturday)
// the day of the week for start is later than the day of the week for end
if ($the_first_day_of_week == 7)
{
// if the start date is a Sunday, then we definitely subtract 1 day
$no_remaining_days--;
if ($the_last_day_of_week == 6)
{
// if the end date is a Saturday, then we subtract another day
$no_remaining_days--;
}
}
else
{
// the start date was a Saturday (or earlier), and the end date was (Mon..Fri)
// so we skip an entire weekend and subtract 2 days
$no_remaining_days -= 2;
}
}
//The no. of business days is: (number of weeks between the two dates) * (5 working days) + the remainder
//---->february in none leap years gave a remainder of 0 but still calculated weekends between first and last day, this is one way to fix it
$workingDays = $no_full_weeks * 5;
if ($no_remaining_days > 0 )
{
$workingDays += $no_remaining_days;
}
//We subtract the holidays
foreach($holidays as $holiday)
{
$time_stamp=strtotime($holiday);
//If the holiday doesn't fall in weekend
if($startDate <= $time_stamp and $time_stamp <= $endDate and date("N",$time_stamp) != 6 and date("N",$time_stamp) != 7)
{
$workingDays--;
}
}
return $workingDays;
}
For your use case, I'd say pay attention to this line:
if($startDate <= $time_stamp and $time_stamp <= $endDate and date("N",$time_stamp) != 6 and date("N",$time_stamp) != 7)
And add this for Monday:
and date("N",$time_stamp) != 1
I have code which returns number of business days in selected month/years. I need to get a list of week days to control It, for example:
if (friday) {
$i = 1;
}
if (thursday) {
$i = 0;
}
And code which I use for calculating weekdays:
<?php
//The function returns the no. of business days between two dates and it skips the holidays
function getWorkingDays($startDate,$endDate,$holidays){
// do strtotime calculations just once
$endDate = strtotime($endDate);
$startDate = strtotime($startDate);
//The total number of days between the two dates. We compute the no. of seconds and divide it to 60*60*24
//We add one to inlude both dates in the interval.
$days = ($endDate - $startDate) / 86400 + 1;
$no_full_weeks = floor($days / 7);
$no_remaining_days = fmod($days, 7);
//It will return 1 if it's Monday,.. ,7 for Sunday
$the_first_day_of_week = date("N", $startDate);
$the_last_day_of_week = date("N", $endDate);
//---->The two can be equal in leap years when february has 29 days, the equal sign is added here
//In the first case the whole interval is within a week, in the second case the interval falls in two weeks.
if ($the_first_day_of_week <= $the_last_day_of_week) {
if ($the_first_day_of_week <= 6 && 6 <= $the_last_day_of_week) $no_remaining_days--;
if ($the_first_day_of_week <= 7 && 7 <= $the_last_day_of_week) $no_remaining_days--;
}
else {
// (edit by Tokes to fix an edge case where the start day was a Sunday
// and the end day was NOT a Saturday)
// the day of the week for start is later than the day of the week for end
if ($the_first_day_of_week == 7) {
// if the start date is a Sunday, then we definitely subtract 1 day
$no_remaining_days--;
if ($the_last_day_of_week == 6) {
// if the end date is a Saturday, then we subtract another day
$no_remaining_days--;
}
}
else {
// the start date was a Saturday (or earlier), and the end date was (Mon..Fri)
// so we skip an entire weekend and subtract 2 days
$no_remaining_days -= 2;
}
}
//The no. of business days is: (number of weeks between the two dates) * (5 working days) + the remainder
//---->february in none leap years gave a remainder of 0 but still calculated weekends between first and last day, this is one way to fix it
$workingDays = $no_full_weeks * 5;
if ($no_remaining_days > 0 )
{
$workingDays += $no_remaining_days;
}
//We subtract the holidays
foreach($holidays as $holiday){
$time_stamp=strtotime($holiday);
//If the holiday doesn't fall in weekend
if ($startDate <= $time_stamp && $time_stamp <= $endDate && date("N",$time_stamp) != 6 && date("N",$time_stamp) != 7)
$workingDays--;
}
return $workingDays;
}
//Example:
$holidays=array("2008-12-25","2008-12-26","2009-01-01");
echo getWorkingDays("2008-12-22","2009-01-02",$holidays)
// => will return 7
?>
Is It possible to make It? Thank you for answers.
You can try something like below:
$startDate = new DateTime( '2013-04-01' ); //intialize start date
$endDate = new DateTime( '2013-04-30' ); //initialize end date
$holiday = array('2013-04-11','2013-04-25'); //this is assumed list of holiday
$interval = new DateInterval('P1D'); // set the interval as 1 day
$daterange = new DatePeriod($startDate, $interval ,$endDate);
$i = 0;
foreach($daterange as $date){
if($date->format("N") == 5) // OR if($date->format("l") == "Friday")
$i++;
}
echo $i;
try this, it increase $i on every occurrence of Friday between two dates
$startdate ="2008-12-22";
$enddate="2009-01-22";
$i=0;
while($startdate <= $enddate)
{
$startdate = date("Y-m-d", strtotime("+1 day", strtotime($startdate)));
$day = date("d",strtotime($startdate));
$month = date("m",strtotime($startdate));
$year = date("Y",strtotime($startdate));
if(date("l", mktime(0, 0, 0, $month, $day, $year)) == "Friday" )
{
echo $day."-".$month."-".$year." is ".date("l", mktime(0, 0, 0, $month, $day, $year))."\n" ;
$i++; \\ increase $i on every occurrence of Friday
}
}
Demo
Can some one help me write a function that calculates the number of working hours between two dates but want to exclude the time when the request had a status of "On Hold".
So lets say the request came in at 3PM friday and was closed at 3PM Wednesday, and working hours are from 8AM to 5PM pacific (Mon thru Friday)...Total working hours will be 27 hours...but if the request remained on hold from Monday 3PM till Tuesday 3PM...Actual work time on the request really becomes 18 hours instead of 27 hours.
I have recently started working on PHP and have been assigned this task which is very confusing to me. Please help
All you have to do is get the total time elapsed, then substract the non-working hours.
You can use dateTime and datePeriod php objects for that (requires php 5.3)
Here a small script to do what you want (but you will have probably to adapt for your needs)
<?php
ini_set('display_errors', 'on');
define('DAY_WORK', 32400); // 9 * 60 * 60
define('HOUR_START_DAY', '08:00:00');
define('HOUR_END_DAY', '17:00:00');
// get begin and end dates of the full period
$date_begin = '2013-11-29 15:00:00';
$date_end = '2013-12-03 15:00:00';
// keep the initial dates for later use
$d1 = new DateTime($date_begin);
$d2 = new DateTime($date_end);
// and get the datePeriod from the 1st to the last day
$period_start = new DateTime($d1->format('Y-m-d 00:00:00'));
$period_end = new DateTime($d2->format('Y-m-d 23:59:59'));
$interval = new DateInterval('P1D');
//$interval = new DateInterval('weekdays'); // 1 day interval to get all days between the period
$period = new DatePeriod($period_start, $interval, $period_end);
$worked_time = 0;
$nb = 0;
// for every worked day, add the hours you want
foreach($period as $date){
$week_day = $date->format('w'); // 0 (for Sunday) through 6 (for Saturday)
if (!in_array($week_day,array(0, 6)))
{
// if this is the first day or the last dy, you have to count only the worked hours
if ($date->format('Y-m-d') == $d1->format('Y-m-d'))
{
$end_of_day_format = $date->format('Y-m-d '.HOUR_END_DAY);
$d1_format = $d1->format('Y-m-d H:i:s');
$end_of_day = new DateTime($end_of_day_format);
$diff = $end_of_day->diff($d1)->format("%H:%I:%S");
$diff = split(':', $diff);
$diff = $diff[0]*3600 + $diff[1]*60 + $diff[0];
$worked_time += $diff;
}
else if ($date->format('Y-m-d') == $d2->format('Y-m-d'))
{
$start_of_day = new DateTime($date->format('Y-m-d '.HOUR_START_DAY));
$d2_format = $d2->format('Y-m-d H:i:s');
$end_of_day = new DateTime($end_of_day_format);
$diff = $start_of_day->diff($d2)->format('%H:%I:%S');
$diff = split(':', $diff);
$diff = $diff[0]*3600 + $diff[1]*60 + $diff[0];
$worked_time += $diff;
}
else
{
// otherwise, just count the full day of work
$worked_time += DAY_WORK;
}
}
if ($nb> 10)
die("die ".$nb);
}
echo sprintf('Works from %s to %s, You worked %d hour(s)', $date_begin, $date_end, $worked_time/60/60);
Calculate work time with an accuracy of 1 minute.
WARNING: This function can take many seconds to load as it does a loop for every minute between the time span.
<?php
$request = array(
'start' => '3PM Nov 29 2013',
'end' => '3PM Dec 4 2013'
);
echo calculate_work($request);
/**
* Calculate work time by looping through every minute
* #param array $request start to end time
* #return int work time in minutes
*/
function calculate_work($request)
{
$start = strtotime($request['start']);
$end = strtotime($request['end']);
$work_time = 0;
/* Add 1 minute to the start so that we don't count 0 as a minute */
for ($time = $start + 60; $time <= $end; $time += 60)
{
// Weekends
if (date('D', $time) == 'Sat' OR date('D', $time) == 'Sun')
continue;
// Non Working Hours
if (date('Hi', $time) <= '0800' OR date('Hi', $time) > '1700')
continue;
// On Hold
if ($time > strtotime('3PM Dec 2 2013') AND $time <= strtotime('3PM Dec 3 2013'))
continue;
$work_time++;
}
// Divide by 60 to turn minutes into hours
return $work_time / 60;
}
/**
* Get the total working hours in seconds between 2 dates..
* #param DateTime $start Start Date and Time
* #param DateTime $end Finish Date and Time
* #param array $working_hours office hours for each weekday (0 Monday, 6 Sunday), Each day must be an array containing a start/finish time in seconds since midnight.
* #return integer
* #link https://github.com/RCrowt/working-hours-calculator
*/
function getWorkingHoursInSeconds(DateTime $start, DateTime $end, array $working_hours)
{
$seconds = 0; // Total working seconds
// Calculate the Start Date (Midnight) and Time (Seconds into day) as Integers.
$start_date = clone $start;
$start_date = $start_date->setTime(0, 0, 0)->getTimestamp();
$start_time = $start->getTimestamp() - $start_date;
// Calculate the Finish Date (Midnight) and Time (Seconds into day) as Integers.
$end_date = clone $end;
$end_date = $end_date->setTime(0, 0, 0)->getTimestamp();
$end_time = $end->getTimestamp() - $end_date;
// For each Day
for ($today = $start_date; $today <= $end_date; $today += 86400) {
// Get the current Weekday.
$today_weekday = date('w', $today);
// Skip to next day if no hours set for weekday.
if (!isset($working_hours[$today_weekday][0]) || !isset($working_hours[$today_weekday][1])) continue;
// Set the office hours start/finish.
$today_start = $working_hours[$today_weekday][0];
$today_end = $working_hours[$today_weekday][1];
// Adjust Start/Finish times on Start/Finish Day.
if ($today === $start_date) $today_start = min($today_end, max($today_start, $start_time));
if ($today === $end_date) $today_end = max($today_start, min($today_end, $end_time));
// Add to total seconds.
$seconds += $today_end - $today_start;
}
return gmdate("H:i:s", $seconds);
}