CakePHP3のChronosの機能紹介

CakePHP3のChronosの公式ドキュメントを翻訳したので、
その機能についてご紹介します。

以前の記事[CakePHP3公式ドキュメントの翻訳が一石N鳥だった件](http://qiita.com/ishizuki/items/e569cf4c780b639ffb5b)でもご紹介しましたが、
私は「CakePHP3翻訳会」への参加を通じて翻訳を行なっていて、
その中のひとつとしてChronosを翻訳しました。

# Chronosとは
Chronosは、CakePHP3.2から導入された、日付時刻を扱うライブラリです。
[公式のリリース](http://bakery.cakephp.org/2016/01/02/cakephp_320rc1_released.html)には以下のように書いてあります。

>Carbon ライブラリを Chronos に置き換え
>
Carbon ライブラリは cakephp/chronos に置き換えられました。この新しいライブラリは Carbon のフォークで、依存関係は追加されていません。カレンダーのdateオブジェクト、イミュータブルなdateオブジェクトとdatetimeオブジェクトを提供します。

Carbonというライブラリは聞いたことが無かったのですが、
Chronosと同様に日付を扱うためのものだったようです。
しかし、あまりイケてないからCarbonをベースにして改良しようというアイデアから生まれました。（多分）
その経緯は[githubのissue](https://github.com/cakephp/cakephp/issues/6509)に残っています。

公式ドキュメントはこちらです（他の人が書き換えていなければ全文私が翻訳しました）
[Chronos(クロノス) — CakePHP Cookbook 3.x ドキュメント](http://book.cakephp.org/3.0/ja/chronos.html)

## Time

ちなみに、CakePHP3では、Chronosを直接使う必要はありません。
内部的には、 [Time](https://book.cakephp.org/3.0/ja/core-libraries/time.html) ユーティリティを動かすために、CakePHP は Chronos を利用しています。
Chronos と DateTime でできることはなんでも、 Time と Date ですることができます。

# Chronosの機能紹介
翻訳を通じて、ドキュメントを読むことになるので、
そこで分かったChronosの機能について紹介します。

## 単体テストが楽
これが一番の目玉だと感じました。
今までPHPでDateTimeを使っていて、それに関するユニットテストを書いていた方への朗報です。

>単体テストを書いている時、現在時刻を固定すると便利です。Chronosは、各クラスの現在時刻を修正することができます。

つまり、テストの前に固定の日時を注入すれば、Chronosの拡張クラスの現在日時を修正できるのです。
そして、実際のコードでそのクラスをnewしている箇所では、注入した日時のオブジェクトが取得でき、
また、現在時刻からの相対日時も取得できます。
以下がその例です。

```php
Chronos::setTestNow(new Chronos('1975-12-25 00:00:00'));

$time = new Chronos(); // 1975-12-25 00:00:00
$time = new Chronos('1 hour ago'); // 1975-12-24 23:00:00
```

これで、ユニットテストで時刻のためにメソッドをモックする苦労が無くなります。
ある特定の日時を再現するために`__getDateTime`とかのメソッドを追加したり、
`__getDateTime`をモックして特定の日時を返すようにする必要がなくなります。

## 日付の比較が簡単
便利メソッドが数々あります。
今まで手で計算していた方に多大な恩恵があります。

```php
// 比較のフルセットが存在します
// =
$first->eq($second);
// !=
$first->ne($second);
// >
$first->gt($second);
// >=
$first->gte($second);
// <
$first->lt($second);
// <=
$first->lte($second);

// カレントオブジェクトが2つのオブジェクトの間にあるかどうかを確認します。
$now->between($start, $end);

// どちらの引数が最も近い(closest)かを見つけます。
$now->closest($june, $november);
// どちらの引数が最も遠い(farthest)かを見つけます。
$now->farthest($june, $november);

//==========
// また、与えられた値のカレンダーに当たる場所について問い合わせできます。:
//==========

// 今日ですか
$now->isToday();
// 昨日ですか
$now->isYesterday();
// 未来ですか
$now->isFuture();
// 過去ですか
$now->isPast();

// 曜日をチェック
// 平日ですか
$now->isWeekday();
// 週末ですか
$now->isWeekend();

// 他の曜日のメソッドも全て存在します。
$now->isMonday();
$now->isSunday();

//==========
// また、値が相対的な期間内にあったかどうかを見つけることができます。:
//==========

$time->wasWithinLast('3 days');
$time->isWithinNext('3 hours');
```

## ある2つの日付の差分を求めるのが簡単
こちらも便利メソッドがたくさん

```php
// 差をあらわすDateIntervalを取得
$first->diff($second);

// 現在日時からの差を取得
Chronos::fromNow($datetime);

// 特定の単位での差を取得
$first->diffInSeconds($second);
$first->diffInMinutes($second);
$first->diffInHours($second);
$first->diffInDays($second);
$first->diffInWeeks($second);
$first->diffInYears($second);
```

フィードやタイムラインで使用するのに適した、人が読める形式の差を生成することができます。
cakephp/i18nを使えば日本語になると思いますが試していません。

```php
// 現在からの差
echo $date->diffForHumans();

// 別の時点からの差
echo $date->diffForHumans($other); // 1 hour ago;
```

## 日付要素の抽出が簡単
```php
$time = new Chronos('2015-12-31 23:59:58');
$time->year;    // 2015
$time->month;   // 12
$time->day;     // 31
$time->hour     // 23
$time->minute   // 59
$time->second   // 58
```

以下のプロパティにもアクセスできます。:

```php
- timezone
- timezoneName
- micro
- dayOfWeek
- dayOfMonth
- dayOfYear
- daysInMonth
- timestamp
- quarter
- weekOfMonth
- age
```