PHP DateTime :: memodifikasi penambahan dan pengurangan bulan

101

Saya telah banyak bekerja dengan itu DateTime classdan baru-baru ini menemukan apa yang saya pikir sebagai bug ketika menambahkan bulan. Setelah sedikit penelitian, tampaknya itu bukan bug, tetapi berfungsi sebagaimana mestinya. Menurut dokumentasi yang ditemukan di sini :

Contoh # 2 Berhati-hatilah saat menambah atau mengurangi bulan

<?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

Adakah yang bisa membenarkan mengapa ini tidak dianggap bug?

Selain itu, apakah ada yang punya solusi elegan untuk memperbaiki masalah ini dan membuatnya jadi 1 bulan akan berfungsi seperti yang diharapkan, bukan sebagaimana yang dimaksudkan?

tplaner
sumber
Apa yang Anda harapkan dari "2001-01-31" ditambah 1 bulan? ... "2001-02-28"? "2001-03-01"?
Artefacto
57
Secara pribadi saya berharap itu terjadi pada 2001-02-28.
tplaner
Cerita yang sama dengan strtotime() stackoverflow.com/questions/7119777/…
Valentin Despa
2
Yup, itu permainan kata yang cukup menyebalkan. Anda telah membaca rinciannya untuk mengetahui bahwa P1M adalah 31 hari. Tidak terlalu mengerti mengapa orang terus mempertahankannya sebagai perilaku yang "benar".
Indivision Dev
Sepertinya pendapat populer adalah bahwa logika harus dibulatkan ke bawah (ke 2/28), meskipun PHP membulatkan ke atas (ke 3/1) ... meskipun saya lebih suka cara PHP, tetapi Microsoft Excel membulatkan ke bawah, mengadu pengembang web dengan pengguna spreadsheet ...
Dave Heq

Jawaban:

106

Mengapa ini bukan bug:

Perilaku saat ini benar. Berikut ini terjadi secara internal:

  1. +1 monthmeningkatkan nomor bulan (awalnya 1) satu. Ini membuat tanggal 2010-02-31.

  2. Bulan kedua (Februari) hanya memiliki 28 hari di tahun 2010, jadi PHP secara otomatis mengoreksinya dengan terus menghitung hari dari tanggal 1 Februari. Anda kemudian berakhir pada 3 Maret.

Cara mendapatkan yang Anda inginkan:

Untuk mendapatkan apa yang diinginkan adalah dengan cara: mengecek bulan berikutnya secara manual. Kemudian tambahkan jumlah hari yang dimiliki bulan depan.

Saya harap Anda sendiri dapat membuat kode ini. Saya hanya memberikan apa yang harus dilakukan.

Cara PHP 5.3:

Untuk mendapatkan perilaku yang benar, Anda dapat menggunakan salah satu fungsionalitas baru PHP 5.3 yang memperkenalkan stanza waktu relatif first day of. Bait ini dapat digunakan dalam kombinasi dengan next month, fifth monthatau +8 monthsuntuk pergi ke hari pertama bulan yang ditentukan. Alih-alih +1 monthdari apa yang Anda lakukan, Anda dapat menggunakan kode ini untuk mendapatkan hari pertama bulan depan seperti ini:

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

Skrip ini akan menghasilkan keluaran dengan benar February. Hal-hal berikut terjadi ketika PHP memproses first day of next monthsyair ini :

  1. next monthmeningkatkan nomor bulan (awalnya 1) satu. Ini membuat tanggal 2010-02-31.

  2. first day ofmenetapkan nomor hari menjadi 1, menghasilkan tanggal 2010-02-01.

shamittomar.dll
sumber
1
Jadi apa yang Anda katakan adalah benar-benar menambahkan 1 bulan, mengabaikan hari-hari sepenuhnya? Jadi saya berasumsi Anda mungkin mengalami masalah serupa dengan +1 tahun jika Anda menambahkannya selama tahun kabisat?
tplaner
@evolve, Ya, itu sastra menambahkan 1 bulan.
shamittomar
13
Dan jika Anda mengurangi 1 bulan setelah menambahkannya, Anda akan mendapatkan tanggal yang sama sekali berbeda, saya asumsikan. Sepertinya itu sangat tidak intuitif.
Dan Breen
2
Contoh luar biasa tentang penggunaan bait baru di PHP 5.3 di mana Anda dapat menggunakan hari pertama, hari terakhir, bulan ini, bulan depan, dan bulan sebelumnya.
Kim Stacks
6
imho ini adalah bug. bug yang serius. jika saya ingin menambahkan 31 hari, saya menambahkan 31 hari. Saya saya ingin menambah satu bulan, satu bulan harus ditambahkan, bukan 31 hari.
low_rents
12

Berikut adalah solusi ringkas lainnya yang sepenuhnya menggunakan metode DateTime, memodifikasi objek di tempat tanpa membuat klon.

$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;

Ini menghasilkan:

2012-01-31
2012-02-29
Rudiger W.
sumber
1
Terima kasih. Solusi terbaik yang disediakan di sini sejauh ini. Anda juga dapat mempersingkat kode menjadi $dt->modify()->modify(). Bekerja dengan baik.
Alph.Dev
10

Ini mungkin berguna:

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
nicolaas thiemen francken
sumber
2
Bukan solusi umum, karena ini hanya berfungsi untuk input tertentu, seperti tanggal 1 setiap bulan. Misalnya melakukan ini selama 30 Januari menyebabkan penderitaan.
Jens Roland
Atau Anda bisa melakukannya$dateTime->modify('first day of next month')->modify('-1day')
Anthony
6

Solusi saya untuk masalah ini:

$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' );
    }
}
Bernland
sumber
3
Perintah "klon" adalah solusi untuk masalah tugas variabel saya. Terima kasih untuk ini.
Steph Rose
4

Saya setuju dengan sentimen OP bahwa ini kontra-intuitif dan membuat frustrasi, tetapi begitu juga menentukan apa +1 month artinya dalam skenario di mana ini terjadi. Pertimbangkan contoh berikut:

Anda mulai dengan 31-01-2015 dan ingin menambahkan sebulan 6 kali untuk mendapatkan siklus penjadwalan untuk mengirim buletin email. Dengan mempertimbangkan ekspektasi awal OP, ini akan menghasilkan:

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

Segera, perhatikan bahwa +1 monthmaksud kami adalahlast day of month atau, sebagai alternatif, menambahkan 1 bulan per iterasi tetapi selalu mengacu pada titik awal. Alih-alih menafsirkan ini sebagai "hari terakhir bulan itu", kita dapat membacanya sebagai "hari ke-31 bulan depan atau hari terakhir tersedia dalam bulan itu". Ini berarti kami melompat dari 30 April ke 31 Mei, bukan ke 30 Mei. Perhatikan bahwa ini bukan karena ini adalah "hari terakhir bulan" tetapi karena kami ingin "yang terdekat dengan tanggal mulai bulan."

Jadi, misalkan salah satu pengguna kami berlangganan buletin lain untuk memulai 2015-01-30. Untuk apa tanggal intuitif itu +1 month? Satu interpretasi adalah "hari ke-30 bulan depan atau paling dekat tersedia" yang akan menghasilkan:

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

Ini akan baik-baik saja kecuali jika pengguna kami mendapatkan kedua buletin pada hari yang sama. Anggaplah ini adalah masalah sisi penawaran, bukan sisi permintaan. Kami tidak khawatir pengguna akan terganggu dengan mendapatkan 2 buletin di hari yang sama, tetapi server email kami tidak mampu membayar bandwidth untuk pengiriman dua kali lipat. banyak buletin. Dengan mengingat hal itu, kami kembali ke interpretasi lain dari "+1 bulan" sebagai "kirim pada hari kedua hingga terakhir setiap bulan" yang akan menghasilkan:

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

Sekarang kami telah menghindari tumpang tindih dengan set pertama, tetapi kami juga berakhir dengan April dan 29 Juni, yang tentunya cocok dengan intuisi asli kami yang +1 monthseharusnya kembali m/$d/Yatau yang menarik dan sederhana m/30/Yuntuk semua bulan yang memungkinkan. Jadi sekarang mari kita pertimbangkan interpretasi ketiga +1 monthmenggunakan kedua tanggal:

31 Januari

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

30 Januari

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

Di atas memiliki beberapa masalah. Februari dilewati, yang bisa menjadi masalah pada supply-end (katakanlah jika ada alokasi bandwidth bulanan dan Feb terbuang percuma dan Maret bertambah dua kali lipat) dan demand-end (pengguna merasa dicurangi pada Feb dan merasakan Maret ekstra sebagai upaya untuk memperbaiki kesalahan). Di sisi lain, perhatikan bahwa dua set tanggal:

  • tidak pernah tumpang tindih
  • selalu pada tanggal yang sama ketika bulan itu memiliki tanggal (jadi set 30 Januari terlihat cukup bersih)
  • semuanya dalam 3 hari (dalam banyak kasus 1 hari) dari apa yang dapat dianggap sebagai tanggal yang "benar".
  • semuanya setidaknya 28 hari (satu bulan lunar) dari penerus dan pendahulunya, sehingga didistribusikan dengan sangat merata.

Mengingat dua set terakhir, tidak akan sulit untuk hanya memutar kembali salah satu tanggal jika jatuh di luar bulan berikutnya yang sebenarnya (jadi putar kembali ke 28 Feb dan 30 April di set pertama) dan tidak kehilangan waktu tidur selama set pertama. tumpang tindih dan perbedaan sesekali dari pola "hari terakhir bulan" vs "hari kedua hingga hari terakhir bulan". Tapi mengharapkan perpustakaan untuk memilih antara "paling cantik / alami", "interpretasi matematis dari 31/02 dan bulan lainnya melimpah", dan "relatif terhadap bulan pertama atau bulan lalu" selalu akan berakhir dengan harapan seseorang tidak terpenuhi dan beberapa jadwal perlu menyesuaikan tanggal yang "salah" untuk menghindari masalah dunia nyata yang disebabkan oleh interpretasi yang "salah".

Jadi sekali lagi, sementara saya juga berharap +1 monthuntuk mengembalikan tanggal yang sebenarnya ada di bulan berikutnya, itu tidak sesederhana intuisi dan diberi pilihan, menggunakan matematika daripada ekspektasi pengembang web mungkin adalah pilihan yang aman.

Berikut adalah solusi alternatif yang masih kikuk tetapi menurut saya memiliki hasil yang bagus:

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);
}

Ini tidak optimal tetapi logika yang mendasarinya adalah: Jika menambahkan 1 bulan menghasilkan tanggal selain yang diharapkan bulan depan, hapus tanggal itu dan tambahkan 4 minggu sebagai gantinya. Berikut hasil dengan dua tanggal tes:

31 Januari

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

30 Januari

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

(Kode saya berantakan dan tidak akan berfungsi dalam skenario multi-tahun. Saya menyambut siapa pun untuk menulis ulang solusi dengan kode yang lebih elegan selama premis yang mendasarinya tetap utuh, yaitu jika +1 bulan mengembalikan tanggal yang funky, gunakan +4 minggu sebagai gantinya.)

Anthony
sumber
4

Saya membuat fungsi yang mengembalikan DateInterval untuk memastikan bahwa menambahkan bulan menunjukkan bulan berikutnya, dan menghapus hari-hari setelahnya.

$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');
    }
}
AR
sumber
4

Sehubungan dengan jawaban shamittomar, bisa jadi ini untuk menambahkan bulan "dengan aman":

/**
 * 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;
}
patrickzzz.dll
sumber
Terima kasih banyak!!
tokek
2

Saya menemukan cara yang lebih pendek dengan menggunakan kode berikut:

                   $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');
Rommel Paras
sumber
1

Berikut adalah implementasi dari versi perbaikan dari jawaban Juhana dalam pertanyaan terkait:

<?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;
    }
}

Versi ini $createdDatemengasumsikan bahwa Anda berurusan dengan periode bulanan berulang, seperti langganan, yang dimulai pada tanggal tertentu, seperti tanggal 31. Itu selalu membutuhkan waktu yang $createdDateterlambat "berulang pada" tanggal tidak akan bergeser ke nilai yang lebih rendah karena mereka didorong ke depan melalui bulan-bulan dengan nilai yang lebih rendah (misalnya, jadi semua tanggal berulang ke-29, 30 atau 31 pada akhirnya tidak akan macet pada tanggal 28 setelah lewat melalui bulan Februari bukan tahun kabisat).

Berikut beberapa kode driver untuk menguji algoritme:

$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;
}

Output mana:

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
derekm
sumber
1

Ini adalah versi perbaikan dari jawaban Kasihasi dalam pertanyaan terkait. Ini akan menambah atau mengurangi jumlah bulan yang berubah-ubah dengan benar.

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');
}

Sebagai contoh:

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

akan mengeluarkan:

'2015-02-28'
Hải Phong
sumber
0

Jika Anda hanya ingin menghindari melewatkan satu bulan, Anda dapat melakukan sesuatu seperti ini untuk mengeluarkan tanggal dan menjalankan loop pada bulan berikutnya mengurangi tanggal satu per satu dan memeriksa ulang hingga tanggal yang valid di mana $ starting_calculated adalah string yang valid untuk strtotime (mis. mysql datetime atau "sekarang"). Ini menemukan akhir bulan pada 1 menit hingga tengah malam alih-alih melewatkan bulan.

    $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"));
pengguna1590391
sumber
0

Jika menggunakan strtotime()gunakan saja$date = strtotime('first day of +1 month');

Primoz Roma
sumber
0

Saya perlu mendapatkan tanggal untuk 'bulan ini tahun lalu' dan itu menjadi tidak menyenangkan dengan cepat ketika bulan ini adalah Februari dalam tahun kabisat. Namun, saya yakin ini berhasil ...: - / Triknya tampaknya mendasarkan perubahan Anda pada hari pertama setiap bulan.

$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);
Hanya Biasa Saja
sumber
0
$ds = new DateTime();
$ds->modify('+1 month');
$ds->modify('first day of this month');
Tim Graham
sumber
1
Anda perlu menjelaskan jawaban Anda. Jawaban hanya kode dianggap berkualitas rendah
Machavity
Terima kasih! Ini adalah jawaban yang paling rapi. Jika Anda mengganti 2 baris terakhir maka selalu memberikan bulan yang benar. Pujian!
Danny Schoemann
0
$month = 1; $year = 2017;
echo date('n', mktime(0, 0, 0, $month + 2, -1, $year));

akan keluar 2(februari). akan bekerja untuk bulan-bulan lain juga.

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

Untuk hari-hari:

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

Penting:

Metode add()kelas DateTime memodifikasi nilai objek sehingga setelah memanggil add()Objek DateTime ia mengembalikan objek tanggal baru dan juga memodifikasi objek itu sendiri.

MiharbKH
sumber
0

Anda sebenarnya dapat melakukannya hanya dengan date () dan strtotime () juga. Misalnya untuk menambahkan 1 bulan ke tanggal hari ini:

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

jika Anda ingin menggunakan kelas datetime tidak apa-apa juga tapi ini sama mudahnya. lebih jelasnya disini

Pecandu PHP
sumber
0

Jawaban yang diterima sudah menjelaskan mengapa ini bukan tetapi, dan beberapa jawaban lain memberikan solusi yang rapi dengan ekspresi php seperti first day of the +2 months . Masalah dengan ekspresi tersebut adalah bahwa mereka tidak dilengkapi secara otomatis.

Solusinya cukup sederhana. Pertama, Anda harus menemukan abstraksi berguna yang mencerminkan ruang masalah Anda. Dalam hal ini, ini adalah ISO8601DateTime. Kedua, harus ada beberapa implementasi yang dapat menghadirkan representasi tekstual yang diinginkan. Sebagai contoh, Today, Tomorrow, The first day of this month, Future- semua merupakan implementasi khusus dari ISO8601DateTimekonsep.

Jadi, dalam kasus Anda, implementasi yang Anda butuhkan adalah TheFirstDayOfNMonthsLater. Sangat mudah untuk menemukannya hanya dengan melihat daftar subclass di IDE manapun. Berikut kodenya:

$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

Hal yang sama dengan hari-hari terakhir dalam sebulan. Untuk lebih banyak contoh dari pendekatan ini, baca ini .

Vadim Samokhin
sumber
-2
     $date = date('Y-m-d', strtotime("+1 month"));
     echo $date;
Mohammed F. Ghazo
sumber