I've seen plenty of posts about DateTime in PHP, saying to be careful about adding / subtracting days / months. Even the PHP manual warns about it. I want a function which will always increment / decrement a date to the next / previous month. The actual day (1-28/31) is irrelevant in my case.
Because of this, I thought about consistently setting the day as the 14th before incrementing / decrementing the month each time, as this gives about 13 days either side as a margin of error, so no possible ways of skipping entire months (by using days at either extreme of the month)
But I feel this is a poor implementation, yet I've not seen any solutions which seem to deal with this properly. In fact, many of the threads on SO which have accepted up-voted answers nearly all suffer from skipping months.
I use a custom class to increment/decrement dates:
class Dates
{
public function __construct() {}
public function add_date($_date, $_years, $_months, $_days, $_spacer, $_leading_zeros = 1) {
$values = explode($_spacer, $_date);
for($i = 0;$i < 3;$i++) {$values[$i] = round($values[$i]);}
$values[2] += $_days;
if($values[2] > 31) {
$aux = floor($values[2] / 31);
while($values[2] > 31) {$values[2] -= 31;}
$values[1] += $aux;
}
$values[1] += $_months;
$values[0] += $_years;
if($values[1] > 12) {
$aux = floor($values[1] / 12);
while($values[1] > 12) {$values[1] -= 12;}
$values[0] += $aux;
}
$leapYear = (($values[0] % 4 == 0) && (($values[0] % 100 != 0) || ($values[0] % 400 == 0))) ? 29 : 28;
$days = Array(0, 31, $leapYear, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
if($values[2] > $days[$values[1]]) {
$values[2] -= $days[$values[1]];
$values[1]++;
}
if($_leading_zeros) {return $this -> leading_zeros($values[0].$_spacer.$values[1].$_spacer.$values[2], $_spacer);}
else {return $values[0].$_spacer.$values[1].$_spacer.$values[2];}
}
public function subtract_date($_date, $_years, $_months, $_days, $_spacer, $_leading_zeros = 1) {
$values=explode($_spacer, $_date);
for($i = 0;$i < 3;$i++){$values[$i] = round($values[$i]);}
$days = Array(0, 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
$values[0] -= $_years;
$values[1] -= $_months;
while($values[1] < 1) {
$values[1] += 12;
$values[0]--;
}
$values[2] -= $_days;
while($values[2] < 1) {
$values[1]--;
if($values[1] == 0) {
$values[1] = 12;
$values[0]--;
}
if($values[1] == 2) {$days[2] = (($values[0] % 4 == 0) && (($values[0] % 100 != 0) || ($values[0] % 400 == 0))) ? 29 : 28;}
$values[2] += $days[$values[1]];
}
if($_leading_zeros) {return $this -> leading_zeros($values[0].$_spacer.$values[1].$_spacer.$values[2], $_spacer);}
else {return $values[0].$_spacer.$values[1].$_spacer.$values[2];}
}
public function leading_zeros($_date, $_spacer) {
$_date = $_spacer.$_date.$_spacer;
for($i = 1;$i < 10;$i++) {
while(strstr($_date, $_spacer.$i.$_spacer)){$_date = str_replace($_spacer.$i.$_spacer, $_spacer.'0'.$i.$_spacer, $_date);}
}
$_date = substr($_date, 1);
$_date = substr($_date, 0, -1);
return $_date;
}
}
If the days are irrelevant you can a simple modulo operation:
$cur_month = 6; // 0 - 11
$next_month = $cur_month + 1 % 12;
$prev_month = $cur_month + 11 % 12; // + 11 is like doing + 12 - 1
If you want the years as well you can check for that ( $month === 0
or $month === 11
)
My answer is based on incrementing a month, but not based on an interval. Since I don't know how your dates look like, I'll assume they are in the format of day.month.Year
or dmY
. So, since your requirement is really, really simple (unless I missed something), you can do the following:
$start = 1;
$end = 24;
$template = '14.{{m}}.2014';
$tz = new DateTimeZone('Europe/London');
for($i = $start; $i < $end; $i++)
{
$date = str_replace('{{m}}', $i, $template);
$dt = DateTime::createFromFormat('d.m.Y', $date, $tz);
printf("\nDate: %s", $dt->format('d.m.Y'));
}
Output:
Date: 14.01.2014
Date: 14.02.2014
Date: 14.03.2014
Date: 14.04.2014
Date: 14.05.2014
Date: 14.06.2014
Date: 14.07.2014
Date: 14.08.2014
Date: 14.09.2014
Date: 14.10.2014
Date: 14.11.2014
Date: 14.12.2014
Date: 14.01.2015
Date: 14.02.2015
Date: 14.03.2015
Date: 14.04.2015
Date: 14.05.2015
Date: 14.06.2015
Date: 14.07.2015
Date: 14.08.2015
Date: 14.09.2015
Date: 14.10.2015
Date: 14.11.2015
You can use strtotime to do that safely : strtotime
$ts = strtotime($yourDate);
// increment
$newTs = strtotime('first day of +1 month', $ts);
// decrement
$newTs = strtotime('first day of -1 month', $ts);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.