PHP DateTime :: sửa đổi cộng và trừ tháng


101

Tôi đã làm việc rất nhiều với DateTime classvà gần đây đã gặp phải những gì tôi nghĩ là một lỗi khi thêm tháng. Sau một chút nghiên cứu, có vẻ như nó không phải là một lỗi mà thay vào đó nó hoạt động như dự định. Theo tài liệu tìm thấy ở đây :

Ví dụ # 2 Hãy cẩn thận khi cộng hoặc trừ các tháng

<?php
$date = new DateTime('2000-12-31');

$date->modify('+1 month');
echo $date->format('Y-m-d') . "\n";

$date->modify('+1 month');
echo $date->format('Y-m-d') . "\n";
?>
The above example will output:
2001-01-31
2001-03-03

Bất cứ ai có thể giải thích tại sao điều này không được coi là một lỗi?

Hơn nữa, có ai có bất kỳ giải pháp thanh lịch nào để khắc phục vấn đề và làm cho nó để +1 tháng sẽ hoạt động như mong đợi thay vì như dự định không?


Bạn mong đợi "2001-01-31" cộng với 1 tháng sẽ là gì? ... "2001-02-28"? "2001-03-01"?
Artefacto

57
Cá nhân tôi mong đợi nó là 2001-02-28.
tplaner

Câu chuyện tương tự với strtotime() stackoverflow.com/questions/7119777/…
Valentin Despa

2
Đúng, đó là một câu hỏi khá khó chịu. Bạn đã đọc bản in đẹp để tìm ra rằng P1M là 31 ngày. Không hiểu sao mọi người cứ bảo vệ nó là hành vi "đúng".
Indivision Dev

Có vẻ như ý kiến ​​phổ biến cho rằng logic nên làm tròn xuống (thành 2/28), mặc dù PHP làm tròn (thành 3/1) ... mặc dù tôi thích cách của PHP hơn, nhưng Excel của Microsoft làm tròn xuống, khiến các nhà phát triển web chống lại người dùng bảng tính ...
Dave Heq 7/12/16

Câu trả lời:


106

Tại sao nó không phải là một lỗi:

Hành vi hiện tại là đúng. Những điều sau đây xảy ra trong nội bộ:

  1. +1 monthtăng số tháng (ban đầu là 1) lên một. Điều này làm cho ngày 2010-02-31.

  2. Tháng thứ hai (tháng 2) chỉ có 28 ngày trong năm 2010, vì vậy PHP sẽ tự động sửa lỗi này bằng cách tiếp tục tính các ngày kể từ ngày 1 tháng 2. Sau đó, bạn sẽ kết thúc vào ngày 3 tháng 3.

Làm thế nào để đạt được những gì bạn muốn:

Để có được những gì bạn muốn là: kiểm tra thủ công vào tháng tiếp theo. Sau đó, thêm số ngày tháng sau có.

Tôi hy vọng bạn có thể tự mình viết mã này. Tôi chỉ đưa ra những việc cần làm.

Cách PHP 5.3:

Để có được hành vi chính xác, bạn có thể sử dụng một trong những chức năng mới của PHP 5.3 giới thiệu khoảng thời gian tương đối first day of. Đoạn thơ này có thể được dùng kết hợp với next month, fifth monthhoặc +8 monthsđi đến ngày đầu tiên của tháng theo quy định. Thay vì +1 monthnhững gì bạn đang làm, bạn có thể sử dụng mã này để nhận được ngày đầu tiên của tháng tới như sau:

<?php
$d = new DateTime( '2010-01-31' );
$d->modify( 'first day of next month' );
echo $d->format( 'F' ), "\n";
?>

Tập lệnh này sẽ xuất ra một cách chính xác February. Những điều sau đây xảy ra khi PHP xử lý first day of next monthđoạn thơ này :

  1. next monthtăng số tháng (ban đầu là 1) lên một. Điều này làm cho ngày 2010-02-31.

  2. first day ofđặt số ngày thành 1, dẫn đến ngày 2010-02-01.


1
Vì vậy, những gì bạn đang nói là nó theo nghĩa đen thêm 1 tháng, bỏ qua hoàn toàn ngày? Vì vậy, tôi giả định rằng bạn có thể gặp phải vấn đề tương tự với +1 năm nếu bạn thêm nó vào năm nhuận?
tplaner

@evolve, Vâng, văn học thêm 1 tháng.
shamittomar

13
Và nếu bạn trừ đi 1 tháng sau khi cộng nó, bạn sẽ có một ngày hoàn toàn khác, tôi cho là vậy. Điều đó có vẻ rất không trực quan.
Dan Breen,

2
Ví dụ tuyệt vời về cách sử dụng stanzas mới trong PHP 5.3 nơi bạn có thể sử dụng ngày đầu tiên, ngày trước, tháng này, tháng sau và tháng trước.
Kim Stacks

6
imho đây là một lỗi. một lỗi nghiêm trọng. nếu tôi muốn thêm 31 ngày, tôi thêm 31 ngày. Tôi muốn thêm một tháng, một tháng nên được thêm vào, không phải 31 ngày.
low_rents

12

Đây là một giải pháp nhỏ gọn khác hoàn toàn sử dụng các phương thức DateTime, sửa đổi đối tượng tại chỗ mà không tạo bản sao.

$dt = new DateTime('2012-01-31');

echo $dt->format('Y-m-d'), PHP_EOL;

$day = $dt->format('j');
$dt->modify('first day of +1 month');
$dt->modify('+' . (min($day, $dt->format('t')) - 1) . ' days');

echo $dt->format('Y-m-d'), PHP_EOL;

Nó xuất ra:

2012-01-31
2012-02-29

1
Cảm ơn. Giải pháp tốt nhất được cung cấp ở đây cho đến nay. Bạn cũng có thể rút ngắn mã thành $dt->modify()->modify(). Hoạt động tốt.
Alph.Dev

10

Điều này có thể hữu ích:

echo Date("Y-m-d", strtotime("2013-01-01 +1 Month -1 Day"));
  // 2013-01-31

echo Date("Y-m-d", strtotime("2013-02-01 +1 Month -1 Day"));
  // 2013-02-28

echo Date("Y-m-d", strtotime("2013-03-01 +1 Month -1 Day"));
  // 2013-03-31

echo Date("Y-m-d", strtotime("2013-04-01 +1 Month -1 Day"));
  // 2013-04-30

echo Date("Y-m-d", strtotime("2013-05-01 +1 Month -1 Day"));
  // 2013-05-31

echo Date("Y-m-d", strtotime("2013-06-01 +1 Month -1 Day"));
  // 2013-06-30

echo Date("Y-m-d", strtotime("2013-07-01 +1 Month -1 Day"));
  // 2013-07-31

echo Date("Y-m-d", strtotime("2013-08-01 +1 Month -1 Day"));
  // 2013-08-31

echo Date("Y-m-d", strtotime("2013-09-01 +1 Month -1 Day"));
  // 2013-09-30

echo Date("Y-m-d", strtotime("2013-10-01 +1 Month -1 Day"));
  // 2013-10-31

echo Date("Y-m-d", strtotime("2013-11-01 +1 Month -1 Day"));
  // 2013-11-30

echo Date("Y-m-d", strtotime("2013-12-01 +1 Month -1 Day"));
  // 2013-12-31

2
Không phải là một giải pháp chung, vì điều này chỉ hoạt động đối với một số đầu vào nhất định, chẳng hạn như ngày 1 của tháng. Ví dụ: làm điều này vào ngày 30 tháng Giêng dẫn đến đau khổ.
Jens Roland

Hoặc bạn có thể làm$dateTime->modify('first day of next month')->modify('-1day')
Anthony

6

Giải pháp của tôi cho vấn đề:

$startDate = new \DateTime( '2015-08-30' );
$endDate = clone $startDate;

$billing_count = '6';
$billing_unit = 'm';

$endDate->add( new \DateInterval( 'P' . $billing_count . strtoupper( $billing_unit ) ) );

if ( intval( $endDate->format( 'n' ) ) > ( intval( $startDate->format( 'n' ) ) + intval( $billing_count ) ) % 12 )
{
    if ( intval( $startDate->format( 'n' ) ) + intval( $billing_count ) != 12 )
    {
        $endDate->modify( 'last day of -1 month' );
    }
}

3
Lệnh "clone" là giải pháp cho các vấn đề về gán biến của tôi. Cảm ơn vì điều này.
Steph Rose,

4

Tôi đồng ý với quan điểm của OP rằng điều này là phản trực giác và gây khó chịu, nhưng việc xác định ý +1 monthnghĩa của điều này trong các tình huống xảy ra là gì. Hãy xem xét các ví dụ sau:

Bạn bắt đầu với 2015-01-31 và muốn thêm một tháng 6 lần để có một chu kỳ lập lịch gửi bản tin email. Với những kỳ vọng ban đầu của OP, điều này sẽ trở lại:

  • 2015-01-31
  • 2015-02-28
  • 2015-03-31
  • 2015-04-30
  • 2015-05-31
  • 2015-06-30

Ngay lập tức, hãy lưu ý rằng chúng tôi dự kiến +1 monthcó nghĩa là last day of monthhoặc, cách khác, thêm 1 tháng mỗi lần lặp lại nhưng luôn tham chiếu đến điểm bắt đầu. Thay vì hiểu điều này là "ngày cuối cùng của tháng", chúng tôi có thể đọc nó là "ngày 31 của tháng tới hoặc có sẵn cuối cùng trong tháng đó". Điều này có nghĩa là chúng tôi chuyển từ ngày 30 tháng 4 sang ngày 31 tháng 5 thay vì đến ngày 30 tháng 5. Lưu ý rằng điều này không phải vì nó là "ngày cuối cùng của tháng" mà vì chúng tôi muốn "có sẵn gần nhất với ngày bắt đầu của tháng."

Vì vậy, giả sử một trong những người dùng của chúng tôi đăng ký một bản tin khác để bắt đầu vào ngày 30 tháng 1 năm 2015. Ngày trực quan để làm +1 monthgì? Một diễn giải sẽ là "ngày 30 của tháng tiếp theo hoặc gần nhất có sẵn" sẽ trả về:

  • 2015-01-30
  • 2015-02-28
  • 2015-03-30
  • 2015-04-30
  • 2015-05-30
  • 2015-06-30

Điều này sẽ ổn trừ khi người dùng của chúng tôi nhận được cả hai bản tin trong cùng một ngày. Hãy giả sử rằng đây là vấn đề từ phía cung thay vì phía cầu Chúng tôi không lo lắng rằng người dùng sẽ khó chịu khi nhận được 2 bản tin trong cùng một ngày nhưng thay vào đó, máy chủ thư của chúng tôi không thể cung cấp băng thông để gửi gấp đôi nhiều bản tin. Với ý nghĩ đó, chúng tôi quay lại cách giải thích khác của "+1 tháng" là "gửi vào ngày thứ hai đến ngày cuối cùng của mỗi tháng" sẽ trả về:

  • 2015-01-30
  • 2015-02-27
  • 2015-03-30
  • 2015-04-29
  • 2015-05-30
  • 2015-06-29

Bây giờ chúng tôi đã tránh được bất kỳ sự trùng lặp nào với nhóm đầu tiên, nhưng chúng tôi cũng kết thúc với tháng 4 và ngày 29 tháng 6, điều này chắc chắn phù hợp với trực giác ban đầu của chúng tôi rằng +1 monthđơn giản là sẽ trở lại m/$d/Yhoặc hấp dẫn và đơn giản m/30/Ycho tất cả các tháng có thể. Vì vậy, bây giờ chúng ta hãy xem xét cách giải thích thứ ba về +1 monthviệc sử dụng cả hai ngày:

Ngày 31 tháng 1

  • 2015-01-31
  • 2015-03-03
  • 2015-03-31
  • 2015-05-01
  • 2015-05-31
  • 2015-07-01

Ngày 30 tháng 1

  • 2015-01-30
  • 2015-03-02
  • 2015-03-30
  • 2015-04-30
  • 2015-05-30
  • 2015-06-30

Trên đây có một số vấn đề. Tháng Hai bị bỏ qua, có thể là một vấn đề cả về nguồn cung (giả sử nếu có sự phân bổ băng thông hàng tháng và tháng Hai trở nên lãng phí và tháng Ba tăng gấp đôi) và nhu cầu cuối cùng (người dùng cảm thấy bị lừa ngoài tháng Hai và nhận thấy tháng Ba thừa như cố gắng sửa chữa sai lầm). Mặt khác, lưu ý rằng hai ngày đặt:

  • không bao giờ chồng chéo
  • luôn vào cùng một ngày khi tháng đó có ngày (vì vậy, bộ ngày 30 tháng 1 trông khá sạch sẽ)
  • tất cả đều trong vòng 3 ngày (1 ngày trong hầu hết các trường hợp) kể từ ngày có thể được coi là ngày "chính xác".
  • đều cách người kế nhiệm và người tiền nhiệm ít nhất 28 ngày (một tháng âm lịch), do đó rất đồng đều.

Với hai nhóm cuối cùng, sẽ không khó để chỉ cần lùi lại một trong các ngày nếu nó nằm ngoài tháng tiếp theo thực tế (vì vậy hãy quay trở lại ngày 28 tháng 2 và ngày 30 tháng 4 trong bộ đầu tiên) và không bị mất ngủ vì chồng chéo và phân kỳ không thường xuyên từ mẫu "ngày cuối cùng của tháng" so với "ngày thứ hai đến ngày cuối cùng của tháng". Nhưng mong đợi thư viện lựa chọn giữa "đẹp nhất / tự nhiên nhất", "giải thích toán học của 02/31 và các lần tràn tháng khác", và "liên quan đến đầu tiên của tháng hoặc tháng trước" sẽ luôn kết thúc với sự mong đợi của ai đó không được đáp ứng và một số lịch trình cần phải điều chỉnh ngày "sai" để tránh vấn đề trong thế giới thực mà cách diễn giải "sai" giới thiệu.

Vì vậy, một lần nữa, mặc dù tôi cũng mong đợi +1 monthđể trả lại một ngày thực sự là vào tháng sau, nó không đơn giản như trực giác và đưa ra các lựa chọn, đi với toán học hơn mong đợi của các nhà phát triển web có lẽ là lựa chọn an toàn.

Đây là một giải pháp thay thế vẫn còn rắc rối như bất kỳ giải pháp nào nhưng tôi nghĩ rằng có kết quả tốt:

foreach(range(0,5) as $count) {
    $new_date = clone $date;
    $new_date->modify("+$count month");
    $expected_month = $count + 1;
    $actual_month = $new_date->format("m");
    if($expected_month != $actual_month) {
        $new_date = clone $date;
        $new_date->modify("+". ($count - 1) . " month");
        $new_date->modify("+4 weeks");
    }
    
    echo "* " . nl2br($new_date->format("Y-m-d") . PHP_EOL);
}

Nó không phải là tối ưu nhưng logic cơ bản là: Nếu thêm 1 tháng dẫn đến một ngày khác với tháng tiếp theo dự kiến, hãy loại bỏ ngày đó và thay vào đó thêm 4 tuần. Dưới đây là kết quả của hai ngày thi:

Ngày 31 tháng 1

  • 2015-01-31
  • 2015-02-28
  • 2015-03-31
  • 2015-04-28
  • 2015-05-31
  • 2015-06-28

Ngày 30 tháng 1

  • 2015-01-30
  • 2015-02-27
  • 2015-03-30
  • 2015-04-30
  • 2015-05-30
  • 2015-06-30

(Mã của tôi là một mớ hỗn độn và sẽ không hoạt động trong một kịch bản kéo dài nhiều năm. Tôi hoan nghênh bất kỳ ai viết lại giải pháp với mã thanh lịch hơn miễn là tiền đề cơ bản được giữ nguyên, tức là nếu tháng +1 trả về một ngày thú vị, hãy sử dụng +4 tuần thay vào đó.)


4

Tôi đã tạo một hàm trả về DateInterval để đảm bảo rằng việc thêm một tháng sẽ hiển thị tháng tiếp theo và loại bỏ những ngày sau đó.

$time = new DateTime('2014-01-31');
echo $time->format('d-m-Y H:i') . '<br/>';

$time->add( add_months(1, $time));

echo $time->format('d-m-Y H:i') . '<br/>';



function add_months( $months, \DateTime $object ) {
    $next = new DateTime($object->format('d-m-Y H:i:s'));
    $next->modify('last day of +'.$months.' month');

    if( $object->format('d') > $next->format('d') ) {
        return $object->diff($next);
    } else {
        return new DateInterval('P'.$months.'M');
    }
}

4

Cùng với câu trả lời của shamittomar, nó có thể là điều này để thêm tháng "an toàn":

/**
 * Adds months without jumping over last days of months
 *
 * @param \DateTime $date
 * @param int $monthsToAdd
 * @return \DateTime
 */

public function addMonths($date, $monthsToAdd) {
    $tmpDate = clone $date;
    $tmpDate->modify('first day of +'.(int) $monthsToAdd.' month');

    if($date->format('j') > $tmpDate->format('t')) {
        $daysToAdd = $tmpDate->format('t') - 1;
    }else{
        $daysToAdd = $date->format('j') - 1;
    }

    $tmpDate->modify('+ '. $daysToAdd .' days');


    return $tmpDate;
}

Cảm ơn bạn rất nhiều!!
geckos

2

Tôi đã tìm thấy một cách ngắn hơn để giải quyết vấn đề này bằng cách sử dụng mã sau:

                   $datetime = new DateTime("2014-01-31");
                    $month = $datetime->format('n'); //without zeroes
                    $day = $datetime->format('j'); //without zeroes

                    if($day == 31){
                        $datetime->modify('last day of next month');
                    }else if($day == 29 || $day == 30){
                        if($month == 1){
                            $datetime->modify('last day of next month');                                
                        }else{
                            $datetime->modify('+1 month');                                
                        }
                    }else{
                        $datetime->modify('+1 month');
                    }
echo $datetime->format('Y-m-d H:i:s');

1

Đây là phần triển khai phiên bản cải tiến của câu trả lời của Juhana trong một câu hỏi liên quan:

<?php
function sameDateNextMonth(DateTime $createdDate, DateTime $currentDate) {
    $addMon = clone $currentDate;
    $addMon->add(new DateInterval("P1M"));

    $nextMon = clone $currentDate;
    $nextMon->modify("last day of next month");

    if ($addMon->format("n") == $nextMon->format("n")) {
        $recurDay = $createdDate->format("j");
        $daysInMon = $addMon->format("t");
        $currentDay = $currentDate->format("j");
        if ($recurDay > $currentDay && $recurDay <= $daysInMon) {
            $addMon->setDate($addMon->format("Y"), $addMon->format("n"), $recurDay);
        }
        return $addMon;
    } else {
        return $nextMon;
    }
}

Phiên bản này có $createdDategiả định rằng bạn đang xử lý khoảng thời gian định kỳ hàng tháng, chẳng hạn như đăng ký, bắt đầu vào một ngày cụ thể, chẳng hạn như ngày 31. Các ngày $createdDate"lặp lại vào" quá muộn sẽ không chuyển sang các giá trị thấp hơn vì chúng được đẩy về phía trước qua các tháng có giá trị thấp hơn (ví dụ: vì vậy tất cả các ngày định kỳ 29, 30 hoặc 31 cuối cùng sẽ không bị kẹt vào ngày 28 sau khi trôi qua cho đến tháng hai năm không nhuận).

Đây là một số mã trình điều khiển để kiểm tra thuật toán:

$createdDate = new DateTime("2015-03-31");
echo "created date = " . $createdDate->format("Y-m-d") . PHP_EOL;

$next = sameDateNextMonth($createdDate, $createdDate);
echo "   next date = " . $next->format("Y-m-d") . PHP_EOL;

foreach(range(1, 12) as $i) {
    $next = sameDateNextMonth($createdDate, $next);
    echo "   next date = " . $next->format("Y-m-d") . PHP_EOL;
}

Kết quả đầu ra:

created date = 2015-03-31
   next date = 2015-04-30
   next date = 2015-05-31
   next date = 2015-06-30
   next date = 2015-07-31
   next date = 2015-08-31
   next date = 2015-09-30
   next date = 2015-10-31
   next date = 2015-11-30
   next date = 2015-12-31
   next date = 2016-01-31
   next date = 2016-02-29
   next date = 2016-03-31
   next date = 2016-04-30

1

Đây là phiên bản cải tiến của câu trả lời của Kasihasi trong một câu hỏi liên quan. Điều này sẽ thêm hoặc bớt một cách chính xác một số tháng tùy ý cho một ngày.

public static function addMonths($monthToAdd, $date) {
    $d1 = new DateTime($date);

    $year = $d1->format('Y');
    $month = $d1->format('n');
    $day = $d1->format('d');

    if ($monthToAdd > 0) {
        $year += floor($monthToAdd/12);
    } else {
        $year += ceil($monthToAdd/12);
    }
    $monthToAdd = $monthToAdd%12;
    $month += $monthToAdd;
    if($month > 12) {
        $year ++;
        $month -= 12;
    } elseif ($month < 1 ) {
        $year --;
        $month += 12;
    }

    if(!checkdate($month, $day, $year)) {
        $d2 = DateTime::createFromFormat('Y-n-j', $year.'-'.$month.'-1');
        $d2->modify('last day of');
    }else {
        $d2 = DateTime::createFromFormat('Y-n-d', $year.'-'.$month.'-'.$day);
    }
    return $d2->format('Y-m-d');
}

Ví dụ:

addMonths(-25, '2017-03-31')

sẽ xuất:

'2015-02-28'

0

Nếu bạn chỉ muốn tránh bỏ qua một tháng, bạn có thể thực hiện điều gì đó như thế này để lấy ngày ra và chạy vòng lặp vào tháng tiếp theo, giảm ngày xuống một và kiểm tra lại cho đến ngày hợp lệ trong đó $ started_calculated là chuỗi hợp lệ cho strtotime (tức là mysql datetime hoặc "now"). Điều này cho thấy cuối tháng ở 1 phút đến nửa đêm thay vì bỏ qua tháng.

    $start_dt = $starting_calculated;

    $next_month = date("m",strtotime("+1 month",strtotime($start_dt)));
    $next_month_year = date("Y",strtotime("+1 month",strtotime($start_dt)));

    $date_of_month = date("d",$starting_calculated);

    if($date_of_month>28){
        $check_date = false;
        while(!$check_date){
            $check_date = checkdate($next_month,$date_of_month,$next_month_year);
            $date_of_month--;
        }
        $date_of_month++;
        $next_d = $date_of_month;
    }else{
        $next_d = "d";
    }
    $end_dt = date("Y-m-$next_d 23:59:59",strtotime("+1 month"));


0

Nếu sử dụng strtotime()chỉ cần sử dụng$date = strtotime('first day of +1 month');


0

Tôi cần phải có một ngày cho 'tháng này năm trước' và nó trở nên khó chịu khá nhanh khi tháng này là tháng hai trong năm nhuận. Tuy nhiên, tôi tin rằng điều này có hiệu quả ...: - / Mẹo dường như là dựa trên sự thay đổi của bạn vào ngày đầu tiên của tháng.

$this_month_last_year_end = new \DateTime();
$this_month_last_year_end->modify('first day of this month');
$this_month_last_year_end->modify('-1 year');
$this_month_last_year_end->modify('last day of this month');
$this_month_last_year_end->setTime(23, 59, 59);

0
$ds = new DateTime();
$ds->modify('+1 month');
$ds->modify('first day of this month');

1
Bạn cần giải thích câu trả lời của mình. Các câu trả lời chỉ có mã được coi là chất lượng thấp
Machavity

Cảm ơn bạn! Đây là câu trả lời gọn gàng nhất được nêu ra. Nếu bạn chuyển 2 dòng cuối cùng thì nó luôn cho đúng tháng. Thanh danh!
Danny Schoemann

0
$month = 1; $year = 2017;
echo date('n', mktime(0, 0, 0, $month + 2, -1, $year));

sẽ xuất 2(tháng 2). cũng sẽ hoạt động trong các tháng khác.


0
$current_date = new DateTime('now');
$after_3_months = $current_date->add(\DateInterval::createFromDateString('+3 months'));

Ngày:

$after_3_days = $current_date->add(\DateInterval::createFromDateString('+3 days'));

Quan trọng:

Phương thức add()của lớp DateTime sửa đổi giá trị đối tượng để sau khi gọi add()một Đối tượng DateTime, nó trả về đối tượng ngày tháng mới và nó cũng tự sửa đổi đối tượng đó.


0

bạn thực sự có thể làm điều đó chỉ với date () và strtotime (). Ví dụ để thêm 1 tháng vào ngày thường:

date("Y-m-d",strtotime("+1 month",time()));

nếu bạn muốn sử dụng lớp datetime cũng tốt nhưng điều này cũng dễ dàng. thêm chi tiết tại đây


0

Câu trả lời được chấp nhận đã giải thích tại sao đây không phải là nhưng và một số câu trả lời khác đặt ra một giải pháp gọn gàng với các biểu thức php như first day of the +2 months. Vấn đề với những biểu thức đó là chúng không tự động hoàn thành.

Giải pháp là khá đơn giản mặc dù. Trước tiên, bạn nên tìm những nội dung trừu tượng hữu ích phản ánh không gian vấn đề của bạn. Trong trường hợp này, đó là một ISO8601DateTime. Thứ hai, cần có nhiều cách triển khai có thể mang lại một biểu diễn văn bản mong muốn. Ví dụ, Today, Tomorrow, The first day of this month, Future- tất cả các đại diện cho một thực hiện cụ thể của ISO8601DateTimekhái niệm.

Vì vậy, trong trường hợp của bạn, bạn cần triển khai TheFirstDayOfNMonthsLater. Thật dễ dàng tìm thấy chỉ bằng cách nhìn vào danh sách các lớp con trong bất kỳ IDE nào. Đây là mã:

$start = new DateTimeParsedFromISO8601String('2000-12-31');
$firstDayOfOneMonthLater = new TheFirstDayOfNMonthsLater($start, 1);
$firstDayOfTwoMonthsLater = new TheFirstDayOfNMonthsLater($start, 2);
var_dump($start->value()); // 2000-12-31T00:00:00+00:00
var_dump($firstDayOfOneMonthLater->value()); // 2001-01-01T00:00:00+00:00
var_dump($firstDayOfTwoMonthsLater->value()); // 2001-02-01T00:00:00+00:00

Điều tương tự với những ngày cuối tháng. Để biết thêm ví dụ về cách tiếp cận này, hãy đọc phần này .


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.