Amazon Linux上のOpenJDKをアップデートするとTimeZoneのデフォルトがおかしくなったというお話

はじめに

Amazon Linuxで動作するJavaのWebアプリケーションを動かしていたんだけれど、アップデートをするとどうにもログの出力日付がおかしい。
ということで色々調査してみてた結果、以下のTimeZoneのデフォルト値(取得方法は下記のソースコードを参照)が openjdk-7u79 と openjdk-7u85とで異なる結果を返していることが問題の根源である模様。

なお、コマンドの date で取得できる結果は JSTになっていることを確認済み。

(追記: Amazon Linuxglibcが更新されると /etc/localtime も合わせて更新されてしまい、システムの日付がJSTに設定されていたにも関わらずUTCに戻ってしまう現象もありますが、この問題の原因はこれとは異なり、純粋にopenjdkのみをupdateした場合に生じる問題です)

import java.util.*;

public class Test {
  public static void main(String[] args) {
    System.out.println(TimeZone.getDefault());
  }
}
// openjdk 7u79
sun.util.calendar.ZoneInfo[id="Asia/Tokyo",offset=32400000,dstSavings=0,useDaylight=false,transitions=10,lastRule=null]

// openjdk 7u85
sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]

バグなのかどうなのか良くわからないので、一応原因の調査をしてみることに

結論

デフォルト取得の仕様が変わっている模様。

Amazon LinuxでTimeZoneを変更する方法については date の結果だけを変更する方法*1がブログでは紹介されていることが多く、今回はそれしか実行していなかったが、Amazon Linuxのガイドをちゃんとみてみると /etc/sysconfig/clock の値を修正することがきちんと書いてある。

http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/set-time.html

この設定のZONEの値を "Asia/Tokyo" に修正してやれば、きちんとZoneInfoの値としてAsia/Tokyoを返すようになった。

おまけ

CentOS7/RHEL7 から時刻変更のためのコマンド timedatectl というコマンドが追加されている。

今回の検証中に問題がJVMのビルドなのかOSに依存するのか分からなかったため、RHEL7をローンチして調べていた。

その際にも検証のため /etc/localtime のみをJSTに更新していたが、このコマンドを知って現在の情報を表示してみると、全く関係ないTimezoneの値が表示されるにも関わらず、その時刻修正だけが(JST +0900)となっていた。

そのため、/etc/localtime のみではなく別のところでTimezoneの情報を保持していることが分かり、問題の原因らしきものと解決方法を発見することができた。

なお、この時に調査してみた限り、openjdk-8u51でも /etc/localtime に依存しないTimeZoneを返していたため、今後のバージョンアップでLinuxの時刻設定手法を表面的に実施している場合、アプリケーション側にしっぺ返しが来るかもしれません。

*1:/etc/localtimeを変更する