【PHP/Laravel】Carbonの日付計算メソッド - 単数形・複数形の違いについて

## 結論
- 現状の最新バージョンにおいても「挙動」については違いはない。
- ただし、公式としては以下のような使い分けを想定しているようである。
    - 単数系メソッド（例：addDay()/subYear()など）：日付を「1つ分だけ」計算する時
    - 複数形メソッド（例：addDays()/subYears()など）：「2つ分以上」計算する時
- 利用する際はライブラリのアップデート時に予期せぬ不具合を起こさないように公式の想定に準拠しておいた方が良さそう（今後のアップデートで単数系メソッドに引数を渡せないようになる可能性も考えられるため）

## 環境
| ソフトウェア | バージョン |
|------------|-----------|
| PHP        | 8.3.13    |
| Laravel    | 11.32.0   |
| Carbon     | 3.8.2     |

## 内容
PHPには標準DateTimeクラスを拡張したCarbonライブラリというものが存在します。
Laravelなどでは標準搭載されているので利用したことがある人も多いのではないでしょうか。

Carbonライブラリには日付を計算するメソッドとして単数系メソッド（例：addDay()/subYear()など）と複数形メソッド（例：addDays()/subYears()など）が用意されています。

具体的な違いについて理解するために、例えば「10月10日の3日後を取得したい」ケースを想定してみましょう。「日」の加算では`addDay`と`addDays`の2種類を利用できます。

メソッドの命名から`addDay`は「1日分だけ後ろの日付を取得できる（= 2日分以上後ろの日付を取得できない）」と仮定してみます。いざ確認してみましょう。

```php
php artisan tinker

> $date = new Carbon\Carbon('2024-10-10');
= Carbon\Carbon @1728518400 {#5207
    date: 2024-10-10 00:00:00.0 UTC (+00:00),
  }

// 引数なしパターンを検証
> $date->addDay();
= Carbon\Carbon @1728604800 {#5207
    date: 2024-10-11 00:00:00.0 UTC (+00:00),
  }

> $date = new Carbon\Carbon('2024-10-10');
= Carbon\Carbon @1728518400 {#5188
    date: 2024-10-10 00:00:00.0 UTC (+00:00),
  }

// 引数ありパターンを検証
> $date->addDay(3);
= Carbon\Carbon @1728777600 {#5188
    date: 2024-10-13 00:00:00.0 UTC (+00:00),
  }
```

あれ？「1日分後ろの日付」に加えて、引数を渡して「3日分後ろの日付」も取得できました🤔

一旦、これ自体は頭の片隅に置いてもう一方の`addDays`メソッドを試してみましょう。

```php
> $date = new Carbon\Carbon('2024-10-10');
= Carbon\Carbon @1728518400 {#5200
    date: 2024-10-10 00:00:00.0 UTC (+00:00),
  }

// 引数なしパターンを検証
> $date->addDays();
= Carbon\Carbon @1728604800 {#5198
    date: 2024-10-11 00:00:00.0 UTC (+00:00),
  }

> $date = new Carbon\Carbon('2024-10-10');
= Carbon\Carbon @1728518400 {#5188
    date: 2024-10-10 00:00:00.0 UTC (+00:00),
  }

// 引数ありパターンを検証
> $date->addDays(3);
= Carbon\Carbon @1728777600 {#5188
    date: 2024-10-13 00:00:00.0 UTC (+00:00),
  }
```

こちらは想像通りですね。
これらの結果から「挙動」について`Carbon 3.8.2`バージョンについては違いがないことが分かります。

そこで「公式の見解」を見てみましょう。
まずは[公式ドキュメント](https://carbon.nesbot.com/docs/)から確認してみます。
![](https://storage.googleapis.com/zenn-user-upload/8c8100a370f5-20241117.png)

まずは複数形の`addDays`メソッドでは`int|float $value = 1`と書いてありますね。納得できます。

次に単数系の`addDay`メソッドを見てみると`no arguments`と記載されています。（困惑）

次に実際のソースコード（[Carbon.php L390](https://github.com/briannesbitt/Carbon/blob/ff5272f4a18e591727c28f3bd64ec49f681d7a78/src/Carbon/Carbon.php#L390)）を確認してみます。

```src/Carbon/Carbon.php
// ※見やすさ観点でインデントを少なくしています。
 * @method $this addDays(int|float $value = 1) Add days (the $value count passed in) to the instance (using date interval).
 * @method $this addDay() Add one day to the instance (using date interval).
```

`Add one day to the instance`とあるように単数系の`addDay`メソッドでは「1日分のみ加算」することを想定していそうです。

また、テストコード（[AddTest.php L327](https://github.com/briannesbitt/Carbon/blob/ff5272f4a18e591727c28f3bd64ec49f681d7a78/tests/Carbon/AddTest.php#L327)）でも以下のような記述が見つかりました。

```tests/Carbon/AddTest.php
public function testAddDayPassingArg()
{
    // addDay should ideally be used without argument
    /** @var mixed $date */
    $date = Carbon::createFromDate(1975, 5, 10);
    $this->assertSame(12, $date->addDay(2)->day);
}
```

「addDayメソッドは、引数なしで使うのが望ましい」と書かれていますね。

以上の確認から今回のようなケースの場合では「`addDays`メソッドに引数を渡して利用すること」が公式の見解に則っていると言えるでしょう。（逆に「翌日の日付を取得したい場合」は`addDay`メソッドを利用する）

今後のバージョンアップで仕様が変更される可能性もあるため、利用する際は公式の見解に従ってコーディングすることをお勧めします。

ここまでお読み頂き、ありがとうございました。