How to find recursive dates in php or mysql? - php

I have a data like this:
$date = '01-01-2014';
$time = '15:20:00';
$location = 'New Delhi';
$recursive = '1';
.........................
......................... // other data
$recursive = 1 means weekly and 2 means monthly.
Now what i am tring to do is if recursive type is weekly then add 7 days into it till 3 months and if recursive type is monthly then add 1 month into it till 3 months.
Exa:1 $date = '01-01-2014' and $recursive = '1'
Means in above example $recursive is weekly, so get a recursive date for January, February and March.
So the expected results are:
01-01-2014, 08-01-2014, 15-01-2014, 22-01-2014, 29-01-2014 (recursiive date in january)
05-02-2014, 12-02-2014, 19-02-2014, 26-02-2014 (recursiive date in february)
05-03-2014, 12-03-2014, 19-03-2014, 26-03-2014 (recursiive date in march)
Exa 2: $date = 15-04-2014 and $recursive = 1 then get recursive date for April, May and June.
output:
15-04-2014,22-04-2014,29-04-2014 (recursive date in april)
06-05-2014,13-05-2014,20-05-2014,27-05-2014 (recursive date in may)
03-06-2014,10-06-2014,17-06-2014,24-06-2014 (recursive date in june)
Exa 3 : $date = 01-01-2014 and $recursive = 2 then get recursive date for April, May and June.
This is monthly recursive, means add 1 month into it.
output:
01-01-2014
01-02-2014 (recursiive date in february)
01-03-2014 (recursiive date in march)
then i want to insert these dates with other data into database table.
so how to achive above things? should i write logic in php or use mysql query for it?
Thanks in advance.
SIDENOTE: currently i am using this accepted answer. but now i am trying to change that.

so basically what you want to do is something like this.
//you have to have a default time zone set.. so i just did this you should already have it in your .ini file
date_default_timezone_set('America/Los_Angeles');
$date = '01-01-2014';
$time = '15:20:00';
$location = 'New Delhi';
$recursive = '1';
//set your start date and end date
$startdate = date_create($date);
$enddate = date_create($date);
$enddate = date_add($enddate,date_interval_create_from_date_string("3 months"));
//set the interval string
if($recursive == '1'){
$str = "7 days";
} else {
$str = "1 month";
}
function recursivefunc($str, $start, $end){
//if the start is equal or bigger than end pop out.
$s = date_format($start,"Y/m/d");
$e = date_format($end,"Y/m/d");
if(strtotime($s) >= strtotime($e)){
return 1;
}
echo date_format($start,"Y/m/d"), '<br>'; //print out the starting date for each loop
$newDate = date_add($start,date_interval_create_from_date_string($str)); //increment the start
recursiveFunc($str, $newDate, $end); //call the function again
}
recursiveFunc($str, $startdate, $enddate); // initial call to the function

This is how i solve it.
$date = '01-01-2014';
$location = 'New Delhi';
$start = strtotime("+2 months", strtotime($date)); //start date
$end_date = date("Y-m-t", $start); // last day of end month
$end = strtotime($end_date); //last date
/* if recursion type is weekly */
if($json['recurrence'] == "1")
{
for($dd=$start; $dd<=$end;)
{
$new_date = date('Y-m-d', $dd);
$data[] = array(
'date' => $new_date,
'location' => $location
);
$dd = strtotime("+7 day", $dd); // add 7 days
}
}
if($json['recurrence'] == "2")
{
for($dd=$start; $dd<=$end;)
{
$new_date = date('Y-m-d', $dd);
$data[] = array(
'date' => $new_date,
'location' => $location
);
$dd = strtotime("+1 month", $dd); //add 1 month
}
}
echo "<pre>";
print_r($data);

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

How to section a date period monthly

two dates 13-10-2017 and 13-02-2018. I want to separate this period in months like 13-10-2017 to 31-10-2-17, 01-11-2017 to 30-11-2017, 01-12-2017 to 31-12-2017, 01-01-2018 to 31-01-2018 and 01-02-2018 to 13-02-2018. What I did I can get the month names in the date period but not in the format I want.
Here is my code:
$start_date = new DateTime('13-10-2017');
$end_date = new DateTime('13-02-2018');
$date_interval = new DateInterval('P1M');
$date_period = new DatePeriod($start_date, $date_interval, $end_date);
# calculating number of days in the interval
$interval = $start_date->diff( $end_date );
$days = $interval->days;
# getting names of the months in the interval
$month_count = 0;
$month_names = array();
foreach ($date_period as $date) {
$month_names[] = $date->format('F');
$month_count++;
}
$month_name_string = implode(',', $month_names);
echo $start_date->format('d-m-Y').' to '.$end_date->format('d-m-Y'). ' is ' .$days.' days and month names are: '.$month_name_string;
The output I get :
13-10-2017 to 13-02-2018 is 123 days and month names are: October,November,December,January
You can, while iterating, do the following checks:
If the current month is in $start_date, use its day for the start date
If the current month is in $end_date, use its day for the last day
Else, use the 1 and maximum day of each month (using the t format character)
Also, you need to set the time to 00:00:01 in the final day in order to have it considered in the DateInterval:
<?php
$start_date = new DateTime('13-10-2017');
$end_date = new DateTime('13-02-2018');
$end_date->setTime(0, 0, 1); // important, to consider the last day!
$date_interval = new DateInterval('P1M');
$date_period = new DatePeriod($start_date, $date_interval, $end_date);
# calculating number of days in the interval
$interval = $start_date->diff( $end_date );
$days = $interval->days;
# getting names of the months in the interval
$dates = [];
foreach ($date_period as $date) {
$dateArr = [];
if ($date->format("Y-m") === $start_date->format("Y-m")) {
$dateArr["start"] = $start_date->format("d-m-Y");
}
else {
$dateArr["start"] = $date->format("01-m-Y");
}
if ($date->format("Y-m") === $end_date->format("Y-m")) {
$dateArr["end"] = $end_date->format("d-m-Y");
}
else {
$dateArr["end"] = $date->format("t-m-Y"); // last day of the month
}
$dates[] = $dateArr;
}
foreach ($dates as $date) {
echo $date["start"]." to ".$date["end"].PHP_EOL;
}
Demo
You can employ DateTime::modify function. E.g.:
$month_intervals = [];
foreach ($date_period as $date) {
$start = $date == $start_date ? $start_date : $date->modify('first day of this month');
$month_intervals[] = join([
$start->format('d-m-Y'),
$date->modify('last day of this month')->format('d-m-Y')
], ' to ');
}
$month_intervals[] = join([
(clone $end_date)->modify('first day of this month')->format('d-m-Y'),
$end_date->format('d-m-Y')
], ' to ');
echo implode(',', $month_intervals);

Carbon: Get start and end date of week when knowing week in year and year

Carbon provides the function weekOfYear to get the week of the year as integer. However I need to go the other way round to get the a date based on the year + the week of the year.
Carbon::now()->weekOfYear(); // todays week of the year
E.g.
year: 2016
week of year: 42
As a result i need the start and end date of this given week. However i cannot find a fitting function in the Carbon docs
Carbon is a wrapper for PHP's DateTime, so you can use setISODate:
$date = Carbon::now(); // or $date = new Carbon();
$date->setISODate(2016,42); // 2016-10-17 23:59:59.000000
echo $date->startOfWeek(); // 2016-10-17 00:00:00.000000
echo $date->endOfWeek(); // 2016-10-23 23:59:59.000000
/**
* #return array{0: \DateTime, 1: \DateTime}
*/
public static function getWeekDates(\DateTimeInterface $selectedDate): array
{
$daysFromMonday = (int) $selectedDate->format('N') - 1;
$fromDate = \DateTimeImmutable::createFromInterface($selectedDate)->modify("-{$daysFromMonday} days");
$toDate = $fromDate->modify('+6 days');
return [
\DateTime::createFromImmutable($fromDate),
\DateTime::createFromImmutable($toDate),
];
}
This returns date of Monday and Sunday (iso week number).
If you wish to know dates of Sunday and Saturday, you can easily modify the function (replace 'N' with 'w' in format) and remove -1
$WeekArray = array();
$FirstDate = Carbon::now()->addYears(-2);
$LastDate = Carbon::now()->addYears(2);
while ($FirstDate <= $LastDate) {
$WeekNumber = Carbon::parse($FirstDate)->weekOfYear;
$WeekYear = Carbon::parse($FirstDate)->year;
$StartOfWeek = Carbon::parse($FirstDate)->startOfWeek();
$EndOfWeek = Carbon::parse($FirstDate)->endOfWeek();
$WeekItem = new stdClass;
$WeekItem->WeekNumber = $WeekNumber;
$WeekItem->WeekYear = $WeekYear;
$WeekItem->FirstDate = AppHelper::_DateFormatMysql($StartOfWeek);
$WeekItem->LastDate = AppHelper::_DateFormatMysql($EndOfWeek);
if (count($WeekArray) > 0) {
if (collect($WeekArray)->where('WeekYear', $WeekItem->WeekYear)->where('WeekNumber', $WeekItem->WeekNumber)
->where('FirstDate', $WeekItem->FirstDate)->where('LastDate', $WeekItem->LastDate)->count() == 0)
{
array_push($WeekArray, $WeekItem);
}
}
else {
array_push($WeekArray, $WeekItem);
}
$FirstDate = Carbon::parse($FirstDate)->addDays(1);
}

Making full year schedule of event using php date function

I have an event having the following properties:
id
name
weekday
So, an event happens every week on that weekday. I wanted to create an array containing all the dates (Format: dd-mm-yyyy), when that event will take place two specific dates.
I'm unable to figure out the appropriate logic/code.
I implemented the following code:
$day = date('d');//returns today's date in 2-digit format.
$year = date('Y');//4-digit format of current year
$month = date('m');//2-digit format of current month
$cal = array();
$ttdayid = $weekday;//5
$tt = 0;
$tt = abs($day-$ttdayid);
$ttday = $date - $tt;
while ($ttday>0) {
if ($ttday<10) {
$ttday = '0' . $ttday;
}
$arr = array(
'id' => $id,
'title' => $name,
'start' => $year . '-' . $month . '-' . $ttday
);
array_push($cal, $arr);
$ttday-= 7;
}
The above code works for the current month only before today. I'm unable to figure out how to extend it to show dates for previous and next months for the whole year. Also, how to included cases for leap years.
Use the DateTime() object:
$current = new DateTime(); // creates a date for "today" by default
$end = new DateTime('yyyy-mm-dd'); // the ending date
$interval = new DateInterval('P7D'); // 1 week
while($current <= $end) {
$cal[] = $current->format('Y-m-d');
$current = $current->add($interval);
}

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