Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

やりたいこと

  • 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で実装するのが良いでしょう。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away