How to calculate date in PHP using variables - php

Can anyone help create this logic? Kind of difficult to explain...
Looking to take a date, add 3 days then select the next date based on a database value.
Say we start with:
$end_date = "2017-08-23 23:59:59"
$payday = 5; //1=monday, 2=tuesday, 3=wednesday, 4=thursday, 5=friday
//And we want to calculate $paydate:
$temp_date = $end_date + 3 days;
$pay_date = the first $payday(day of week) after $temp_date
Any ideas how to write this in php? This one is stumping me. Thanks!

To add three days you can do this:
$date = new DateTime('2017-08-23 23:59:59');
$date->add(new DateInterval('P3D'));
$date->modify("next friday");
echo $date->format('Y-m-d') . "\n";
You could also use a lookup table, or array, that matches number to named days of the week and use something like $date->modify("next $days[$payday]");
where
$days = [ [1] => "monday",
.... etc

How about this? It will get a date, add 3 days, and then loop through the next days until it finds a day in the $days array (which you can get from a database):
<?php
$date = new DateTime('2017-08-23 23:59:59');
function nextPayday($date) {
$date->add(new DateInterval('P3D'));
echo "Date + 3 days: ".$date->format('D Y-m-d') . "<br>";
$payDate = $date->add(new DateInterval('P1D'));
$days = ["1", "2", "3", "4", "5"];
while (!in_array($payDate->format("N"), $days)) {
$payDate->add(new DateInterval('P1D'));
}
return $payDate->format("D Y-m-d");
}
echo "Date + 3 days: ".$date->format('D Y-m-d') . "<br>";
echo "Next payday: ".nextPayday($date);
Demo
Or, if you need to find a next specific day, use this function instead:
function nextPayday($date) {
$date->add(new DateInterval('P3D'));
echo "Date + 3 days: ".$date->format('D Y-m-d') . "<br>";
$payDate = $date->add(new DateInterval('P1D'));
$day = "5";
while ($payDate->format("N") !== $day) {
$payDate->add(new DateInterval('P1D'));
}
return $payDate->format("D Y-m-d");
}

Jeff, take a look at Carbon which extends PHP's DateTime object.
It allows you to deal with dates in a very clean and intuitive way. Based on your example:
$date = Carbon::parse('next monday')->toDateString();
Adjust that to your exact case.

Another version to achieve the objective:
function nextPayday($dateString, $paydayNum) {
$paydays = [
1=>'monday',
2=>'tuesday',
3=>'wednesday',
4=>'thursday',
5=>'friday'
];
$temp_date_stamp = date('d-m-Y H:i:s', strtotime($dateString.' +3 days'));
$pay_date_stamp = strtotime('first '.$paydays[$paydayNum].' '.$temp_date_stamp);
return date('d-m-Y H:i:s', $pay_date_stamp);
}
$end_date = "2017-08-23 23:59:59";
$payday = 5;
echo nextPayday($end_date, $payday);
result:
01-09-2017 23:59:59

Related

Adding 12 months to February 29

I want to add 12 months to my date. My start date is 02/29/2020 and I want to add 12 months to this.
Code:
$startdate = '02/29/2020';
date('m/d/Y', strtotime('+12 months', strtotime($startdate)));
Output:
03/01/2021
I used this code to add 12 months but the output is 03/01/2021, when the real output should be 02/28/2020.
Have a look!
function add_months($months, DateTime $dateObject)
{
$next = new DateTime($dateObject->format('Y-m-d'));
$next->modify('last day of +'.$months.' month');
if($dateObject->format('d') > $next->format('d')) {
return $dateObject->diff($next);
} else {
return new DateInterval('P'.$months.'M');
}
}
function getCalculatedDate($d1, $months)
{
$date = new DateTime($d1);
// call second function to add the months
$newDate = $date->add(add_months($months, $date));
//formats final date to m/d/Y form
$dateReturned = $newDate->format('m/d/Y');
return $dateReturned;
}
An example would be:-
$startDate = '02/29/2020';
$nMonths = 12; // choose how many months you want to add
$finalDate = getCalculatedDate($startDate, $nMonths); // output: 02/28/2021
This way you will get the output of 02/28/2021
$startdate = '02/29/2020';
$date = date('m/d/Y', strtotime($startdate . '+365 days'));
using DateTime and DateInterval objects leads to 03/01/2021
$date = new \DateTime('02/29/2020');
$date->add(new \DateInterval('P12M'));
echo $date->format('m/d/Y');
for me 03/01/2021 is not always a bad answer

PHP DateInterval

I have this function witch return an array of date. I need to jump on every seven days from now until last year.
$date[] = $lastDate = (new \DateTIme('NOW'))->format('Y-m-d');
for ($i = 1; $i < 54; ++$i) { // 54 -> number of weeks in a year
$date[] = $lastDate = date('Y-m-d', strtotime('-7 day', strtotime($lastDate)));
}
return array_reverse($date);
It works but I can do better.
I would like to change it because using 54 for the number of weeks in a year is not very good. (it can change)
So I want to use the DateInterval php class.
I can have the date of the last year with :
$lastYear = date('Y-m-d', strtotime('-1 year', strtotime($lastDate)));
But I don't know how I can have my array with all my dates with the DateInterval class.
Can someone help me? I'm very bad with date manipulation :( ...
Here is an example array about what I need:
["2015-07-06", "2015-07-13", "2015-07-20", "2015-07-27", "2015-08-03", "2015-08-10", "2015-08-17", "2015-08-24", "2015-08-31", "2015-09-07", "2015-09-14", "2015-09-21", "2015-09-28", "2015-10-05", "2015-10-12", "2015-10-19", "2015-10-26", "2015-11-02", "2015-11-09", "2015-11-16", "2015-11-23", "2015-11-30", "2015-12-07", "2015-12-14", "2015-12-21", "2015-12-28", "2016-01-04", "2016-01-11", "2016-01-18", "2016-01-25", "2016-02-01", "2016-02-08", "2016-02-15", "2016-02-22", "2016-02-29", "2016-03-07", "2016-03-14", "2016-03-21", "2016-03-28", "2016-04-04", "2016-04-11", "2016-04-18", "2016-04-25", "2016-05-02", "2016-05-09", "2016-05-16", "2016-05-23", "2016-05-30", "2016-06-06", "2016-06-13", "2016-06-20", "2016-06-27", "2016-07-04"]
PHP got it 's own native DateInterval object. Here 's a short example how to use it.
$oPeriodStart = new DateTime();
$oPeriodEnd = new DateTime('+12 months');
$oPeriod = new DatePeriod(
$oPeriodStart,
DateInterval::createFromDateString('7 days'),
$oPeriodEnd
);
foreach ($oPeriod as $oInterval) {
var_dump($oInterval->format('Y-m-d));
}
So what we 've done here? For a period of dates you need a start date, an end date and the interval. Just test it for yourself. Have fun.
Try this:
$timestamp = strtotime("last Sunday");
$sundays = array();
$last_year_timestamp = strtotime("-1 year ",$timestamp);
while($timestamp >= $last_year_timestamp) {
if (date("w", $timestamp) == 0) {
$sundays[] = date("Y-m-d", $timestamp);
$timestamp -= 86400*7;
continue;
}
$timestamp -= 86400;
}

last year, this year, next year with php DateTime

I am trying to create a dropbox that will display the last year, the current year and the next year using the php DateTime object.
In my current code I create three objects and have to call a method on 2 of them. This seems a bit heavy on the resources.
$today = new DateTime();
$last_year=new DateTime();
$last_year->sub(new DateInterval('P1Y'));
$next_year = new DateTime();
$next_year->add(new DateInterval('P1Y'));
echo date_format($last_year, 'Y').' '.date_format($today, 'Y').' '.date_format($next_year, 'Y');
another way I found to only use 1 object is
$today = new DateTime();
echo date_format($today->sub(new DateInterval('P1Y')), 'Y').' '.date_format($today->add(new DateInterval('P1Y')), 'Y').' '.date_format($today->add(new DateInterval('P1Y')), 'Y');
but that will become very confusing.
Can someone tell me a better way to do this using DateTime()? As I will need something similar for months ?
Depending upon your version of PHP (>= 5.4), you could tidy it up a bit like this:-
$today = new DateTime();
$last_year=(new DateTime())->sub(new DateInterval('P1Y'));
$next_year = (new DateTime())->add(new DateInterval('P1Y'));
echo $last_year->format('Y').' '.$today->format('Y').' '.$next_year->format('Y');
See it working.
A more readable and concise option may be to use \DateTimeImmutable.
$today = new DateTimeImmutable();
$one_year = new DateInterval('P1Y');
$last_year = $today->sub($one_year);
$next_year = $today->add($one_year);
echo $last_year->format('Y').' '.$today->format('Y').' '.$next_year->format('Y');
See it working.
Other than that, this all looks fine. Worry about optimisation when it is needed.
Try this. This quite efficient.
echo date("Y");
echo date("Y",strtotime("-1 year"));
echo date("Y",strtotime("+1 year"))
May be you can also limit the call of new DateInterval('P1Y') by creating one object and using it for all three calculations?
$interval = new DateInterval('P1Y');
$dateTime = new DateTime();
$lastYear = $dateTime->sub($interval)->format('Y');
$dateTime = new DateTime();
$nextYear = $dateTime->add($interval)->format('Y');
$dateTime = new DateTime();
$thisYear = $dateTime->format('Y');
echo $lastYear . ' ' . $thisYear . ' ' . $nextYear;
and by breaking the single string into multiple commands always helps me in reducing confusions.
<?php
$d = new DateTime('now');
$cy = $d->format('Y');
// Get previous year
$d->modify('-1 year');
$py = $d->format('Y');
//Next year : Since object has previous year, so +2 to get next year
$d->modify('+2 year');
$ny = $d->format('Y');
echo "Previous Year: ".$py."<br>";
echo "Current Year : ".$cy."<br>";
echo "Next Year : ".$ny."<br>";
$d = new DateTime('now');
$cm = $d->format('m');
$d->modify('-1 month');
$pm = $d->format('m');
$d->modify('+2 month');
$nm = $d->format('m');
echo "Previous Month: ".$pm."<br>";
echo "Current Month : ".$cm."<br>";
echo "Next Month : ".$nm."<br>";
?>
Output
Previous Year: 2013
Current Year : 2014
Next Year : 2015
Previous Month: 12
Current Month : 01
Next Month : 02
Just use basic math:
$current = date('Y');
$prev = $current - 1;
$next = $current + 1;
after reading all the answers I came up with this function to create a dropdown box for year.
$name is the name of the
$year_number is the number of years you want to display
this function starts with one year before the current year but you can easily modify it to start displaying from earlier years.
function drop_down_box_date_year(&$dbconn, $name, $year_number){
$today = new DateTime();
$interval = new DateInterval('P1Y');
$startyear = (new DateTime())->sub($interval);
echo '<select name="'.$name.'_year">';
for($i=0;$i<$year_number;$i++){
if($startyear->format('Y')==$today->format('Y')){
echo '<option value="'.$startyear->format('Y').'" selected>'.$startyear->format('Y').'</option>';
}else{
echo '<option value="'.$startyear->format('Y').'">'.$startyear->format('Y').'</option>';
}
$startyear->add($interval);
}
echo'</select>';
}

Need to add number of months in date

I need a method for adding some number of months to any date in PHP. I know how to do this in MySQL but not in PHP. Here's my attempt:
MySQL:
SELECT DATE_ADD( '2011-12-29', INTERVAL 2
MONTH ) // Output "2012-02-29"
SELECT DATE_ADD( '2011-12-30', INTERVAL 2
MONTH ) // output "2012-02-29"
SELECT DATE_ADD( '2011-12-31', INTERVAL 2
MONTH ) // output "2012-02-29"
PHP:
$date = date_create('2011-12-29');
$date->modify("+1 month");
echo $date->format("Y-m-d");
// Output is "2012-01-29" -- this is correct
$date = date_create('2011-12-30');
$date->modify("+2 month");
echo $date->format("Y-m-d");
// Output is "2012-03-01" -- I need the answer like "2012-02-29"
$date = date_create('2011-12-31');
$date->modify("+2 month");
echo $date->format("Y-m-d");
// Output is "2012-03-02" -- I need the answer like "2012-02-29"
The MySQL output is correct. I need the same output in PHP.
If you use PHP5 >= 5.3, all you need to do is use
$date->modify("last day of +2 months");
as suggested in other answers. But if you use 5.2 you could try altering your code like this:
Class DateTimeM Extends DateTime
{
public function modify ($modify)
{
$day = $this->format ('d');
$buf = new DateTime ($this->format ('Y-m-01\TH:i:sO'));
$buf->modify ($modify);
if ($day > $buf->format ('t'))
{
$this->setDate ($buf->format ('Y'), $buf->format ('m'), $buf->format ('t'));
}
else
{
$this->setDate ($buf->format ('Y'), $buf->format ('m'), $day);
}
$this->setTime ($buf->format ('H'), $buf->format ('i'), $buf->format ('s'));
return $this;
}
}
$date = new DateTimeM ('2011-12-29');
$date->modify("+2 month");
echo $date->format("Y-m-d");
I suggest adding the class definition to a separate file and require_once() it. Switch from date_create() to using the new class's object constructor. The new class's modify() method will modify the date using the first day of the original given month instead of the last and check if the original given day of month is larger than the new month's number of days.
A benefit of this approach is that it will work for say $date->modify ('2 year 2 month') as well.
Here's a solution that might do the job for you:
function addMonths(DateTime $date, $months) {
$last = clone $date;
$last = $last->modify("last day of +$months months")->getTimestamp();
$default = clone $date;
$default = $default->modify("+$months months")->getTimestamp();
return $date->setTimestamp(min($last, $default));
}
$date = new DateTime('2011-12-31');
$laterDate = addMonths($date, 2);
This will work regardless of which day of the month you start with.
Hope it surely helps you.
I just try with adding days instead of adding months
$MonthAdded = strtotime("+60 days",strtotime('2011-12-31'));
echo "After adding month: ".date('Y-m-d', $MonthAdded)."<br>";
Output:
After adding month: 2012-02-29
Read the link Dagon posted in the comments to your question. Extrapolating on the answer there, I tried this and it works:
$d = new DateTime("2011-12-31");
$d->modify("last day of +2 months");
echo $d->format("Y-m-d");
// result is 2012-02-29
$d = new DateTime("2012-12-31");
$d->modify("last day of +2 months");
echo $d->format("Y-m-d");
// result is 2013-02-28

Next business day of given date in PHP

Does anyone have a PHP snippet to calculate the next business day for a given date?
How does, for example, YYYY-MM-DD need to be converted to find out the next business day?
Example:
For 03.04.2011 (DD-MM-YYYY) the next business day is 04.04.2011.
For 08.04.2011 the next business day is 11.04.2011.
This is the variable containing the date I need to know the next business day for
$cubeTime['time'];
Variable contains: 2011-04-01
result of the snippet should be: 2011-04-04
Next Weekday
This finds the next weekday from a specific date (not including Saturday or Sunday):
echo date('Y-m-d', strtotime('2011-04-05 +1 Weekday'));
You could also do it with a date variable of course:
$myDate = '2011-04-05';
echo date('Y-m-d', strtotime($myDate . ' +1 Weekday'));
UPDATE: Or, if you have access to PHP's DateTime class (very likely):
$date = new DateTime('2018-01-27');
$date->modify('+7 weekday');
echo $date->format('Y-m-d');
Want to Skip Holidays?:
Although the original poster mentioned "I don't need to consider holidays", if you DO happen to want to ignore holidays, just remember - "Holidays" is just an array of whatever dates you don't want to include and differs by country, region, company, person...etc.
Simply put the above code into a function that excludes/loops past the dates you don't want included. Something like this:
$tmpDate = '2015-06-22';
$holidays = ['2015-07-04', '2015-10-31', '2015-12-25'];
$i = 1;
$nextBusinessDay = date('Y-m-d', strtotime($tmpDate . ' +' . $i . ' Weekday'));
while (in_array($nextBusinessDay, $holidays)) {
$i++;
$nextBusinessDay = date('Y-m-d', strtotime($tmpDate . ' +' . $i . ' Weekday'));
}
I'm sure the above code can be simplified or shortened if you want. I tried to write it in an easy-to-understand way.
For UK holidays you can use
https://www.gov.uk/bank-holidays#england-and-wales
The ICS format data is easy to parse. My suggestion is...
# $date must be in YYYY-MM-DD format
# You can pass in either an array of holidays in YYYYMMDD format
# OR a URL for a .ics file containing holidays
# this defaults to the UK government holiday data for England and Wales
function addBusinessDays($date,$numDays=1,$holidays='') {
if ($holidays==='') $holidays = 'https://www.gov.uk/bank-holidays/england-and-wales.ics';
if (!is_array($holidays)) {
$ch = curl_init($holidays);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
$ics = curl_exec($ch);
curl_close($ch);
$ics = explode("\n",$ics);
$ics = preg_grep('/^DTSTART;/',$ics);
$holidays = preg_replace('/^DTSTART;VALUE=DATE:(\\d{4})(\\d{2})(\\d{2}).*/s','$1-$2-$3',$ics);
}
$addDay = 0;
while ($numDays--) {
while (true) {
$addDay++;
$newDate = date('Y-m-d', strtotime("$date +$addDay Days"));
$newDayOfWeek = date('w', strtotime($newDate));
if ( $newDayOfWeek>0 && $newDayOfWeek<6 && !in_array($newDate,$holidays)) break;
}
}
return $newDate;
}
function next_business_day($date) {
$add_day = 0;
do {
$add_day++;
$new_date = date('Y-m-d', strtotime("$date +$add_day Days"));
$new_day_of_week = date('w', strtotime($new_date));
} while($new_day_of_week == 6 || $new_day_of_week == 0);
return $new_date;
}
This function should ignore weekends (6 = Saturday and 0 = Sunday).
This function will calculate the business day in the future or past. Arguments are number of days, forward (1) or backwards(0), and a date. If no date is supplied todays date will be used:
// returned $date Y/m/d
function work_days_from_date($days, $forward, $date=NULL)
{
if(!$date)
{
$date = date('Y-m-d'); // if no date given, use todays date
}
while ($days != 0)
{
$forward == 1 ? $day = strtotime($date.' +1 day') : $day = strtotime($date.' -1 day');
$date = date('Y-m-d',$day);
if( date('N', strtotime($date)) <= 5) // if it's a weekday
{
$days--;
}
}
return $date;
}
What you need to do is:
Convert the provided date into a timestamp.
Use this along with the or w or N formatters for PHP's date command to tell you what day of the week it is.
If it isn't a "business day", you can then increment the timestamp by a day (86400 seconds) and check again until you hit a business day.
N.B.: For this is really work, you'd also need to exclude any bank or public holidays, etc.
I stumbled apon this thread when I was working on a Danish website where I needed to code a "Next day delivery" PHP script.
Here is what I came up with (This will display the name of the next working day in Danish, and the next working + 1 if current time is more than a given limit)
$day["Mon"] = "Mandag";
$day["Tue"] = "Tirsdag";
$day["Wed"] = "Onsdag";
$day["Thu"] = "Torsdag";
$day["Fri"] = "Fredag";
$day["Sat"] = "Lørdag";
$day["Sun"] = "Søndag";
date_default_timezone_set('Europe/Copenhagen');
$date = date('l');
$checkTime = '1400';
$date2 = date(strtotime($date.' +1 Weekday'));
if( date( 'Hi' ) >= $checkTime) {
$date2 = date(strtotime($date.' +2 Weekday'));
}
if (date('l') == 'Saturday'){
$date2 = date(strtotime($date.' +2 Weekday'));
}
if (date('l') == 'Sunday') {
$date2 = date(strtotime($date.' +2 Weekday'));
}
echo '<p>Næste levering: <span>'.$day[date("D", $date2)].'</span></p>';
As you can see in the sample code $checkTime is where I set the time limit which determines if the next day delivery will be +1 working day or +2 working days.
'1400' = 14:00 hours
I know that the if statements can be made more compressed, but I show my code for people to easily understand the way it works.
I hope someone out there can use this little snippet.
Here is the best way to get business days (Mon-Fri) in PHP.
function days()
{
$week=array();
$weekday=["Monday","Tuesday","Wednesday","Thursday","Friday"];
foreach ($weekday as $key => $value)
{
$sort=$value." this week";
$day=date('D', strtotime($sort));
$date=date('d', strtotime($sort));
$year=date('Y-m-d', strtotime($sort));
$weeks['day']= $day;
$weeks['date']= $date;
$weeks['year']= $year;
$week[]=$weeks;
}
return $week;
}
Hope this will help you guys.
Thanks,.
See the example 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);
foreach($daterange as $date){
if($date->format("N") <6 AND !in_array($date->format("Y-m-d"),$holiday))
$result[] = $date->format("Y-m-d");
}
echo "<pre>";print_r($result);
For more info: http://goo.gl/YOsfPX
You could do something like this.
/**
* #param string $date
* #param DateTimeZone|null|null $DateTimeZone
* #return \NavigableDate\NavigableDateInterface
*/
function getNextBusinessDay(string $date, ? DateTimeZone $DateTimeZone = null):\NavigableDate\NavigableDateInterface
{
$Date = \NavigableDate\NavigableDateFacade::create($date, $DateTimeZone);
$NextDay = $Date->nextDay();
while(true)
{
$nextDayIndexInTheWeek = (int) $NextDay->format('N');
// check if the day is between Monday and Friday. In DateTime class php, Monday is 1 and Friday is 5
if ($nextDayIndexInTheWeek >= 1 && $nextDayIndexInTheWeek <= 5)
{
break;
}
$NextDay = $NextDay->nextDay();
}
return $NextDay;
}
$date = '2017-02-24';
$NextBussinessDay = getNextBusinessDay($date);
var_dump($NextBussinessDay->format('Y-m-d'));
Output:
string(10) "2017-02-27"
\NavigableDate\NavigableDateFacade::create($date, $DateTimeZone), is provided by php library available at https://packagist.org/packages/ishworkh/navigable-date. You need to first include this library in your project with composer or direct download.
I used below methods in PHP, strtotime() does not work specially in leap year February month.
public static function nextWorkingDay($date, $addDays = 1)
{
if (strlen(trim($date)) <= 10) {
$date = trim($date)." 09:00:00";
}
$date = new DateTime($date);
//Add days
$date->add(new DateInterval('P'.$addDays.'D'));
while ($date->format('N') >= 5)
{
$date->add(new DateInterval('P1D'));
}
return $date->format('Y-m-d H:i:s');
}
This solution for 5 working days (you can change if you required for 6 or 4 days working). if you want to exclude more days like holidays then just check another condition in while loop.
//
while ($date->format('N') >= 5 && !in_array($date->format('Y-m-d'), self::holidayArray()))

Categories