# PHP DateTime 加減月問題 ###### tags: `PHP` PHP DateTime 的 [modify function](https://www.php.net/manual/en/datetime.modify.php) 很輕易地讓我們做日期加減,不過加減月份的時候有件事情要注意,假設遇到 31 號,加減月份會遇到非預期的結果,以下範例說明 ```php $dateTime1 = new DateTime('2023-05-31'); $dateTime1->modify('-1 month'); $dateTime1->format('m'); // 05 $dateTime1->format('Y-m-d'); // 2023-05-01 $dateTime2 = new DateTime('2023-05-31'); $dateTime2->modify('+1 month'); $dateTime2->format('m'); // 07 $dateTime2->format('Y-m-d'); //2023-07-01 ``` 從上面範例可以得知,要取 5/31 的上個月,卻仍回傳 5 月; 要取 5/31 的下個月,卻回傳 7 月。其實這跟 DateTime 行為有關,當 `-1 month`,DateTime 會把日期轉成 `2023-04-31`,4 月沒 31 號,於是進位成 `2023-05-01`,取到的月份就是 5。同理, `+1 month` 時日期會轉成 `2023-06-31`,6 月沒 31 號,於是進位成 `2023-07-01`,取到的月份就是 7。 如何解決這問題,最單純的做法是把時間先轉換成當月 1 號,再去加減月份,就能取到預期的月份了。如下: ```php $datetime1 = new DateTime('2023-05-31'); $datetime1->modify('first day of this month')->modify('-1 month'); $datetime1->format('m'); // 04 $datetime1->format('Y-m-d'); // 2023-04-01 $datetime2 = new DateTime('2023-05-31'); $datetime2->modify('first day of this month')->modify('+1 month'); $datetime2->format('m'); // 06 $datetime2->format('Y-m-d'); //2023-06-01 ``` 如果使用 PHP 常見的時間處理套件 [Carbon](https://github.com/briannesbitt/Carbon),可以使用 [`subMonthsNoOverflow`, `addMonthNoOverflow` function](https://carbon.nesbot.com/docs/#api-addsub) 讓加減月不自動進位: ```php use Carbon\Carbon; $datetime1 = Carbon::createFromDate(2023, 5, 31); $datetime1->subMonthsNoOverflow(1); $datetime1->format('m'); // 04 $datetime1->format('Y-m-d'); // 2023-04-30 $datetime2 = Carbon::createFromDate(2023, 5, 31); $datetime2->addMonthsNoOverflow(1); $datetime2->format('m'); // 06 $datetime2->format('Y-m-d'); // 2023-06-30 ```