LoginSignup
5
3

More than 5 years have passed since last update.

Carbonで月日を変える時は、setDate()を使う

Posted at

やりたいこと

  • Carbon で「2016-07-31」を指定
  • この日付から同じ年の「4月1日」を取得したい

発生した問題

下記のように、month()day()で、4月1日を指定すると、なぜか2016-05-01となる。

<?php
namespace Acme;

use Carbon\Carbon;

require_once __DIR__ . '/vendor/autoload.php';

$date = Carbon::createFromDate(2016, 7, 31);
$date->month(4);
$date->day(1);

echo $date->format('Y-m-d'), PHP_EOL;
// 2016-05-01

これは、month(4)を実行した時点で、2016-04-31となってしまうため、これが2016-05-01に変換されてしまう。(これは、基底クラスの DateTime の挙動)

ここに、day(1)を実行しても日は変わらないので、結果として、2016-05-01となる。

対応1

month()を実行した時点で、存在しない日となるのが原因なので、day()を先に実行すれば、動作としては正常になります。

<?php
namespace Acme;

use Carbon\Carbon;

require_once __DIR__ . '/vendor/autoload.php';

$date = Carbon::createFromDate(2016, 7, 31);
// 日を先に変えておけば、挙動としては正しい
$date->day(1);
$date->month(4);

echo $date->format('Y-m-d'), PHP_EOL;
// 2016-04-01

対応2

setDate()で、アトミックに月と日を指定すれば、ok。

<?php
namespace Acme;

use Carbon\Carbon;

require_once __DIR__ . '/vendor/autoload.php';

$date = Carbon::createFromDate(2016, 7, 31);
$date->setDate($date->year, 4, 1);

echo $date->format('Y-m-d'), PHP_EOL;
// 2016-04-01

どちらで対応するか

どちらの対応でも動作しますが、対応1は、実行順を意識しておく必要があるのが難点です。「4月1日にする」という仕様だと、直感的にはmonth()から実行したくなるのに、その反対の実装が必要となります。

その点、対応2の場合、単にsetDate()を呼ぶだけなので、特段意識する必要はありません。

特別な理由が無い限りは、素直に対応2で実装するのが良いでしょう。

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3