PHP で世界の日の出、日の入り時刻表を作る

## はじめに
PHP で世界の日の出、日の入り時刻表を作ってみました。
タイムゾーン、開始日、間隔、終了日を設定すれば、その期間の日の出、日の入り時刻表が表示される感じです。

## サンプルコード
~~~SunriseSunsetList.php
<?php
$timeZone = 'Asia/Tokyo';
// $timeZone = 'America/New_York';
// $timeZone = 'Europe/Oslo';

$period = new DatePeriod(
    date_create('first day of this month', timezone_open($timeZone)),
    new DateInterval('P1D'),
    date_create('last day of this month +1 second', timezone_open($timeZone))
);

$location = timezone_open($timeZone)->getLocation();
printf('%10s%9s%8s' . PHP_EOL, 'date', 'sunrise', 'sunset');

foreach ($period as $day) {
    $sunInfo = date_sun_info(
        $day->getTimeStamp(),
        $location['latitude'],
        $location['longitude']
    );

    printf('%s%9s%8s' . PHP_EOL,
        $day->format('Y-m-d'),
        $day->setTimeStamp($sunInfo['sunrise'])->format('H:i'),
        $day->setTimeStamp($sunInfo['sunset'])->format('H:i')
    );
}
~~~

まずはじめに日の出、日の入り時刻を調べたい都市のタイムゾーンを $timeZone に代入。
[サポートされるタイムゾーンのリスト](http://php.net/manual/ja/timezones.php) から、いろいろな都市のタイムゾーンを選ぶことができる。

[DatePeriod::__construct](http://jp1.php.net/manual/ja/dateperiod.construct.php) では、開始日、間隔、終了日を設定。[DateInterval::__construct](http://www.php.net/manual/ja/dateinterval.construct.php) の値を変えることによって、特定の月の時刻表や、一年を通して各月初めの時刻表など、さまざまな間隔での日の出、日の入り時刻表を作成できる。

~~~AboutDateInterval.php
// period を表す P を最初につける
new DateInterval('P1D'); // 一日ごと
new DateInterval('P2W'); // 二週間ごと
new DateInterval('P3M'); // 三ヶ月ごと

// 時間を含む場合は、時間部分の前に文字 T を入れる
new DateInterval('PT1H'); // 一時間ごと
new DateInterval('PT1M'); // 一分ごと
~~~

[DateTimeZone::getLocation](http://www.php.net/manual/ja/datetimezone.getlocation.php) では、タイムゾーンの位置情報   (国コード、緯度/経度、コメント) が取得できるので、この値を使って日の出、日の入り時刻を計算する。

今回のサンプルコードでは [date_sun_info](http://www.php.net/manual/ja/function.date-sun-info.php) という関数を利用した。日の出時刻だけや、日の入り時刻だけ取得したい場合などは [date_sunrise](http://www.php.net/manual/ja/function.date-sunrise.php), [date_sunset](http://www.php.net/manual/ja/function.date-sunset.php) という関数でもよさそう。date_sun_info ではタイムスタンプ、緯度、経度を指定する。すると日の出、日の入り時刻などさまざまな情報がタイムスタンプとして配列で返ってくるので、あとはその値をいい感じにフォーマットして表示する。

以下は、東京の 2014-04-01 から 2014-04-30 まで一日ごとの日の出、日の入り時刻表になる。

~~~sh
$ php SunriseSunsetList.php
      date  sunrise  sunset
2014-04-01    05:27   18:02
2014-04-02    05:26   18:03
2014-04-03    05:24   18:03
(省略)
2014-04-28    04:52   18:24
2014-04-29    04:51   18:25
2014-04-30    04:50   18:26
~~~

例えば、ノルウェーの首都オスロのタイムゾーンで 2014-01 から 2014-12 まで各月初めの日の出、日の入り時刻表を表示したい場合は以下のようにする。

~~~SunriseSunsetList.php
<?php
$timeZone = 'Europe/Oslo';

$period = new DatePeriod(
    date_create('2014-01', timezone_open($timeZone)),
    new DateInterval('P1M'),
    date_create('2014-12 +1 second', timezone_open($timeZone))
);
~~~

結果は以下。

~~~sh
$ php SunriseSunsetList.php
      date  sunrise  sunset
2014-01-01    09:18   15:23
2014-02-01    08:29   16:31
2014-03-01    07:14   17:44
2014-04-01    06:41   20:00
2014-05-01    05:14   21:13
2014-06-01    04:06   22:23
2014-07-01    04:00   22:41
2014-08-01    04:58   21:47
2014-09-01    06:12   20:21
2014-10-01    07:22   18:50
2014-11-01    07:39   16:22
2014-12-01    08:51   15:20
~~~

東京とはかなり違いますね。
ちなみに、南極のどこかのタイムゾーンにすると sunrise, sunset ともに同じ値になる日がある。
おそらく白夜かなとか、勝手に思ってます。

## 照らし合わせ
一応、本当に合っているかチェックするために、[日の出日の入り（世界地名選択)](http://keisan.casio.jp/exec/system/1253955558) で計算されたものと照らし合わせると、一致している、もしくは 1, 2 分の誤差が発生する程度でした。

## 備考
[date_create](http://www.php.net/manual/ja/function.date-create.php) は [DateTime::__construct](http://www.php.net/manual/ja/datetime.construct.php)
[timezone_open](http://www.php.net/manual/ja/function.timezone-open.php) は [DateTimeZone::__construct](http://www.php.net/manual/ja/datetimezone.construct.php) の別名です。

~~~AboutDateTimeAlias.php
<?php
// 別名を使うことによって一行で日時が表示できるなどの利点があったり、
// PHP 5.2 もしくは 5.3 でも動作させることができる
echo date_create()->format('Y-m-d') . PHP_EOL;

// 以下でも上記と同じことができるが PHP 5.4 以降でしか動作しない
echo (new DateTime)->format('Y-m-d') . PHP_EOL;
~~~

また、今回のサンプルコードでは、タイムゾーンから緯度/経度を取得しているが、
もう少し細かく都市などを指定したい場合は、どこかから緯度/経度を引っ張ってきてやる必要が出てくる。

## 参考リンク
- [PHP: DateTime - Manual](http://www.php.net/manual/ja/class.datetime.php)
- [DateTimeクラスを使ったモダンな日付処理 : アシアルブログ](http://blog.asial.co.jp/704)
- [phpでタイムゾーンの"日の出/日没"時間、"時間差"を取得 - Qiita] (http://qiita.com/mohsenreza/items/50213a0ae71aa7eceea4)