Related
I want to count the total day difference from user input
For example when the user inputs
start_date = 2012-09-06 and end-date = 2012-09-11
For now I am using this code to find the diffeence
$count = abs(strtotime($start_date) - strtotime($end_date));
$day = $count+86400;
$total = floor($day/(60*60*24));
The result of total will be 6. But the problem is that I dont want to include the days at weekend (Saturday and Sunday)
2012-09-06
2012-09-07
2012-09-08 Saturday
2012-09-09 Sunday
2012-09-10
2012-09-11
So the result will be 4
----update---
I have a table that contains date,the table name is holiday date
for example the table contains 2012-09-07
So, the total day will be 3, because it didn't count the holiday date
how do I do that to equate the date from input to date in table?
Very easy with my favourites: DateTime, DateInterval and DatePeriod
$start = new DateTime('2012-09-06');
$end = new DateTime('2012-09-11');
// otherwise the end date is excluded (bug?)
$end->modify('+1 day');
$interval = $end->diff($start);
// total days
$days = $interval->days;
// create an iterateable period of date (P1D equates to 1 day)
$period = new DatePeriod($start, new DateInterval('P1D'), $end);
// best stored as array, so you can add more than one
$holidays = array('2012-09-07');
foreach($period as $dt) {
$curr = $dt->format('D');
// substract if Saturday or Sunday
if ($curr == 'Sat' || $curr == 'Sun') {
$days--;
}
// (optional) for the updated question
elseif (in_array($dt->format('Y-m-d'), $holidays)) {
$days--;
}
}
echo $days; // 4
In my case I needed the same answer as OP, but wanted something a little smaller. #Bojan's answer worked, but I didn't like that it doesn't work with DateTime objects, required using timestamps, and was comparing against strings instead of the actual objects themselves (which feels hacky)... Here's a revised version of his answer.
function getWeekdayDifference(\DateTime $startDate, \DateTime $endDate)
{
$days = 0;
while($startDate->diff($endDate)->days > 0) {
$days += $startDate->format('N') < 6 ? 1 : 0;
$startDate = $startDate->add(new \DateInterval("P1D"));
}
return $days;
}
Per #xzdead's comment if you'd like this to be inclusive of the start and end date:
function getWeekdayDifference(\DateTime $startDate, \DateTime $endDate)
{
$isWeekday = function (\DateTime $date) {
return $date->format('N') < 6;
};
$days = $isWeekday($endDate) ? 1 : 0;
while($startDate->diff($endDate)->days > 0) {
$days += $isWeekday($startDate) ? 1 : 0;
$startDate = $startDate->add(new \DateInterval("P1D"));
}
return $days;
}
The easiest and fastest way to get difference without weekends is by using Carbon library.
Here's an example how to use it:
<?php
$from = Carbon\Carbon::parse('2016-05-21 22:00:00');
$to = Carbon\Carbon::parse('2016-05-21 22:00:00');
echo $to->diffInWeekdays($from);
use DateTime:
$datetime1 = new DateTime('2012-09-06');
$datetime2 = new DateTime('2012-09-11');
$interval = $datetime1->diff($datetime2);
$woweekends = 0;
for($i=0; $i<=$interval->d; $i++){
$datetime1->modify('+1 day');
$weekday = $datetime1->format('w');
if($weekday !== "0" && $weekday !== "6"){ // 0 for Sunday and 6 for Saturday
$woweekends++;
}
}
echo $woweekends." days without weekend";
// 4 days without weekends
date('N') gets the day of the week (1 - Monday, 7 - Sunday)
$start = strtotime('2012-08-06');
$end = strtotime('2012-09-06');
$count = 0;
while(date('Y-m-d', $start) < date('Y-m-d', $end)){
$count += date('N', $start) < 6 ? 1 : 0;
$start = strtotime("+1 day", $start);
}
echo $count;
Here is the improved version of #dan-lee function:
function get_total_days($start, $end, $holidays = [], $weekends = ['Sat', 'Sun']){
$start = new \DateTime($start);
$end = new \DateTime($end);
$end->modify('+1 day');
$total_days = $end->diff($start)->days;
$period = new \DatePeriod($start, new \DateInterval('P1D'), $end);
foreach($period as $dt) {
if (in_array($dt->format('D'), $weekends) || in_array($dt->format('Y-m-d'), $holidays)){
$total_days--;
}
}
return $total_days;
}
To use it:
$start = '2021-06-12';
$end = '2021-06-17';
$holidays = ['2021-06-15'];
echo get_total_days($start, $end, $holidays); // Result: 3
Have a look at this post:
Calculate business days
(In your case, you could leave out the 'holidays' part since you're after working/business days only)
<?php
//The function returns the no. of business days between two dates
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;
}
return $workingDays;
}
// This will return 4
echo getWorkingDays("2012-09-06","2012-09-11");
?>
If you don't need full days but accurate seconds instead try this code. This accepts unix timestamps as an input.
function timeDifferenceWithoutWeekends($from, $to) {
$start = new DateTime("#".$from);
$current = clone $start;
$end = new DateTime("#".$to);
$sum = 0;
while ($current<$end) {
$endSlice = clone $current;
$endSlice->setTime(0,0,0);
$endSlice->modify('+1 day');
if ($endSlice>$end) {
$endSlice= clone $end;
}
$seconds = $endSlice->getTimestamp()-$current->getTimestamp();
$currentDay = $current->format("D");
if ($currentDay != 'Sat' && $currentDay != 'Sun') {
$sum+=$seconds;
}
$current = $endSlice;
}
return $sum;
}
/**
* Getting the Weekdays count[ Excludes : Weekends]
*
* #param type $fromDateTimestamp
* #param type $toDateTimestamp
* #return int
*/
public static function getWeekDaysCount($fromDateTimestamp = null, $toDateTimestamp=null) {
$startDateString = date('Y-m-d', $fromDateTimestamp);
$timestampTomorrow = strtotime('+1 day', $toDateTimestamp);
$endDateString = date("Y-m-d", $timestampTomorrow);
$objStartDate = new \DateTime($startDateString); //intialize start date
$objEndDate = new \DateTime($endDateString); //initialize end date
$interval = new \DateInterval('P1D'); // set the interval as 1 day
$dateRange = new \DatePeriod($objStartDate, $interval, $objEndDate);
$count = 0;
foreach ($dateRange as $eachDate) {
if ( $eachDate->format("w") != 6
&& $eachDate->format("w") != 0
) {
++$count;
}
}
return $count;
}
Kindly have a look at this precise php function returning days count with weekends excluded.
function Count_Days_Without_Weekends($start, $end){
$days_diff = floor(((abs(strtotime($end) - strtotime($start))) / (60*60*24)));
$run_days=0;
for($i=0; $i<=$days_diff; $i++){
$newdays = $i-$days_diff;
$futuredate = strtotime("$newdays days");
$mydate = date("F d, Y", $futuredate);
$today = date("D", strtotime($mydate));
if(($today != "Sat") && ($today != "Sun")){
$run_days++;
}
}
return $run_days;
}
Try it out, it really works..
A very simple solution using Carbon\Caborn
here is the repository file which is called from a controller store function
<?php
namespace App\Repositories\Leave;
use App\Models\Holiday;
use App\Models\LeaveApplication;
use App\Repositories\BaseRepository;
use Carbon\Carbon;
class LeaveApplicationRepository extends BaseRepository
{
protected $holiday;
public function __construct(LeaveApplication $model, Holiday $holiday)
{
parent::__construct($model);
$this->holiday = $holiday;
}
/**
* Get all authenticated user leave
*/
public function getUserLeave($id)
{
return $this->model->where('employee_id',$id)->with(['leave_type','approver'])->get();
}
/**
* #param array $request
*/
public function create($request)
{
$request['total_days'] = $this->getTotalDays($request['start_date'],$request['end_date']);
return $this->model->create($request->only('send_to','leave_type_id','start_date','end_date','desc','total_days'));
}
/**
* Get total leave days
*/
private function getTotalDays($startDate, $endDate)
{
$holidays = $this->getHolidays(); //Get all public holidays
$leaveDays = 0; //Declare values which hold leave days
//Format the dates
$startDate = Carbon::createFromFormat('Y-m-d',$startDate);
$endEnd = Carbon::createFromFormat('Y-m-d',$endDate);
//Check user dates
for($date = $startDate; $date <= $endEnd; $date->modify('+1 day')) {
if (!$date->isWeekend() && !in_array($date,$holidays)) {
$leaveDays++; //Increment days if not weekend and public holidays
}
}
return $leaveDays; //return total days
}
/**
* Get Current Year Public Holidays
*/
private function getHolidays()
{
$holidays = array();
$dates = $this->holiday->select('date')->where('active',1)->get();
foreach ($dates as $date) {
$holidays[]=Carbon::createFromFormat('Y-m-d',$date->date);
}
return $holidays;
}
}
Controller function receives user input request and validate before call the repository function
<?php
namespace App\Http\Controllers\Leave;
use App\Http\Controllers\AuthController;
use App\Http\Requests\Leave\LeaveApplicationRequest;
use App\Repositories\Leave\LeaveApplicationRepository;
use Exception;
class LeaveApplicationController extends AuthController
{
protected $leaveApplication;
/**
* LeaveApplicationsController constructor.
*/
public function __construct(LeaveApplicationRepository $leaveApplication)
{
parent::__construct();
$this->leaveApplication = $leaveApplication;
}
/**
* Store a newly created resource in storage.
*/
public function store(LeaveApplicationRequest $request)
{
try {
$this->leaveApplication->create($request);
return $this->successRoute('leaveApplications.index','Leave Applied');
}
catch (Exception $e) {
return $this->errorWithInput($request);
}
}
}
Here's an alternative to calculate business days between two dates and also excludes USA holidays using Pear's Date_Holidays from http://pear.php.net/package/Date_Holidays.
$start_date and $end_date should be DateTime objects (you can use new DateTime('#'.$timestamp) to convert from timestamp to DateTime object).
<?php
function business_days($start_date, $end_date)
{
require_once 'Date/Holidays.php';
$dholidays = &Date_Holidays::factory('USA');
$days = 0;
$period = new DatePeriod($start_date, new DateInterval('P1D'), $end_date);
foreach($period as $dt)
{
$curr = $dt->format('D');
if($curr != 'Sat' && $curr != 'Sun' && !$dholidays->isHoliday($dt->format('Y-m-d')))
{
$days++;
}
}
return $days;
}
?>
Need some logic here:
Need to get day of month date("d")
What I know:
$year = 2013;
$month = 10;
$week_nr_of_month = 3; // from 1 to 6 weeks in month
$day_of_week = 0; // Sunday date("w")
Thanks for logic
Result must be: 13 October
This was fun to figure out.
<?php
$year = 2013;
$month = 10;
$week_nr_of_month = 3; // from 1 to 6 weeks in month
$day_of_week = 0; // Sunday date("w")
$start = new DateTime();
$start->setDate($year, $month, '1');
$end = clone $start;
$end->modify('last day of this month');
$interval = new DateInterval('P1D');
$period = new DatePeriod($start, $interval, $end);
foreach ($period as $date) {
if ($date->format('w') == $day_of_week) {
$wom = week_of_month($date->format('Y-m-d'));
if ($week_nr_of_month == $wom) {
echo $date->format('Y-m-d');
}
}
}
function week_of_month($date) {
$dt = new DateTime($date);
$bg = clone $dt;
$bg->modify('first day of this month');
$day_of_first = $bg->format('N');
$day_of_month = $dt->format('j');
return floor(($day_of_first + $day_of_month - 1) / 7) + 1;
}
See it in action
Used this answer for inspiration to get the week number for the date.
strtotime may be of help. Can't test right now, but...
$ordinal = array("first","second","third","fourth","fifth");
$weekdays = array("monday","tuesday","wednesday","thursday","friday","saturday","sunday");
$timestamp = strtotime($year."-".$month." ".$ordinal[$week_nr_of_month]." ".$weekdays[$day_of_week]);
I need to get the next 7 (or more) dates except sunday. Firstly i did it like
$end_date = new DateTime();
$end_date->add(new DateInterval('P7D'));
$period = new DatePeriod(
new DateTime(),
new DateInterval('P1D'),
$end_date
);
And after checked $period in foreach. But then i noticed that if i remove Sunday i need to add one more day to the end and this is each time when Sunday is... Is there any way to do it?
$start = new DateTime('');
$end = new DateTime('+7 days');
$interval = new DateInterval('P1D');
$period = new DatePeriod($start, $interval, $end);
foreach ($period as $dt) {
if ($dt->format("N") === 7) {
$end->add(new DateInterval('P1D'));
}
else {
echo $dt->format("l Y-m-d") . PHP_EOL;
}
}
See it in action
I'm a fan of using iterators, to keep the actual loop as simple as possible.
$days_wanted = 7;
$base_period = new DatePeriod(
new DateTime(),
new DateInterval('P1D'),
ceil($days_wanted * (8 / 7)) // Enough recurrences to exclude Sundays
);
// PHP >= 5.4.0 (lower versions can have their own FilterIterator here)
$no_sundays = new CallbackFilterIterator(
new IteratorIterator($base_period),
function ($date) {
return $date->format('D') !== 'Sun';
}
);
$period_without_sundays = new LimitIterator($no_sundays, 0, $days_wanted);
foreach ($period_without_sundays as $day) {
echo $day->format('D Y-m-d') . PHP_EOL;
}
You cannot remove days from a DatePeriod, but you can simply keep a count of non-Sundays and keep iterating until you have accumulated 7 of them:
$date = new DateTime();
for ($days = 0; $days < 7; $date->modify('+1 day')) {
if ($date->format('w') == 0) {
// it's a Sunday, skip it
continue;
}
++$days;
echo $date->format('Y-m-d')."\n";
}
You can try using UNIX time, adding day and if day is Sunday, add another one.
First day of your list will be eg. today at 12:00. Than you add 24 * 60 * 60 to get next day, and so on. Convert UNIX to day is simple, use date() function.
$actDay = time();
$daysCount = 0;
while(true)
{
if (date("D", $actDay) != "Sun")
{
//do something with day
$daysCount++;
}
if ($daysCount >= LIMIT) break;
$actDay += 24 * 60 * 60;
}
This question already has answers here:
PHP: Return all dates between two dates in an array [duplicate]
(26 answers)
Closed 4 years ago.
<?php
$start=date('2013-05-02');
$end=date('2013-05-06');
?>
I got out put like following,I don't know how to get this please help me
Thursday 2013-05-02
Friday 2013-05-03
Saturday 2013-05-04
Sunday 2013-05-05
Monday 2013-05-06
$start = new DateTime('2013-5-02');
$end = new DateTime('2013-6-02');
$interval = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($start, $interval, $end);
foreach ($period as $dt)
{
echo $dt->format("l Y-m-d");
echo "<br>";
}
Note[it's support only Above 5.3.0 php version]
Adapting the answer found here you can quite easily do this.
function createDateRangeArray($strDateFrom,$strDateTo)
{
// takes two dates formatted as YYYY-MM-DD and creates an
// inclusive array of the dates between the from and to dates.
// could test validity of dates here but I'm already doing
// that in the main script
$aryRange=array();
$iDateFrom=mktime(1,0,0,substr($strDateFrom,5,2), substr($strDateFrom,8,2),substr($strDateFrom,0,4));
$iDateTo=mktime(1,0,0,substr($strDateTo,5,2), substr($strDateTo,8,2),substr($strDateTo,0,4));
if ($iDateTo>=$iDateFrom)
{
array_push($aryRange,date('Y-m-d',$iDateFrom)); // first entry
while ($iDateFrom<$iDateTo)
{
$iDateFrom+=86400; // add 24 hours
array_push($aryRange,date('l Y-m-d',$iDateFrom));
}
}
return $aryRange;
}
$start=date('2013-05-02');
$end=date('2013-05-06');
echo '<pre>'.print_r(createDateRangeArray($start, $end), 1).'</pre>';
This will work for you
<?php
function dateRange($start, $end) {
date_default_timezone_set('UTC');
$diff = strtotime($end) - strtotime($start);
$daysBetween = floor($diff/(60*60*24));
$formattedDates = array();
for ($i = 0; $i <= $daysBetween; $i++) {
$tmpDate = date('Y-m-d', strtotime($start . " + $i days"));
$formattedDates[] = date('l Y-m-d', strtotime($tmpDate));
}
return $formattedDates;
}
$start='2013-05-02';
$end='2013-05-06';
$formattedDates = dateRange($start, $end);
echo join(', ', $formattedDates);
// => Thursday 2013-05-02, Friday 2013-05-03, Saturday 2013-05-04, Sunday 2013-05-05, Monday 2013-05-06
Check this out,
<?php
$from_date = strtotime("2013-05-02");
$to_date = strtotime("2013-08-02");
for ($current_date = $from_date; $current_date <= $to_date; $current_date += (60 * 60 * 24)) { // looping for avvailable dates
// use date() and $currentDateTS to format the dates in between
$date = date("Y-m-d",$current_date);
$day_name = getdate($current_date) ;
$day_name = $day_name['weekday'];
echo $date." ".$day_name."<br>";
}
?>
Given the following dates:
6/30/2010 - 7/6/2010
and a static variable:
$h = 7.5
I need to create an array like:
Array ( [2010-06-30] => 7.5 [2010-07-01] => 7.5 => [2010-07-02] => 7.5 => [2010-07-05] => 7.5 => [2010-07-06] => 7.5)
Weekend days excluded.
No, it's not homework...for some reason I just can't think straight today.
For PHP >= 5.3.0, use the DatePeriod class. It's unfortunately barely documented.
$start = new DateTime('6/30/2010');
$end = new DateTime('7/6/2010');
$oneday = new DateInterval("P1D");
$days = array();
$data = "7.5";
/* Iterate from $start up to $end+1 day, one day in each iteration.
We add one day to the $end date, because the DatePeriod only iterates up to,
not including, the end date. */
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")] = $data;
}
}
print_r($days);
The simplest method:
$start = strtotime('6/30/2010');
$end = strtotime('7/6/2010');
$result = array();
while ($start <= $end) {
if (date('N', $start) <= 5) {
$current = date('m/d/Y', $start);
$result[$current] = 7.5;
}
$start += 86400;
}
print_r($result);
UPDATE: Forgot to skip weekends. This should work now.
This is gnud's answer but as a function (also added an option to exclude the current day from the calculation):
(examples below)
public function getNumberOfDays($startDate, $endDate, $hoursPerDay="7.5", $excludeToday=true)
{
// d/m/Y
$start = new DateTime($startDate);
$end = new DateTime($endDate);
$oneday = new DateInterval("P1D");
$days = array();
/* Iterate from $start up to $end+1 day, one day in each iteration.
We add one day to the $end date, because the DatePeriod only iterates up to,
not including, the end date. */
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")] = $hoursPerDay;
}
}
if ($excludeToday)
array_pop ($days);
return $days;
}
And to use it:
$date1 = "2012-01-12";
$date2 = date('Y-m-d'); //today's date
$daysArray = getNumberOfDays($date1, $date2);
echo 'hours: ' . array_sum($daysArray);
echo 'days: ' . count($daysArray);
This is OOP approach, just in case. It returns an array with all of dates, except the weekends days.
class Date{
public function getIntervalBetweenTwoDates($startDate, $endDate){
$period = new DatePeriod(
new DateTime($startDate),
new DateInterval('P1D'),
new DateTime($endDate)
);
$all_days = array();$i = 0;
foreach($period as $date) {
if ($this->isWeekend($date->format('Y-m-d'))){
$all_days[$i] = $date->format('Y-m-d');
$i++;
}
}
return $all_days;
}
public function isWeekend($date) {
$weekDay = date('w', strtotime($date));
if (($weekDay == 0 || $weekDay == 6)){
return false;
}else{
return true;
}
}
}
$d = new Date();
var_dump($d->getIntervalBetweenTwoDates('2015-08-01','2015-08-08'));