先日 Java の Web アプリでログに出力される時間が UTC で出力されるという事がありました。日本に住んでいるので JST で表示されないと紛らわしくて困ります。
すぐに思いついたのが /etc/localtime
が UTC に対応するものになっていることでしたが、違いました。ちゃんと Asia/Tokyo に対応するものになっており date コマンドの出力も JST で表示されます。次に疑ったのは環境変数です。しかし、/proc/<pid>/environ
を見ても TZ などが設定されてはいません。ためしに TZ を設定して起動すると、意図通りログに出力される時間は JST で出力されています。とりあえずこれで直ると言えば直るのですが、どうも気になりますし、気持ち悪いです。
Web を検索していくつかのページを見て見ましたが、出てくるのは /etc/localtime
や環境変数と Java のシステムプロパティ user.timezone
のことだけです。
まずは検証用の簡単なコードを書きました。
1 2 3 4 5 6 7 |
public class Main { public static void main(String[] args) { System.out.println(new java.text.SimpleDateFormat("z").format(new java.util.Date())); System.out.println(java.util.TimeZone.getDefault().getID()); System.out.println(System.getProperty("user.timezone")); } } |
問題のあるサーバ上でこれを実行すると以下の結果を得ました。
1 2 3 4 |
$ java Main UTC Etc/UTC Etc/UTC |
次に、問題のないサーバで実行すると以下の結果を得ました。
1 2 3 4 |
$ java Main JST Asia/Tokyo Asia/Tokyo |
いずれのサーバでも /etc/timezone
は Asia/Tokyo になっていますし、環境変数やシステムプロパティも設定していません。
何か OS の設定が関係していると仮定し /etc 以下を探してみると…、ありました。/etc/timezone
です。問題のあるサーバにはこのファイルがあり、内容は Etc/UTC
になっていました。問題のないサーバではこのファイルはありませんでした。早速ファイルの内容を Asia/Tokyo
に書き換えて検証コードを実行すると、
1 2 3 4 |
$ java Main JST Asia/Tokyo Asia/Tokyo |
ビンゴです。
気になったので /etc/timezone の内容は Asia/Tokyo
のままにして /etc/localtime を UTC を指すようにして実行してみると
1 2 3 4 5 6 7 8 9 10 |
$ cat /etc/timezone Asia/Tokyo $ ls --time-style=iso -l /etc/localtime lrwxrwxrwx 1 root root 27 06-25 07:42 /etc/localtime -> /usr/share/zoneinfo/Etc/UTC $ date +%Z UTC $ java Main JST Asia/Tokyo Asia/Tokyo |
予想通り /etc/localtime
よりも /etc/timezone
の方が優先されるようです。
この /etc/timezone
は debian 系の Ubuntu にはありましたが Red Hat 系の CentOS や Scientific Linux には確認した限りではありませんでした。ちなみに Red Hat 系のディストリビューションでも /etc/timezone
を作ってやるとそちらが優先されました。
今回の検証は Ubuntu 12.04 及び Scientific Linux 6.4 上で行いました。
java.util.TimeZone
では最終的に native メソッドを呼んでいるため他の環境では結果が異なるかもしれません。