Carbon 1と2での動作変更点

# 概要

以下のドキュメントにCarbon 2への移行について記載がありますが、それぞれについてtinkerを利用して実際に動作を確認していきます。

https://carbon.nesbot.com/docs/#api-carbon-2

## 検証に利用したバージョン

* Carbon 1: 1.39.1
* Carbon 2: 2.48.0

# 動作確認

## デフォルトの日付

> Default values (when parameters are omitted) for $month and $day in the ::create() method are now 1 (were values from current date in Carbon 1). And default values for $hour, $minute and $second are now 0, this goes for omitted values, but you still can pass explicitly null to get the current value from now (similar behavior as in Carbon 1).

### Carbon 1

```php
>>> Carbon::create()
=> Carbon\Carbon @1621653995 {#3168
     date: 2021-05-22 12:26:35.0 Asia/Tokyo (+09:00),
   }
```

現在日時が返されています。

### Carbon 2

```php
>>> Carbon::create()
=> Carbon\Carbon @-62167252739 {#4825
     date: 0000-01-01 00:00:00.0 Asia/Tokyo (+09:18),
   }
```

年と月のデフォルトが1になっていて、そのほかは0になっています。

```php
\Carbon\Carbon::create(null, null, null, null, null, null)
=> Carbon\Carbon @1621655137 {#4827
     date: 2021-05-22 12:45:37.954871 Asia/Tokyo (+09:00),
   }
```

それぞれに `null` を渡すことで現在日時が利用されるようになっています。

## マイクロ秒精度

> Now you get microsecond precision everywhere, it also means 2 dates in the same second but not in the same microsecond are no longer equal.

どこでもマイクロ秒の精度が得られるようになり、秒まで同じでも2つの日付が等しくなくなったとあります。

比較すべきコードが思いつきませんでしたが、以下の結果は1と2で同じでした。

### Carbon 1

```php
>>> Carbon::now()->equalTo(Carbon::now())
=> false
```

### Carbon 2

```php
>>> Carbon::now()->equalTo(Carbon::now())
=> false
```

## JSONシリアライズ

> `$date->jsonSerialize()` and `json_encode($date)` no longer returns arrays but simple strings: `"2017-06-27T13:14:15.000000Z"`. This allows to create dates from it easier in JavaScript. You still can get the previous behavior using:

```php
Carbon::serializeUsing(function ($date) {
    return [
        'date' => $date->toDateTimeString(),
    ] + (array) $date->tz;
});
```

`jsonSerialize`と`json_encode`は配列を返さなくなり、文字列を返すようになったとのこと。しかし、`serializeUsing`で前のように返すことも可能とのこと。

### Carbon 1

```php
>>> // シリアライズ未設定
>>> $dt = Carbon::now()
=> Carbon\Carbon @1621739556 {#3179
     date: 2021-05-23 12:12:36.362641 Asia/Tokyo (+09:00),
   }
>>> $dt->jsonSerialize()
=> []
>>> json_encode($dt)
=> "[]"
    
>>> // シリアライズ設定
>>> Carbon::serializeUsing(function ($date) {
...     return [
...         'date' => $date->toDateTimeString(),
...     ] + (array) $date->tz;
... });
=> null
>>> $dt->jsonSerialize()
=> [
     "date" => "2021-05-23 10:39:51",
     "timezone_type" => 3,
     "timezone" => "Asia/Tokyo",
   ]
>>> json_encode($dt)
=> "{"date":"2021-05-23 10:43:54","timezone_type":3,"timezone":"Asia\/Tokyo"}"

```

`serializeUsing` をする前は空の配列が返ってきていますが、その後は`serializeUsing`で設定した内容が返ってきていることがわかります。

シリアライズ未設定時に空の配列が返るのが正しい動作なのかは不明です。

### Carbon 2

```php
>>> $dt = Carbon::now()
>>> // シリアライズ未設定
=> Carbon\Carbon @1621734690 {#4826
     date: 2021-05-23 10:51:30.734085 Asia/Tokyo (+09:00),
   }
>>> $dt->jsonSerialize()
=> "2021-05-23T01:51:30.734085Z"
>>> json_encode($dt)
=> ""2021-05-23T01:51:30.734085Z""
    
>>> // シリアライズ設定
>>> Carbon::serializeUsing(function ($date) {                                                                                             ...     return [
...         'date' => $date->toDateTimeString(),
...     ] + (array) $date->tz;
... });
});
=> null
>>> $dt->jsonSerialize()
=> [
     "date" => "2021-05-23 10:51:30",
     "timezone_type" => 3,
     "timezone" => "Asia/Tokyo",
   ]
>>> json_encode($dt)                                                                                                                     
=> "{"date":"2021-05-23 10:51:30","timezone_type":3,"timezone":"Asia\/Tokyo"}"
```

`serializeUsing` をする前は文字列が返ってきていますが、その後は`serializeUsing`で設定した内容が返ってきていることがわかります。

## 文字列フォーマット

> `$date->setToStringFormat()` with a closure no longer return a format but a final string. So you can return any string and the following in Carbon 1:

```php
Carbon::setToStringFormat(function ($date) {
    return $date->year === 1976 ?
        'jS \o\f F g:i:s a' :
        'jS \o\f F, Y g:i:s a';
});
```

>  would become in Carbon 2:

```php
Carbon::setToStringFormat(function ($date) {
    return $date->formatLocalized($date->year === 1976 ?
        'jS \o\f F g:i:s a' :
        'jS \o\f F, Y g:i:s a'
    );
});
```

2では文字列フォーマットのクロージャではフォーマットではなく、最終的な文字列を返すようになったとのこと。ただし、2でもクロージャ内でフォーマットを指定することが可能とのこと。

### Carbon 1

```php
>>> Carbon::setToStringFormat(function ($date) {
...     return $date->year === 1976 ?
...         'jS \o\f F g:i:s a' :
...         'jS \o\f F, Y g:i:s a';
... });
=> null
>>> echo $dt
23rd of May, 2021 10:45:31 am⏎

```

フォーマットをクロージャ内で指定することで文字列化時に指定したフォーマットが指定されています。

### Carbon 2

```php
>>> Carbon::setToStringFormat(function ($date) {
...     return $date->year === 1976 ?
...         'jS \o\f F g:i:s a' :
...         'jS \o\f F, Y g:i:s a';
... });
=> null
>>> echo $dt
jS \o\f F, Y g:i:s a⏎
>>> Carbon::setToStringFormat(function ($date) {
...     return $date->formatLocalized($date->year === 1976 ?
...         'jS \o\f F g:i:s a' :
...         'jS \o\f F, Y g:i:s a'
...     );
... });
=> null
>>> echo $dt                                                                                                                             
jS \o\f F, Y g:i:s a⏎
```

クロージャ内で`formatLocalized`を返さないとフォーマット文字列がそのまま返ってきてるのはわかりますが、`formatLocalize`で返すようにしても変わりませんでした。バグ？？

## 週の初めと終わりの設定で例外が発生しなくなった

> `setWeekStartsAt` and `setWeekEndsAt` no longer throw exceptions on values out of ranges, but they are also deprecated.

### Carbon 1

```php
>>> Carbon::setWeekStartsAt(7)
InvalidArgumentException with message 'Day of a week should be greater than or equal to 0 and less than or equal to 6.'
```

### Carbon 2

```php
>>> Carbon::setWeekStartsAt(7)
=> null
```

## 同じ月の判定

> `isSameMonth` and `isCurrentMonth` now returns `false` for same month in different year but you can pass `false` as a second parameter of `isSameMonth` or first parameter of `isCurrentMonth` to compare ignoring the year.

同じ月でも年が違えば`false`を返すようになったとのこと。

### Carbon 1

```php
>>> $dt1 = Carbon::create(2021, 1, 1)
=> Carbon\Carbon @1609468118 {#3170
     date: 2021-01-01 11:28:38.0 Asia/Tokyo (+09:00),
   }
>>> $dt2 = Carbon::create(2020, 1, 1)
=> Carbon\Carbon @1577845721 {#3183
     date: 2020-01-01 11:28:41.0 Asia/Tokyo (+09:00),
   }
>>> $dt1->isSameMonth($dt2)
=> true
```

### Carbon 2

```php
>>> $dt1 = Carbon::create(2021, 1, 1)
=> Carbon\Carbon @1609426800 {#4827
     date: 2021-01-01 00:00:00.0 Asia/Tokyo (+09:00),
   }
>>> $dt2 = Carbon::create(2020, 1, 1)
=> Carbon\Carbon @1577804400 {#4837
     date: 2020-01-01 00:00:00.0 Asia/Tokyo (+09:00),
   }
>>> $dt1->isSameMonth($dt2)
=> false
```

## `CarbonInterval`が例外を投げるようになった

> In Carbon 1, calls of an unknown method on `CarbonInterval` (ex: `CarbonInterval::anything()`) just returned null. In Carbon 2 they throw an exception.

### Carbon 1

```php
>>> CarbonInterval::anything()
=> null
```

### Carbon 2

```php
>>> CarbonInterval::anything()
Carbon\Exceptions\BadFluentConstructorException with message 'Unknown fluent constructor 'anything'.'
```

## `dayOfYear`の数え方の変更

> In Carbon 1, `dayOfYear` started from `0`. In Carbon 2 it starts from `1`.

### Carbon 1

```php
>>> $dt = Carbon::create(2021, 1, 1)
=> Carbon\Carbon @1609469811 {#3165
     date: 2021-01-01 11:56:51.0 Asia/Tokyo (+09:00),
   }
>>> $dt->dayOfYear()
BadMethodCallException with message 'Method dayOfYear does not exist.'
```

そんなメソッドはないと怒られてしまう。。。

### Carbon 2

```php
>>> $dt = Carbon::create(2021, 1, 1)
=> Carbon\Carbon @1609426800 {#4833
     date: 2021-01-01 00:00:00.0 Asia/Tokyo (+09:00),
   }
>>> $dt->dayOfYear()
=> 1
```

## `addDay`などに`null`が渡されたときの動作の変更

> In Carbon 1, `null` was considered as `0` when passed to add/sub method (such as `addDays(null)`, `subMonths(null)`, etc.). In Carbon 2, it behaves the same as no parameters so default to `1`. Anyway, you're discouraged to pass `null` in such methods as it's ambiguous and the behavior for next major version is not guaranteed.

2では`null`が渡されたらデフォルトの動作になったとのこと。

### Carbon 1

```php
>>> $dt = Carbon::create(2021, 1, 1)
=> Carbon\Carbon @1609470044 {#3171
     date: 2021-01-01 12:00:44.0 Asia/Tokyo (+09:00),
   }
>>> $dt->addDay(null)
=> Carbon\Carbon @1609470044 {#3171
     date: 2021-01-01 12:00:44.0 Asia/Tokyo (+09:00),
   }
```

日付が変わっていません。

### Carbon 2

```php
>>> $dt = Carbon::create(2021, 1, 1)
=> Carbon\Carbon @1609426800 {#4833
     date: 2021-01-01 00:00:00.0 Asia/Tokyo (+09:00),
   }
>>> $dt->addDay(null)
=> Carbon\Carbon @1609513200 {#4833
     date: 2021-01-02 00:00:00.0 Asia/Tokyo (+09:00),
   }
```

日付が加算されています。

## その他削除されたメソッドなど

> * `::compareYearWithMonth()` and `::compareYearWithMonth()` have been removed. Strict comparisons are now the default. And you can use the next parameter of isSame/isCurrent set to false to get month-only comparisons.
> * As we dropped PHP 5, `$self` is no longer needed in mixins you should just use `$this` instead.
> * As PHP 7.1+ perfectly supports microseconds, `useMicrosecondsFallback` and `isMicrosecondsFallbackEnabled` are no longer needed and so have been removed.

このあたりまで確認しようとすると時間がかかりすぎるため気になる方はご自身で確認してみてください。