日付時刻関連のクラスを活用しよう

以下も併せてお読みください。

- [日付時刻関連で使われる書式の調査](http://qiita.com/mpyw/items/55df438d12ef8e94dbc5)
- ["厳密に" 日付時刻のフォーマットをチェックする](http://qiita.com/mpyw/items/d8c12ced65a1cd87c630)

# クラス一覧

<table>
<tr>
<th colspan="2">クラス名 (実装しているインターフェースも示す)</th><th>イミュータブル</th><th>用途</th>
</tr>
<tr>
<td colspan="2"><a href="#datetimezone%E3%82%AF%E3%83%A9%E3%82%B9">DateTimeZone</a></td><td>○</td><td>タイムゾーン</td>
</tr>
<tr>
<td colspan="2"><a href="#dateinterval%E3%82%AF%E3%83%A9%E3%82%B9">DateInterval</a></td><td>○</td><td>時間</td>
</tr>
<tr>
<td rowspan="2"><code>DateTimeInterface</code></td><td><a href="#datetime%E3%82%AF%E3%83%A9%E3%82%B9">DateTime</a></td><td>×</td><td rowspan="2">日付時刻</td>
</tr>
<tr>
<td><a href="#datetimeimmutable%E3%82%AF%E3%83%A9%E3%82%B9">DateTimeImmutable</a></td><td>○</td>
</tr>
<tr>
<td><code>Traversable</code></td><td><a href="#dateperiod%E3%82%AF%E3%83%A9%E3%82%B9">DatePeriod</a></td><td>○</td><td>期間</td>
</tr>
</table>

# 各クラスの基本的な使い方

## [DateTimeZone]クラス

タイムゾーンを定義するクラスです。このクラスは再度外部から能動的に`__construct()`をコールしない限りはイミュータブルが保証されます。

### インスタンスの生成

[サポートされるタイムゾーンのリスト]にある名称または`+0900`のような時差を表す文字列を第1引数としてコンストラクタに与えます。

```php:現在&nbsp;(2通り)
$tz = new \DateTimeZone('Asia/Tokyo');
$tz = new \DateTimeZone('+0900');
```

## [DateInterval]クラス

時間を定義するクラスです。このクラスは再度外部から能動的に`__construct()`をコールしない限りはイミュータブルが保証されます。

### インスタンスの生成 ([時間の入力書式]を利用)

[時間の入力書式]に従う文字列を第1引数としてコンストラクタに与えます。

```php:簡単な例
$two_days = new \DateInterval('P2D');
$two_weeks = new \DateInterval('P2W');
$two_seconds = new \DateInterval('PT2S');
$six_years_and_five_minutes = new \DateInterval('P6YT5M');
```

### インスタンスの生成 ([日付時刻の入力書式]を利用)

[日付時刻の入力書式]に従う文字列を第1引数として[DateInterval::createFromDateString]に与えます。

```php:簡単な例
$two_days = \DateInterval::createFromDateString('2 days');
$two_weeks = \DateInterval::createFromDateString('2 weeks');
$two_seconds = \DateInterval::createFromDateString('2 seconds');
$six_years_and_five_minutes = \DateInterval::createFromDateString('6 years 5 minutes');
```

こちらの方法を用いると、より複雑な表現も可能です。

```php:複雑な例
// 平日1日ごと
$next_weekdays = \DateInterval::createFromDateString('next weekdays');
// 月末ごと
$last_day_of_next_month = \DateInterval::createFromDateString('last day of next month');
```

### フォーマット出力

[時間の出力書式]に従う文字列を第1引数として[DateInterval::format]に与えます。

```php:「日」「時」を取り出す
$interval = new \DateInterval('P2DT6H');
echo $interval->format('%d日と%h時間'); // 2日と6時間 
```

[var_dump]してみると実際に設定されているプロパティが確認できます。詳細に関しては[時間の入力書式]を参照してください。

```php:var_dumpでプロパティを確認
$interval = new \DateInterval('P2DT6H');
var_dump($interval);
/*
object(DateInterval)#1 (15) {
  ["y"]=>
  int(0)
  ["m"]=>
  int(0)
  ["d"]=>
  int(2)
  ["h"]=>
  int(6)
  ["i"]=>
  int(0)
  ["s"]=>
  int(0)
  ["weekday"]=>
  int(0)
  ["weekday_behavior"]=>
  int(0)
  ["first_last_day_of"]=>
  int(0)
  ["invert"]=>
  int(0)
  ["days"]=>
  bool(false)
  ["special_type"]=>
  int(0)
  ["special_amount"]=>
  int(0)
  ["have_weekday_relative"]=>
  int(0)
  ["have_special_relative"]=>
  int(0)
}
*/
```

## [DateTime]クラス

日付時刻を定義するクラスです。このクラスは**ミュータブル**に設計されているので、再度外部から能動的に`__construct()`をコールする、なんて変なことしなくても内部状態が変化します。

### インスタンスの生成

[日付時刻の入力書式]に従う文字列を第1引数としてコンストラクタに与えます。

```php:現在&nbsp;(3通り)
$date = new \DateTime;
$date = new \DateTime();
$date = new \DateTime('now');
```

### インスタンスの生成 (タイムゾーンを指定)

[日付時刻の入力書式]に従う文字列を第1引数、[DateTimeZone]を第2引数としてコンストラクタに与えます。書式中で指定することも可能ではありますが、あまり推奨されません。また、両方を指定した場合は**書式中のタイムゾーンが優先**されます。

```php:現在の東京
$date = new \DateTime('now', new \DateTimeZone('Asia/Tokyo')); // OK
$date = new \DateTime('now', new \DateTimeZone('+0900'));      // OK
$date = new \DateTime('now Asia/Tokyo');                       // 非推奨
$date = new \DateTime('now +0900');                            // そもそも意味が異なる！ダメ
```

上記の例の4番目の例だけは意味が異なることに注意してください。これは以下のような解釈が為されるものです。

1. [date_default_timezone_get]で得られる**デフォルトタイムゾーン**に従った現在時刻を得る。
2. その時刻がタイムゾーン`+0900`のものであると**見なす**。

バグか仕様のどちらであるかは不明ですが、何れにせよ進んで使うべき書式ではないとは言えるでしょう。相対指定を用いる際は特に書式中で指定せずに[DateTimeZone]オブジェクトとして第2引数で与えることが強く推奨されます。

### インスタンスの生成 (書式を指定)

[日付時刻の入力書式定義のための書式]に従う文字列を第1引数、自分で定義した書式に従う文字列を第2引数として[DateTime::createFromFormat]に与えます。コンストラクタをそのまま使うだけでは解釈に曖昧さが出る問題や、日本語に対応していないといった問題を解消することが出来る有用なメソッドです。外部入力に対しての利用が特に推奨されます。

```php:日本語の日付時刻をパースする
$date = \DateTime::createFromFormat('Y年n月j?*G時i分s秒', '2015年3月18日　　　　　13時04分06秒');
if ($date !== false) {
    echo $date->format('Y-m-d H:i:s'); // 2015-03-18 13:04:06
}
```

### フォーマット出力

[日付時刻の出力書式]に従う文字列を第1引数として[DateTimeInterface::format]に与えます。

```php:頭にゼロを付ける
$date = new \DateTime('2015-01-02 15:04:05');
$ampm = ['am' => '午前', 'pm' => '午後'];
echo $date->format('Y年m月d日') . $ampm[$date->format('a')] . $date->format('h時i分s秒');
// 2015年01月02日午後03時04分05秒
```

```php:頭にゼロを付けない&nbsp;(分と秒に関してはゼロ抜き書式が用意されていないので強引に処理する)
$date = new \DateTime('2015-01-02 15:04:05');
$ampm = ['am' => '午前', 'pm' => '午後'];
echo $date->format('Y年n月j日') . $ampm[$date->format('a')] . $date->format('g時')
     . ltrim($date->format('i分'), 0) . ltrim($date->format('s秒'), 0);
// 2015年1月2日午後3時4分5秒
```

### 内部状態の変更

既に生成したオブジェクトが持つ日付時刻情報を後から操作するためのメソッドが用意されています。ここでは`__construct()`も後から操作するためのメソッドの一つとして見なします。

| メソッド名 | 第1引数 | 第2引数 | 第3引数 | 返り値 | 範囲外の月日時分秒の指定 | 注記 |
|:----:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| [DateTime::__construct] | 日付時刻<br />(文字列) | [DateTimeZone] | | `NULL` | <ul><li>`31`日以内は自動補正</li><li>それ以外は[Exception]をスロー</li></ul> | **書式中のタイムゾーン優先** |
| [DateTime::modify] | 日付時刻<br />(文字列) | | | `$this` | <ul><li>`31`日以内は自動補正</li><li>それ以外は[Exception]をスロー</li></ul> | <ul><li>**タイムゾーン不可**</li><li>**タイムスタンプ不可**</li></ul> |
| [DateTime::setDate] | 年<br />(整数) | 月<br />(整数) | 日<br />(整数) | `$this` | 自動補正 | 時刻には影響無し|
| [DateTime::setISODate] | 年<br />(整数) | 週番号<br />(整数) | 曜日番号<br />(整数) | `$this` | 自動補正 | 時刻には影響無し |
| [DateTime::setTime] | 時<br />(整数) | 分<br />(整数) | 秒<br />(整数) | `$this` | 自動補正 | 日付には影響無し |
| [DateTime::setTimestamp] | タイムスタンプ<br />(整数) | | | `$this` |  | 32bit環境では**2038年問題**に注意 |
| [DateTime::setTimezone] | [DateTimeZone] | | | `$this` |  | 日付時刻の再計算が行われる |
| [DateTime::add] | 加算する[DateInterval] | | | `$this` |  | |
| [DateTime::sub] | 減算する[DateInterval] | | | `$this` |  | |

```php:setDateメソッドを利用
$date = new \DateTime('13:04:06', new \DateTimeZone('Asia/Tokyo'));
$date->setDate(2015, 2, 46); // 2月46日は存在しないので自動補正がかかる
echo $date->format('Y-m-d H:i:s e'); // 2015-03-18 13:04:06 Asia/Tokyo
```

```php:setISODateメソッドを利用
$date = new \DateTime('13:04:06', new \DateTimeZone('Asia/Tokyo'));
$date->setISODate(2015, 12, 3); // 12週目の水曜日
echo $date->format('Y-m-d H:i:s e'); // 2015-03-18 13:04:06 Asia/Tokyo
```

```php:setTimeメソッドを利用
$date = new \DateTime('2015-03-18', new \DateTimeZone('Asia/Tokyo'));
$date->setTime(13, 4, 6);
echo $date->format('Y-m-d H:i:s e'); // 2015-03-18 13:04:06 Asia/Tokyo
```

```php:setTimezoneメソッドを利用
$date = new \DateTime('2015-03-10 04:04:06', new \DateTimeZone('UTC'));
$date->setTimezone(new \DateTimeZone('Asia/Tokyo'));
echo $date->format('Y-m-d H:i:s e'); // 2015-03-10 13:04:06 Asia/Tokyo
```

```php:Datetime&#58;&#58;modifyメソッドで代用&nbsp;(2通り)
$date->modify('2015-03-18');
$date->modify('2015-W12-3');
```

```php:__constructを能動的にコール
$date = new \DateTime('now', new \DateTimeZone('UTC'));
$date->__construct('2015-03-18 13:04:06', new \DateTimeZone('Asia/Tokyo'));
echo $date->format('Y-m-d H:i:s e'); // 2015-03-18 13:04:06 Asia/Tokyo
```

```php:\$dateに2日間足して、それから\$a(7日間)の分だけ足し、更に$b(1日間)の分だけ引く
$a = new \DateInterval('P7D');
$b = new \DateInterval('P1D');
$date = new \DateTime('2015-03-10');
$date->modify('+2 days')->add($a)->sub($b);
echo $date->format('Y-m-d'); // 2015-03-18
```

### 2つの[DateTimeInterface]の差を求める

[DateTimeInterface::diff]を実行し、返り値として得られる[DateInterval]オブジェクトを利用します。

```php:2015-01-01とその1年後の差を求める
$today = new \DateTime('2015-01-01');
$next_year = new \DateTime('2016-01-01');
var_dump($today->diff($next_year));
/*
object(DateInterval)#3 (15) {
  ["y"]=>
  int(1)
  ["m"]=>
  int(0)
  ["d"]=>
  int(0)
  ["h"]=>
  int(0)
  ["i"]=>
  int(0)
  ["s"]=>
  int(0)
  ["weekday"]=>
  int(0)
  ["weekday_behavior"]=>
  int(0)
  ["first_last_day_of"]=>
  int(0)
  ["invert"]=>
  int(0)
  ["days"]=>
  int(366)
  ["special_type"]=>
  int(0)
  ["special_amount"]=>
  int(0)
  ["have_weekday_relative"]=>
  int(0)
  ["have_special_relative"]=>
  int(0)
}
*/
```

当たり前ですが、[var_dump]の結果、1年の差があることが確認できました。更に、最初に[DateInterval]を自分で生成したときとは異なり、**`days`**というプロパティが設定されていることも確認できます。このプロパティは[DateTimeInterface::diff]によって生成されたときにのみ自動で設定されるものであり、**総日数**を表します。

```php:DateInteval&#58;&#58;formatで総日数を表示させることもできる
$today = new \DateTime('2015-01-01');
$next_year = new \DateTime('2016-01-01');
echo $today->diff($next_year)->format('%a日間'); // 366日間 (2016年は閏年) 
```

また、この演算によって得られた結果が正の時間になっていることも意識してください。[時間の入力書式]でも説明していますが、`invert`というプロパティは正負の逆転を意味するものであり、[DateTimeInterface::diff]で小さいほうから大きいほうを引く演算が行われたときにのみ、自動で`1`に設定されるようになっています。今回は `0` のままなので正を意味します。

…ところが、少し違和感がありませんか？

```php
$today->diff($next_year)
```

このコード、直感的には「呼び出し元から引数を引く」ように感じる人が多いのではないでしょうか？実際はその**逆**です。<ins>「引数から呼び出し元を引く」</ins>と考えるのが正しいです。誤解を招きやすい設計になっているので十分留意してください。この点は[DateTime::sub]とは大きく感覚が異なります。

## [DateTimeImmutable]クラス

[DateTime]クラスとほとんど同じメソッドを持ちます。このクラスは[DateTime]クラスとは異なり、再度外部から能動的に`__construct()`をコールしない限りはイミュータブルが保証されます。PHP5.4以前との互換性を気にする必要がない場合、**積極的に[DateTime]の代わりに[DateTimeImmutable]を使うべき**であると言えるでしょう。本来[DateTime]がイミュータブルに設計されるべきであるにも関わらず、ミュータブルな設計になっていたPHPを異常だと考えるべきです。

```php:\$dateに2日間足して、それから\$a(7日間)の分だけ足し、更に\$b(1日間)の分だけ引いたものを\$newdateに代入する
$a = new \DateInterval('P7D');
$b = new \DateInterval('P1D');
$date = new \DateTimeImmutable('2015-03-10');
$newdate = $date->modify('+2 days')->add($a)->sub($b);
echo $date->format('Y-m-d') . PHP_EOL;    // 2015-03-10 (変更されていない)
echo $newdate->format('Y-m-d') . PHP_EOL; // 2015-03-18
```

`modify` は英単語的には「修正する」という意味ですが、新しくインスタンスを作り直しているあたりがやや直感とのギャップを生んでいるかもしれません。

## [DatePeriod]クラス

一定区間または一定回数の間だけ、[DateInterval]ごとに[DateTimeInterface]を取り出すクラスです。`Iterator`インターフェースは実装されていませんが、`Traversable`インターフェースはされているので、`foreach`構文で取り扱ったり[iterator_to_array]関数で配列に変換したりすることができます。

コンストラクタは引数の取り方が3通りあります。

```php
public DatePeriod::__construct ( DateTimeInterface $start , DateInterval $interval , int $recurrences [, int $options ] )
```
```php
public DatePeriod::__construct ( DateTimeInterface $start , DateInterval $interval , DateTimeInterface $end [, int $options ] )
```
```php
public DatePeriod::__construct ( string $isostr [, int $options ] )
```

但し、[DateTimeImmutable]を完全に受け付けられるようになったのは`5.5.8`以降であることにご注意ください。

![screenshot.2015-03-06.png](https://qiita-image-store.s3.amazonaws.com/0/25060/7a3e92ae-46de-c52e-a43c-e6804a020358.png)


### インスタンスの生成 (「開始日時」「反復間隔」「終了日時」の組み合わせ)

```php:2015-01-01から1日間隔で2015-01-05の直前まで繰り返す
print_r(array_map(
    function (\DateTimeInterface $date) { return $date->format('Y-m-d'); },
    iterator_to_array(new \DatePeriod(
        new \DateTime('2015-01-01'), // 開始日時 (ここから)
        new \DateInterval('P1D'),    // 反復間隔 (この間隔で)
        new \DateTime('2015-01-05')  // 終了日時 (ここの "直前" まで繰り返す)
    ))
));
/*
Array
(
    [0] => 2015-01-01
    [1] => 2015-01-02
    [2] => 2015-01-03
    [3] => 2015-01-04
)
*/
```

### インスタンスの生成 (「開始日時」「反復間隔]」「反復回数」の組み合わせ)

```php:2015-01-01から1日間隔で3回追加反復する
print_r(array_map(
    function (\DateTimeInterface $date) { return $date->format('Y-m-d'); },
    iterator_to_array(new \DatePeriod(
        new \DateTime('2015-01-01'), // 開始日時 (ここから)
        new \DateInterval('P1D'),    // 反復間隔 (この間隔で)
        3                            // 反復回数 (この回数だけ追加で繰り返す)
    ))
));
/*
Array
(
    [0] => 2015-01-01
    [1] => 2015-01-02
    [2] => 2015-01-03
    [3] => 2015-01-04
)
*/
```

### インスタンスの生成 (「ISO8601書式」)

[期間の入力書式]に従います。

```php:上で紹介したものはISO8601形式の文字列でも表現できる
print_r(array_map(
    function (\DateTimeInterface $date) { return $date->format('Y-m-d'); },
    iterator_to_array(new \DatePeriod('2015-01-01T00:00:00Z/P1D/2015-01-05T00:00:00Z'))
));

print_r(array_map(
    function (\DateTimeInterface $date) { return $date->format('Y-m-d'); },
    iterator_to_array(new \DatePeriod('2015-01-01T00:00:00Z/P1D/R3'))
));
```

### インスタンスの生成 (開始日の除外)

`DatePeriod::EXCLUDE_START_DATE`を追加の引数として渡します。

```php:2015-01-01の直後から1日間隔で2015-01-05の直前まで繰り返す
print_r(array_map(
    function (\DateTimeInterface $date) { return $date->format('Y-m-d'); },
    iterator_to_array(new \DatePeriod(
        new \DateTime('2015-01-01'),    // 開始日時 (ここから)
        new \DateInterval('P1D'),       // 反復間隔 (この間隔で)
        new \DateTime('2015-01-05'),    // 終了日時 (ここの "直前" まで繰り返す)
        \DatePeriod::EXCLUDE_START_DATE // 但し開始日を除外する
    ))
));
/*
Array
(
    [0] => 2015-01-02
    [1] => 2015-01-03
    [2] => 2015-01-04
)
*/
```

### インスタンスの生成 (終了日の包含)

指定する[DateInterval]分だけ終了日時を引き延ばしておきます。

```php:2015-01-01から1日間隔で2015-01-06の直前まで繰り返す
$interval = new \DateInterval('P1D');
print_r(array_map(
    function (\DateTimeInterface $date) { return $date->format('Y-m-d'); },
    iterator_to_array(new \DatePeriod(
        new \DateTime('2015-01-01'),                  // 開始日時 (ここから)
        $interval,                                    // 反復間隔 (この間隔で)
        (new \DateTime('2015-01-05'))->add($interval) // 終了日時 (ここの "直前" まで繰り返す)
    ))
));
/*
Array
(
    [0] => 2015-01-01
    [1] => 2015-01-02
    [2] => 2015-01-03
    [3] => 2015-01-04
    [4] => 2015-01-05
)
*/
```

# 応用例

### 指定した[DateTimeImmutable]が属する月を1日単位で走査する[DatePeriod]を返す関数

簡単に言うと「1ヵ月の取得」です。

```php:実装と使用例
function get_month_period(\DateTimeImmutable $today) {
    return new \DatePeriod(
        $today->modify('today first day of'),
        new \DateInterval('P1D'),
        $today->modify('today first day of next month')
    );
}
foreach (get_month_period(new \DateTimeImmutable('2015-02-15')) as $date) {
    echo $date->format('Y-m-d') . PHP_EOL;
}
/*
2015-02-01
2015-02-02
2015-02-03
...
2015-02-26
2015-02-27
2015-02-28
*/
```

### 指定した2つの[DateTimeImmutable]が属する月同士の区間中に存在する全ての月末日を走査する[DatePeriod]を返す関数

簡単に言うと「全ての月末日の取得」です。

```php:実装と使用例
function get_last_days_period(\DateTimeImmutable $start, \DateTimeImmutable $end) {
    return new \DatePeriod(
        $start->modify('today last day of'),
        \DateInterval::createFromDateString('last day of next month'),
        $end->modify('today first day of next month')
    );
}
foreach (get_last_days_period(
    new \DateTimeImmutable('2015-09-27'),
    new \DateTimeImmutable('2016-03-15')
) as $date) {
    echo $date->format('Y-m-d') . PHP_EOL;
}
/*
2015-09-30
2015-10-31
2015-11-30
2015-12-31
2016-01-31
2016-02-29
2016-03-31
*/
```


### 指定した[DateTimeImmutable]が属する月が属する全ての日曜開始週を1日単位で走査する[DatePeriod]を返す関数

簡単に言うと「カレンダー」です。@rana_kualuさんが**[「PHPでナウいカレンダー」](http://qiita.com/rana_kualu/items/4c7c883d01e9d5ca43d9)**として実装されているものをもう少しシンプルにしてみました。日曜週開始の扱いに不安があったので、一応テストも行ってみました。

```php:実装と使用例
function get_calendar_period(\DateTimeImmutable $today) {
    return new \DatePeriod(
        $today->modify('first day of')->modify('Sunday last week'),
        new \DateInterval('P1D'),
        $today->modify('last day of')->modify('Sunday this week')
    );
}
foreach (get_calendar_period(new \DateTimeImmutable('2016-02-28')) as $i => $date) {
    echo $date->format('d ');
    if ($i % 7 === 6) {
        echo PHP_EOL;
    }
}
/*
31 01 02 03 04 05 06 
07 08 09 10 11 12 13 
14 15 16 17 18 19 20 
21 22 23 24 25 26 27 
28 29 01 02 03 04 05 
*/
```

```php:テスト&nbsp;(実装は省略)
// オブジェクトのままでは比較が面倒なので文字列に変換
function to_date_string(\DateTimeInterface $date) {
    return $date->format('Y-m-d');
}

// 年月を指定してテスト
function test($year, $month) {
    assert("
        array_map('to_date_string', iterator_to_array((new Calendar($year, $month))->getCalendar()))
        ===
        array_map('to_date_string', iterator_to_array(get_calendar_period(new \DateTimeImmutable('$year-$month'))))
    ");
}

// 1970年1月～2099年12月までをチェックしてみる (何も出力されなければ成功)
foreach (range(1970, 2099) as $year) {
    foreach (range(1, 12) as $month) {
        test($year, $month);
    }
}
```

なお、もし月曜開始にしたい場合は以下のように変更してください。

```php
function get_calendar_period(\DateTimeImmutable $today) {
    return new \DatePeriod(
        $today->modify('first day of')->modify('Monday this week'),
        new \DateInterval('P1D'),
        $today->modify('last day of')->modify('Monday next week')
    );
}
```

# バグ情報

- [DateTime::getTimestamp()すると日付が変わる件](http://qiita.com/rana_kualu/items/c535e63e75db2f059bde)
- [DateTimeで「front of」「back of」とタイムゾーンを組み合わせた時の挙動にバグがある件](http://qiita.com/mpyw/items/871e086d46a92276a0f3)

日付時刻関連のバグは非常に多いと思われます。公式に報告されているバグやご自身のブログ等に投稿されているバグなどで、注意すべきものがあれば報告していただければこちらに追加で掲載致します。

[日付時刻の入力書式]: http://qiita.com/mpyw/items/55df438d12ef8e94dbc5#%E6%97%A5%E4%BB%98%E6%99%82%E5%88%BB%E3%81%AE%E5%85%A5%E5%8A%9B%E6%9B%B8%E5%BC%8F
[日付時刻の入力書式定義のための書式]: http://qiita.com/mpyw/items/55df438d12ef8e94dbc5#%E6%97%A5%E4%BB%98%E6%99%82%E5%88%BB%E3%81%AE%E5%85%A5%E5%8A%9B%E6%9B%B8%E5%BC%8F%E5%AE%9A%E7%BE%A9%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E6%9B%B8%E5%BC%8F
[日付時刻の出力書式]: http://qiita.com/mpyw/items/55df438d12ef8e94dbc5#%E6%97%A5%E4%BB%98%E6%99%82%E5%88%BB%E3%81%AE%E5%87%BA%E5%8A%9B%E6%9B%B8%E5%BC%8F
[時間の入力書式]: http://qiita.com/mpyw/items/55df438d12ef8e94dbc5#%E6%99%82%E9%96%93%E3%81%AE%E5%85%A5%E5%8A%9B%E6%9B%B8%E5%BC%8F
[時間の出力書式]: http://qiita.com/mpyw/items/55df438d12ef8e94dbc5#%E6%99%82%E9%96%93%E3%81%AE%E5%87%BA%E5%8A%9B%E6%9B%B8%E5%BC%8F
[期間の入力書式]: http://qiita.com/mpyw/items/55df438d12ef8e94dbc5#%E6%9C%9F%E9%96%93%E3%81%AE%E5%85%A5%E5%8A%9B%E6%9B%B8%E5%BC%8F

[Exception]: http://www.php.net/manual/ja/class.exception.php
[DatePeriod]: http://www.php.net/manual/ja/class.dateperiod.php
[DateTime]: http://www.php.net/manual/ja/class.datetime.php
[DateTimeInterface]: http://www.php.net/manual/ja/class.datetimeinterface.php
[DateTimeImmutable]: http://www.php.net/manual/ja/class.datetimeimmutable.php
[DateInterval]: http://www.php.net/manual/ja/class.dateinterval.php
[DateTimeZone]: http://www.php.net/manual/ja/class.datetimezone.php
[DateTimeInterface::getTimestamp]: http://www.php.net/manual/ja/datetime.gettimestamp.php
[DateTime::createFromFormat]: http://www.php.net/manual/ja/datetime.createfromformat.php
[DateTimeImmutable::createFromFormat]: http://www.php.net/manual/ja/datetimeimmutable.createfromformat.php
[DateTime::__construct]: http://www.php.net/manual/ja/datetime.construct.php
[DateTimeImmutable::__construct]: http://www.php.net/manual/ja/datetimeimmutable.construct.php
[DateInterval::__construct]: http://www.php.net/manual/ja/dateinterval.construct.php
[DateTime::modify]: http://www.php.net/manual/ja/datetime.modify.php
[DateTimeImmutable::modify]: http://www.php.net/manual/ja/datetimeimmutable.modify.php
[DateTime::add]: http://www.php.net/manual/ja/datetime.add.php
[DateTime::sub]: http://www.php.net/manual/ja/datetime.sub.php
[DateTime::setDate]: http://www.php.net/manual/ja/datetime.setdate.php
[DateTime::setTime]: http://www.php.net/manual/ja/datetime.settime.php
[DateTime::setISODate]: http://www.php.net/manual/ja/datetime.setisodate.php
[DateTime::setTimestamp]: http://www.php.net/manual/ja/datetime.settimestamp.php
[DateTime::setTimezone]: http://www.php.net/manual/ja/datetime.settimezone.php
[DateTimeInterface::diff]: http://www.php.net/manual/ja/datetime.diff.php
[DateTimeInterface::format]: http://www.php.net/manual/ja/datetime.format.php
[DateInterval::format]: http://www.php.net/manual/ja/dateinterval.format.php
[DateInterval::createFromDateString]: http://www.php.net/manual/ja/dateinterval.createfromdatestring.php
[DateTimeInterface::diff]: http://www.php.net/manual/ja/datetime.diff.php
[strtotime]: http://www.php.net/manual/ja/function.strtotime.php
[date]: http://www.php.net/manual/ja/function.date.php
[idate]: http://www.php.net/manual/ja/function.idate.php
[date_default_timezone_get]: http://www.php.net/manual/ja/function.date-default-timezone-get.php
[var_dump]: http://www.php.net/manual/ja/function.var-dump.php
[iterator_to_array]: http://www.php.net/manual/ja/function.iterator-to-array.php
[サポートされるタイムゾーンのリスト]: http://www.php.net/manual/ja/timezones.php
[サポートする日付と時刻の書式]: http://www.php.net/manual/ja/datetime.formats.php
[相対的な書式]: http://www.php.net/manual/ja/datetime.formats.relative.php