I have searched the piece of code online. It's about getting the working days of the month (which subtracting the number of the Weekend Holidays (Sunday only) and the number of Public Holidays of the month).
Eg, my working days is from Monday to Saturday, but I have 3 public holidays in this month which are on 24th (Saturday), 25th (Sunday), and 26th (Mondy) of June.
Supposedly my working days will be 24. However, with this code,
{<?php
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 * 6;
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("2017-06-25","2017-06-24","2017-06-26");
echo getWorkingDays("2017-06-01","2017-06-30",$holidays)
// => will return 7
?>}
I get an extra working day --> (24 + 1) days. I think the public holiday which falls on 24th June (Saturday) is counted as a working days, the program does not ignore it as a holiday.
Thank you for your help, much appreciated.
if you want to skip Saturday then simply remove it from holidays count condition
<?php
//If the holiday doesn't fall in weekend
if ($startDate <= $time_stamp && $time_stamp <= $endDate && date("N",$time_stamp) != 7 )
$workingDays--;
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;
}
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 a record set that is pulling various pieces of information from a SQL database including dates. What I'd like to do is work out the number of working days from a specific date to todays date. I'm basically working out how many working days have passed since the first date.
I don't have an issue working out the working days, there are many very helpful posts on here. The issue I have is that I need this to recur on each line in the table that is filled from the database. But as the variables are different for each row, the page is blank after the first result, because I assume the script is trying to run again using the same named variables.
Is there a way to enclose the php code for this sum so that it can run in the next row with the same variables without the previous row interfering?
Thanks in advance for help.
<?php
//The function returns the no. of business days between two dates and it skips the holidays
function getWorkingDays($startDate,$endDate){
// 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;
}
$approval = date('Y-m-d',strtotime($row_rsworksorders1['intraartapproval']));
$w_days = getWorkingDays($approval,(date('Y-m-d'))) . ' Days';
echo $w_days;
?>
The date being pulled from the database is $row_rsworksorders1['intraartapproval'])
I am writing an application for a class and it requires that I format an expected arrival date. The expected arrival date is ideally 5 business days from the current day. I do not even know how to make it accurately display 5 days from the current day, let alone doing so without weekends. Any help on the topic would be appreciated.
I have tried using the following function, which I've seen elsewhere on the site, but I cannot get the function operational at all, even just pasting it in my code and not using it anywhere yields an error message. I feel that it might be related to the strtotime() function, since I haven't been able to use that elsewhere in this application.
In addition, I'd like to avoid using the function below if at all possible, simply because I do not understand half of what it involves. I'd ideally like to use a function that I can comprehend.
<?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
?>
You should use the strtotime() function.
The logic would be as described:
take the current date and add 5 days
if the day number of that date is 6 (saturday) or 0 (sunday), add 2 or 1 more days respectively
I tested it on XAMPP and it works perfectly!!
function get_arrival_date($departure_date){
$arrival_date = date ('Y-m-d', strtotime ($departure_date. " +5 days"));
$day_number = date("w", strtotime($arrival_date));
switch($day_number)
{
case "6":
$arrival_date = date ('Y-m-d', strtotime ($arrival_date. " +2 days"));
break;
case "0":
$arrival_date = date ('Y-m-d', strtotime ($arrival_date. " +1 days"));
break;
}
return $arrival_date;
}
//End of function... Let's start with a little test
//First you set the departure date in a variable.
//You can even supply this value directly as a string '2014-12-20' or
//retrieve it from mysql database if you want
$date1 = date ('Y-m-d'); //Today (just and example)
//Then you call the function and assign its result to a variable
$date2= get_arrival_date($date1); //This variable holds the arrival date
echo $date2; //Let's print the arrival date
P.s.If you find this answer useful please mark it as the right one.
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