Calculate end date pushing date forward if there is a holiday - php

I have written some code where I have a start date and number of days duration and then get an end date ie start date 18th December, duration 21 days, end date 8th January. However I want to push the end date forward to avoid certain holidays (25th December through to 6th January) so that the end date becomes 15th January. All the answers I have seen include how to calculate business days and take out weekends, which I don't need. I just want to be able to define specific holidays in an array, get it to see if the holiday is within the start date and end date and if it is move the end date forward by that number of days.
Oh, then the date needs to be inserted into a database. Thanks.

Iterate through the $holidays array. If a holiday is in the given range, then move end date one day in the future:
$startDate = new DateTime('2015-12-18');
$endDate = new DateTime('2016-01-08');
// $holidays array must be sorted. if not, then sort it first
$holidays = array("2015-12-25","2015-12-26","2016-01-01");
$newEndDate = $endDate;
foreach ($holidays as $holiday) {
$holidayDate = new DateTime($holiday);
if ($startDate <= $holidayDate && $holidayDate <= $newEndDate) {
// there is a holiday in the range
$newEndDate->add(new DateInterval('P1D'));
}
}
echo($newEndDate->format('Y-m-d'));

Thank you for all those that posted possible solutions. I solved the problem by adding a selector to the php page which adds 7, 14 or 21 days to the end date (the user sees this as 1 week, 2 weeks etc) and this solved the problem.

Related

PHP: How calculate calendar days with all 42 days

The goal is exclusively to get a range of days, in other words
, start date and end date, as if it were a "calendar matrix", containing the 42 days, being the days of the current month, with the days of the previous month and next month. No need to present (render) a calendar, only get dates.
For example, follow image below.
I need to enter a certain month of a given year, and would need to get this range of days, as picture.
Using PHP Carbon, I easily get the days of the current month, using startOfMonth(), endOfMonth() , subMonth(), addMonth().
Doing this, I get every day of these 3 months, but the goal is to be able to "filter" these days to present only the interval equal to a calendar, but obviously something dynamic, ie, if I use Carbon, would simply inform the desired date , and get "filtered" range, respecting the position of each "cell".
$prev_start = Carbon::now()->subMonth()->startOfMonth();
$prev_end = Carbon::now()->subMonth()->endOfMonth();
$start = Carbon::now()->startOfMonth();
$end = Carbon::now()->endOfMonth();
$next_start = Carbon::now()->addMonth()->startOfMonth();
$next_end = Carbon::now()->addMonth()->endOfMonth();
So here's what you can do:
$monthStart = Carbon::now()->startOfMonth();
$monthEnd = Carbon::now()->endOfMonth();
$calendarStart = $monthStart->startOfWeek(Carbon::SUNDAY);
$calendarEnd = $monthEnd->endOfWeek(Carbon::SATURDAY);
$calendarStart and $calendarEnd should now contain the first and last day that will be displayed in a single screen. This assumes that the calendar will expand the first and last week displayed.
If you are using a calendar that always shows 42 days regardless you can just do:
$monthStart = Carbon::now()->startOfMonth();
$calendarStart = $monthStart->startOfWeek(Carbon::SUNDAY);
$calendarEnd = $calendarStart->addDay(42);

I get an specific day from relative date and also the last day of the relative date, how can I find the difference?

$result = DB::table('customer')->where('isp',2)->get();
// start_date is stored date in database
$date= $result->start_date;
$dts = Carbon::create($date);
// in order to get the last day of relative month
// get the last day of month for instance is equal to 2010-09-30 00:00:00
// find the difference between in days
}
When I use from diffindays of Laravel the output is 0. Any ideas why?

Carbon get month by number returns march for number 2

Has anyone ever had this bug before, or know a way to fix it?
I want to get a list of all months in the current year (start date and end date) in an array, so i'm doing like this (open to suggestions for cleaner easier ways)
//Create a months array
$months = [];
//Get start and end of all months
for($i = 1; $i <= 12; $i++){
$array = [];
$array['start'] = Carbon::create()->month($i)->startOfMonth()->format('d/m/y');
$array['end'] = Carbon::create()->month($i)->endOfMonth()->format('d/m/y');
array_push($months, $array);
}
Which produces this result
As you can see, its looped and retrieved the months, but notice that it skips February completely and adds March twice.
If I manually run and return this code
return Carbon::create()->month(2)->startOfMonth()->format('d/m/y');
It returns 01/03/2018.
Why does carbon print out March for month 2? Has anyone ever had this issue before or know of a way to fix it?
Carbon::create()->month(2) will first create today's date, and then set the month to 2, but keep the other values. Because today's date is the 29th of August, the date ends up referring to the 29th of February, which (this year at least) doesn't exist. PHP rolls these "fake" dates over into the next month, so February 29th becomes March 1st.
If you explicitly set the day of the month first, this should work as expected:
Carbon::create()->day(1)->month($i);
(Also, if you'd tried this yesterday it would have worked fine, and you might never have noticed the bug. If you tried it tomorrow, you would have ended up with March 2nd and probably noticed it a lot faster. Dates are great fun.)
Figured this out whilst commenting on a suggested answer.
Its because todays date is 29th August 2018, and there are not 29 days in February.
Basically Carbon is creating an instance from todays date with Carbon::create() but then when using ->month(2) will try to get the 29th Feb and error. It needs to work from the first of the month so change it to
Carbon::create()->startOfMonth()->month($i)->startOfMonth()->format('d/m/y');
So it references from the 1st of the month and it will work as expected.
Pure PHP is enough for this:
$datePeriod = new \DatePeriod(
new \DateTimeImmutable(date('01-01-Y')),
new \DateInterval('P1M'),
new \DateTimeImmutable(date('31-12-Y'))
);
$dates = [];
foreach ($datePeriod as $date) {
$dates[] = [
'start' => $date->modify('first day of this month')->format('d/m/y'),
'end' => $date->modify('last day of this month')->format('d/m/y'),
];
}
It's 0 based by the looks. so month(0) would be January, 1 = February, etc.
Change your loop to
for($i = 0; $i < 12; $i++){
$array = [];
$array['start'] = Carbon::create()->month($i)->startOfMonth()->format('d/m/y');
$array['end'] = Carbon::create()->month($i)->endOfMonth()->format('d/m/y');
array_push($months, $array);
}

Next delivery date listed on website

I'm building a website for a business that makes deliveries every second Thursday. I need to display when the next delivery is going to be, and have that date change to two weeks forward when the previous delivery date is reached.
Based on what I've been able to research so far, I've cobbled together this code:
$start_date = '2016-10-27'; // next delivery date to start counting from
// create a DateTime object that represents start of sequence
$start_datetime = DateTime::createFromFormat('Y-m-d', $start_date);
// create a DateTime object representing the current date
$current_datetime = new DateTime('today');
$date_interval = new DateInterval('P2W'); // for delivery every 2 weeks
// determine end date for DatePeriod object that will later be used
// this is no further out than current date plus the interval
$end_datetime = new DateTime('tomorrow');
$end_datetime->add($date_interval);
$date_period = new DatePeriod($start_datetime, $date_interval, $end_datetime);
// iterate until the last date in the set
foreach($date_period as $dp) {
$next_delivery = $dp;
}
?>
<div class="header-next-delivery">
Next delivery: <?php echo $next_delivery->format('l, M j, Y'); ?>
</div>
This seems to work, but I can't help thinking that there must be a more elegant way to do this than having to iterate through a set of dates from the start date to the last date in the set. As time passes, the set will just get bigger and bigger.
Also, I'm having trouble figuring out the internal workings of these functions -- how would I set the exact time that the displayed delivery date bumps forward by two weeks?
Thanks for any insight!
You can get date interval in days from $start_date to current date. Divide it by 14 (two weeks), get remainder and substract it from 14. Then you can add that value of days to current date.
$start_date = date_create('2016-10-27');
$current_date = date_create();
$interval = date_diff($start_date, $current_date);
$days_diff = (int)$interval->format('%a');
$current_date->add(14 - ($days_diff % 14).' days');

php date/week problem

I'm kind of at a loss here. It seems as though somehow my code is missing a whole week at the end of 2009 and I've tried a couple different things.
My base function to get the start and end date for a week is below. Given a Year, Week and Day of the Week it gives you a date.
function datefromweeknr($aYear, $aWeek, $aDay)
{
$Days=array('xx','ma','di','wo','do','vr','za','zo');
//xx = Current Sun, ma = Mon ..... zo = Sun of the next Week
$DayOfWeek=array_search($aDay,$Days); //get day of week (1=Monday)
$DayOfWeekRef = date("w", mktime (0,0,0,1,4,$aYear)); //get day of week of January 4 (always week 1)
if ($DayOfWeekRef==0){
$DayOfWeekRef=7;
}
$ResultDate=mktime(0,0,0,1,4,$aYear)+((($aWeek-1)*7+($DayOfWeek-$DayOfWeekRef))*86400);
return $ResultDate;
}
Seemed to work completely fine until I realized that I was missing the week of December 27th 2009 to January 2nd 2010.
echo '<table border="1">';
for($i = 1; $i < 53; $i++){
if($i < 10){
$w = '0'.$i.'1';
}
else{
$w = $i.'1';
}
echo '<tr><td>Week#'.$i.' </td><td> '.date("Y-m-d",datefromweeknr(2009,$i,"xx")).' </td><td> '.date("Y-m-d",datefromweeknr(2009, $i,"za")).'</td><td> Week = '.date("W: Y-m-d",strtotime("2009W$w")).' </td></tr>';
}
echo '</table>';
It seems the 52nd week of the year ends on 2009-12-26 and the 1st week of the new year starts on 2010-01-03. I'm losing a whole week, No Bueno!
Anyone know what I'm doing wrong or can point me to a fool proof way of supplying a week number and a year to get me the start and end date of that week without losing any days in the process?
Check here:
http://www.onlineconversion.com/day_week_number.htm
If you enter 29 december 2009, so see that US and ISO/Europe give different week numbers (resp. 52 and 53).
Could this be related to your problem? Which standard do you dates conform too?
Edit:
From http://www.epochconverter.com/epoch/weeknumbers.php :
Week number according to the ISO-8601 standard, weeks starting on Monday. The first week of the year is the week that contains that year's first Thursday. The highest week number in a year is either 52 or 53.
Your question remainded me of a bug comment I read today on php.net:
In PHP 5 prior to 5.2.7, requesting a
given occurrence of a given weekday in
a month where that weekday was the
first day of the month would
incorrectly add one week to the
returned timestamp. This has been
corrected in 5.2.7 and later versions.
Which is irrevelent for now but I would suggest you to replace your calculations in datefromweeknr with strtotime calls. I'm pretty sure strtotime will fix your calculation bug.
So you could use something like:
strtotime('last Monday', $timestamp);

Categories