2011-04-22 92 views
23

想要创建一个可以在PHP中执行此操作的函数。PHP:在不超过月份的最后一天的情况下添加月份

我需要在月份的最后一天添加月份数,但不能超过 。

例如:

Add 1 month to January (1-28th), 2011, should produce February (1-28th), 2011. 
Add 1 month to January 30th, 2011, should produce February 28th, 2011. 
Add 3 months to January 31st, 2011, should produce April 30th, 2011. 
Add 13 months to January 30th, 2011, should produce February 29th, 2012. 
Add 1 month to October 31st, 2011, should produce November 30th, 2011. 

如果我使用日期此外在PHP中,我得到超支:

Adding 1 month to January 30th, 2011, results in March 2nd, 2011. 

我的规范不允许我溢出到一个新的月份。

最简单的方法是什么?

+0

我加了一些例子。 – 2011-04-22 22:59:11

回答

33

您可以在添加1个月之前和之后比较一个月中的某一天。如果不一样,你会在下个月超过。

function add($date_str, $months) 
{ 
    $date = new DateTime($date_str); 

    // We extract the day of the month as $start_day 
    $start_day = $date->format('j'); 

    // We add 1 month to the given date 
    $date->modify("+{$months} month"); 

    // We extract the day of the month again so we can compare 
    $end_day = $date->format('j'); 

    if ($start_day != $end_day) 
    { 
     // The day of the month isn't the same anymore, so we correct the date 
     $date->modify('last day of last month'); 
    } 

    return $date; 
} 

$result = add('2011-01-28', 1); // 2011-02-28 
$result = add('2011-01-31', 3); // 2011-04-30 
$result = add('2011-01-30', 13); // 2012-02-29 
$result = add('2011-10-31', 1); // 2011-11-30 
$result = add('2011-12-30', 1); // 2011-02-28 
+0

闰年呢?如果想从一个月的第一天开始添加一个月,会发生什么情况?如果我是对的:在1月1日加1个月会给1月30日;增加一个月到01年2月将给你的代码03月 - 不知道这是否needet,但如果是这样,这似乎并不正确。 – oezi 2011-04-22 22:08:40

+0

闰年可以通过[checkdate](http://php.net/manual/en/function.checkdate.php)进行检查。因此只需要2个不同的阵列。 – 2011-04-22 22:41:46

+0

非常好!非常感谢 – 2018-01-30 13:54:22

3

这似乎为我工作,给侑期望的结果:

<?php 
$date = "2011-01-30"; 

list($year,$month,$day) = explode("-",$date); 

// add month here 
$month++; 
// to avoid a month-wrap, set the day to the number of days of the new month if it's too high 
$day = min($day,date("t",strtotime($year."-".$month."-01"))); 

$date = $year."-".$month."-".$day; 

// 2011-02-28 
echo $date; 
?> 

编辑:
阅读Crend国王comemnt后,我认为我们这里需要更多的信息。什么在下列情况下,所期望的结果:

2011-01-30 > 2011-02-28 
2011-01-28 > 2011-02-28 or 2011-02-26 ? 
2011-02-01 > 2011-03-01 or 2011-03-03 ? 
文字

:应在方法添加下个月的天数,至极就是Crend国王做和什么让像2011-02-26和2011年业绩-03-03(这对我来说看起来并不像我想要的结果),还是应该增加一个月,让原来的一天保持原样,而不是像我的代码那样“太高”了?我很困惑...

+0

2月28日到3月31日如何?如果2月28日到4月30日会怎么样? – 2011-04-22 21:55:38

+0

我不认为这是规范的一部分......我想我们需要更多的例子来理解这一点,请参阅我的编辑以获取更多信息 – oezi 2011-04-22 22:11:10

+0

如果OP需要简单的一个月+1(例如'add(Feb 28th)'产生3月28日),我认为你的答案在1个月内是正确的。 – 2011-04-22 22:54:18

3

据我所知,这个问题的范围是非常有限的,所以你很可能通过测试一种类型的错误,并修复它最好。

所有你想要做的就是确保在29日,30日或31日这样的迟到日期中增加“一个月”不会推动你进入下一个月的第一,第二或第三。 ()在日期“2012-01-31”中使用它的字符串如“+1个月”),它首先将月份数增加1,然后找到第31个从那个月开始的一天。这就是为什么它会蔓延到3月3日。

当这不是你想要的,你所要做的就是再次使用date_modify(),现在告诉它返回几天(本例中为3天)。由于您只想回到上个月的最后一天,因此您希望返回的天数始终与错误日期中的月份相同。

剩下的就是确保在不需要时使用此更正,就像PHP将来要改进时一样。这是相对容易的,因为可能出现问题的范围非常有限。

  • (1)仅添加个月到日期29,30或31时,会出现问题
  • (2)发生问题时,所得到的日期始终为1,2或3。

我在下面的代码中添加了“+1个月”,检查是否导致月份从高到低变化很大,如果是这样的话就调整日期。

//Create the date, store its day-of-month, and add X months 
$myDateTimeISO = "2012-01-31"; 
$addThese = 1; 
$myDateTime = new DateTime($myDateTimeISO); 
$myDayOfMonth = date_format($myDateTime,'j'); 
date_modify($myDateTime,"+$addThese months"); 

//Find out if the day-of-month has dropped 
$myNewDayOfMonth = date_format($myDateTime,'j'); 
if ($myDayOfMonth > 28 && $myNewDayOfMonth < 4){ 
//If so, fix by going back the number of days that have spilled over 
    date_modify($myDateTime,"-$myNewDayOfMonth days"); 
} 
echo date_format($myDateTime,"Y-m-d"); 

结果于:2012-02-29(是的,这是一个闰年)。如果你想增加几年,问题和症状几乎是一样的。同样,你只需要检查结果的月份是1/2/3,而月份的日期是29/30/31。如果是这样,则需要使用date_modify返回“-X days”,其中X是结果日期。

0

任何有兴趣我做了一个坚实的方式来处理这个问题

/** 
* @var \DateInterval 
*/ 
private $remainder; 

/** 
* @param \DateTimeImmutable $date 
* @param string $modifier 
* @return \DateTimeImmutable 
*/ 
private function nextInterval(\DateTimeImmutable $date, $modifier) 
{ 
    $dayNumber = (int)$date->format('j'); 
    $next = $date->modify($modifier); 
    if (!is_null($this->remainder)) { 
     $next = $next->add($this->remainder); 
     $dayNumber += $this->remainder->days; 
     $this->remainder = null; 
    } 

    // This should in general only apply to months which do not have the same daynumber in that month after adding 
    if ($dayNumber !== (int)$next->format('j')) { 
     $n = $next->modify('last day of last month'); 
     $this->remainder = $n->diff($next); 
     $next = $n; 
    } 

    return $next; 
} 

结果:

2014-11-30 
2014-12-30 
2015-01-30 
2015-02-28 
2015-03-30 
2015-04-30 
2015-05-30 

2015-12-30 
2016-01-30 
2016-02-29 
2016-03-30 
2016-04-30 
相关问题