WordPressで現在時刻を利用すると9時間ずれてしまう問題

こんにちは。WordPressで時刻を扱うと9時間ずれてしまいました。
あーまたかぁと思いながらその解決方法について調べてまとめました。

# 1. WordPressで時刻がずれてしまう問題
WordPress2.9 (2009年12月にリリースだそうで、もうずいぶんと前ですね) から内部的な時刻がUTC (世界標準時) が利用されるようになりました。
それに伴って`date('Y-m-d H:i:s');`なんて呼び出すと時刻が9時間遅れて出てくるようになってしまいました。
結論は`date_i18n('Y-m-d H:i:s');`を使え、ということでなのですがこの件について良く忘れてしまうので備忘録として。

# 2. 以前までの解決方法
## 2.1. date_default_timezone_setを使う方法
```php:wp-settings.php

 if ( function_exists( 'date_default_timezone_set' ) )
    date_default_timezone_set( 'Asia/Tokyo' );
```
参考サイト
http://kfc.myhome.cx/myblog/2012/02/wordpress%E3%81%A7timezone%E3%81%8C9%E6%99%82%E9%96%93%E3%81%9A%E3%82%8C%E3%82%8B/
(参考サイトにある`date_default_timezone_set( 'UTC+9' );`は現在では動きませんでした。)

wp-settings.phpを書き換えてしまう方法ですね。僕もやったことがあります。
でもwp-settings.phpは本体側にあたりますのでバージョンアップで書き換わる可能性大です。
また知らないところでUTCを使う前提でコーディングされている場合(他人のプラグインとか)もありますのでむやみに全体設定を書き換えるのは控えておいた方が良さそうです。

またfunctions.phpで同じように
`date_default_timezone_set('Asia/Tokyo');`
を定義してしまう方法もあります。
こちらは本体のアップデートした際の書き換えの影響を受けませんが、他で使われる可能性は同じですので控えた方が良さそうです。

参考サイト
http://ryus.co.jp/blog/phpdateminus9/

## 2.2. strtotimeで差分してしまう方法
`$now = date('Y-m-d H:i:s', strtotime('+9hour'));`
現在時刻に9時間プラスしてしまう方式ですね。
これならば本体が変わっても大丈夫！なのですが…、ちょっと心に引っかかるもの、ありませんか？

あり得ないかも知れませんがもしこのコードがタイムゾーンの違う海外で動かすことになったら…。
これまたあり得ないかも知れませんが日本がサマータイム制を導入して9時間ズレが変わってしまったら…。という懸念が生まれます。

# 3. 最近の時刻の取得方法

## 3.1. date_i18nを使ったWordPressでの解決方法
実はWordPressでもちゃんとこの問題を解決するための関数が用意されています。
`date_i18n('Y-m-d H:i:s');`
とすればdate()のような使い方をする事ができます。便利ですね！

参考サイト
http://ucwd.jp/blog/729
こちらの記事では'U'でユニックスタイムスタンプの拾い方まで紹介されています。

ちなみにi18nは
> I18n は、internationalization、すなわちアプリケーションを翻訳可能にするプロセスのことをいいます。 WordPress では、決まった方法で翻訳されるべき文字列をマークすることを意味します。 I と n の間に 18 文字あるため、これを i18n と呼びます。
> I18n for WordPress Developers - WordPress Codex 日本語版
> http://wpdocs.sourceforge.jp/I18n_for_WordPress_Developers

とのことです。


## 3.2. DateTimeを使う方法。
最近はPHPも格好良くなってきています。
date()よりも少し格好良く時刻を取得できます。
二手間にはなりますが

`$now = new DateTime('', new DateTimeZone('Asia/Tokyo'));`
として
`$now->format('Y-m-d H:i:s');`
とすることでタイムゾーンを指定して取得できます。

WordPressであれば
`$now = new DateTime('', new DateTimeZone(get_option('timezone_string')));`
とすることで、管理画面で設定されたタイムゾーンの文字列を取得することが出来ます。

![Screen Shot 2015-05-11 at 4.16.51 PM.png](https://qiita-image-store.s3.amazonaws.com/0/47327/91e83577-b551-eb07-bf76-dca13c275f1e.png)


参考サイト
http://wordpress.stackexchange.com/questions/8400/how-to-get-wordpress-time-zone-setting

# 4. まとめ
WordPressでサクッと時刻を取りたいときは
`date_i18n('Y-m-d H:i:s')`
を、時刻演算とかさせるときには
`$now = new DateTime('', new DateTimeZone(get_option('timezone_string')))`
で取得すると良さそうです。

`date_default_timezone_set()`の使用は避けた方が良いでしょう。
PHPやWordPress、コンピュータテクノロジ全般に言えることなのですがどうしても流行廃りがあります。
「あの頃はこれが良かったんだけれど…」と思っていても数年後にはダメーとなっていることがあるので注意が必要ですね。
僕も良く「ﾌﾟｰｸｽｸｽ」されてしまうので頑張ります。

また`date_i18n()`はWordPressの関数ですので他のPHPも扱っているとついつい忘れてしまいます。なので個人的にはDateTImeでの使い方に慣れるようにしてWordPress以外の場所でも使えるようにして覚えると汎用性が高いかな、と思っています。

# 5. コードでまとめ
```php
var_dump(get_the_time('Y-m-d H:i:s')); // 記事の時刻

var_dump(date('Y-m-d H:i:s')); // 9時間ずれ (1)

date_default_timezone_set( 'Asia/Tokyo' );
var_dump(date('Y-m-d H:i:s')); // 内部のタイムゾーンを設定し直す (2.1)
date_default_timezone_set( 'UTC' );


var_dump(date('Y-m-d H:i:s', strtotime('+9hour'))); // 9時間ズレは直る (2.2)

var_dump(date('Y-m-d H:i:s', strtotime(get_option('gmt_offset').'hours'))); // wp設定画面準拠 (2.2 bis)

var_dump(date_i18n('Y-m-d H:i:s')); // wp標準関数 (3.1)

$now = new DateTime('', new DateTimeZone(get_option('timezone_string'))); // wp設定画面準拠 (3.2)
var_dump($now->format('Y-m-d H:i:s'));
```

# 6. UTCとGMT
UTCとGMTって違いがよく分かりませんでしたが、調べると
> GMTは天体観測によって時刻をきめているが、UTCはSI(国際単位)で定義されている1秒を使っている。原子時計で時刻をきめているのである。GMTとUTCは似て非なるものなのであった。
> http://www.asahi-net.or.jp/~hi5k-stu/compt/utc_gmt.htm

とのことでした。また

> コンピュータで使っている時間は、GMTでもUTCでもない

とのことでした。そうなんですね。
ちなみにWordPressではデータベースのカラム名などにはGMTを使っていますね。
このカラムはかなり前のバージョンから存在していたように覚えていまして、その当時(2008年ごろ？)はウェブなどでもUTCよりGMTという表現が多かったように思います。