2011-04-22 93 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 
相關問題