Calculate weekdays between two date - php

I want to calculate how many days in a Weekday. But it return "Uncaught Error: Call to a member function add() on integer".
Here my code
$dateStart_convert = DateTime::createFromFormat("d/m/Y", $cuti_sdate);
$start = $dateStart_convert->getTimestamp();
$dateEnd_convert = DateTime::createFromFormat("d/m/Y", $cuti_edate);
$end = $dateEnd_convert->getTimestamp();
$oneday = new DateInterval("P1D");
$workdays = 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)
{
$workdays[] = $day->format("Y-m-d");
}
$weekday_date = array_merge(array_diff($workdays, $cuti_date));
$c_weekday = count($weekday_date);
}

use this :)
<?php
$start = new DateTime($startDate);
$end = new DateTime($endDate);
$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;
}
}
$weekdays = count($days);
?>

Related

Php get the timestamp values grouped by months

Suppose that i have
$time1 = 1492894800 //23/04/2017
$time2 = 1503521999 //23/08/2017
I would like to get timestamps grouped by months such that
get timestamp with rangess between months preserving first and last month of $time1 and $time2 such that i should have
1 23/04/2017 to 30/04/2017
2 01/05/2017 - 31/05/2017
....... //continue full months and lastly
01/08/2017 - 23/08/2017
i have tried
$timearrays = $this->getMontTimestampRanges($time1, $time2);
public function getMontTimestampRanges($ts1, $ts2){
$start = (new DateTime(date("Y-m-d", $ts1)));
$end = (new DateTime(date("Y-m-d", $ts2)));
$interval = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($start, $interval, $end);
$timestamps = [];
foreach ($period as $dt) {
//am stuck here on how to group based on the months
..push to array
}
return $timestamps;
}
so the final array i would like it to be of the form:
$timestamps = [
0=>["from":, "to": ] //first month(april)
1=>[ ] //second month may
]
How do i go about this?
After clarifying your query on my last answer, I have decided to delete my answer and post a new answer.
$start = 1492894800; //23/04/2017
$end = 1503521999; //23/08/2017
$steps = date('Ym', $end) - date('Ym', $start);
$timestamps = array();
for($i = 0; $i <= $steps; $i++) {
$base = strtotime("+{$i} months", $start);
$timestamps[] = array(
'from' => $i == 0 ? date('Y-m-d', $start) : date('Y-m-01', $base),
'to' => $i == $steps ? date('Y-m-d', $end) : date('Y-m-t', $base)
);
// If we want timestamps
// $timestamps[] = array(
// 'from' => strtotime(date('Y-m-01', $base)),
// 'to' => strtotime(date('Y-m-t', $base))
// );
}
print_r($timestamps);
Ideone link
I edited your code
Try this:
<?php
$time1 = 1492894800 ;//23/04/2017
$time2 = 1503521999; //23/08/2017
$timearrays = getMontTimestampRanges($time1, $time2);
var_dump( $timearrays);
function getMontTimestampRanges($ts1, $ts2){
$start = new DateTime(date("Y-m-d", $ts1));
$end = new DateTime(date("Y-m-d", $ts2));
$interval = DateInterval::createFromDateString('1 month');
$period = new DatePeriod($start, $interval, $end);
$timestamps = [];
$startM = $period->getStartDate()->format('m');
$endM = $period->getEndDate()->format('m');
foreach ($period as $dt) {
//am stuck here on how to group based on the months
//start
if($startM == $dt->format('m'))
{
$timestamps[] = array('start'=>$start->format('Y-m-d'),'end'=>$dt->format('Y-m-t'));
}
elseif($endM == $dt->format('m'))
{
$timestamps[] = array('start'=>$dt->format('Y-m').'-01','end'=>$end->format('Y-m-d') );
}
else
{
$timestamps[] = array('start'=>$dt->format('Y-m').'-01','end'=>$dt->format('Y-m-t'));
}
}
return $timestamps;
}
http://sandbox.onlinephpfunctions.com/code/8527e45427fd0114f1e058fffc1885e460807a0a
Hope it helps.

How can I calculate date weekend in php

I have a date like this
$start = strtotime('2010-01-01'); $end = strtotime('2010-01-25');
My question:
How can I calculate or count weekend from $start & $end date range..??
A more modern approach is using php's DateTime class. Below, you get an array with week numbers as keys. I added the counts of weeks and weekend days.
<?php
$begin = new DateTime('2010-01-01');
$end = new DateTime('2010-01-25');
$interval = new DateInterval('P1D');
$daterange = new DatePeriod($begin, $interval, $end);
$weekends = [];
foreach($daterange as $date) {
if (in_array($date->format('N'), [6,7])) {
$weekends[$date->format('W')][] = $date->format('Y-m-d');
}
}
print_r($weekends);
echo 'Number of weeks: ' . count($weekends);
echo 'Number of weekend days: ' . (count($weekends, COUNT_RECURSIVE) - count($weekends));
Note: if you're using PHP 5.3, use array() instead of block arrays [].
May be this code snippet will help:
<?php
//get current month for example
$beginday = date("Y-m-01");
$lastday = date("Y-m-t");
$nr_work_days = getWorkingDays($beginday, $lastday);
echo $nr_work_days;
function getWorkingDays($startDate, $endDate)
{
$begin = strtotime($startDate);
$end = strtotime($endDate);
if ($begin > $end) {
echo "startdate is in the future! <br />";
return 0;
} else {
$no_days = 0;
$weekends = 0;
while ($begin <= $end) {
$no_days++; // no of days in the given interval
$what_day = date("N", $begin);
if ($what_day > 5) { // 6 and 7 are weekend days
$weekends++;
};
$begin += 86400; // +1 day
};
$working_days = $no_days - $weekends;
return $working_days;
}
}
Another solution can be: (Get date range between two dates excluding weekends)
This might help maybe:
$start = strtotime('2010-01-01');
$end = strtotime('2010-01-25');
$differ = $end-$start;
$min = $differ/60;
$hrs = $min/60;
$days = $hrs/24;
$weeks = $days/7;
if(is_int($weeks))
$weeks++;
echo '<pre>';
print_r(ceil($weeks));
echo '</pre>';

How do I get the number of days between two dates excluding the weekend [duplicate]

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;
}
?>

How to get a day of month from "what I know"?

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]);

Get date range between two dates excluding weekends

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'));

Categories