Amazon Linux上のOpenJDKをアップデートするとTimeZoneのデフォルトがおかしくなったというお話
はじめに
Amazon Linuxで動作するJavaのWebアプリケーションを動かしていたんだけれど、アップデートをするとどうにもログの出力日付がおかしい。
ということで色々調査してみてた結果、以下のTimeZoneのデフォルト値(取得方法は下記のソースコードを参照)が openjdk-7u79 と openjdk-7u85とで異なる結果を返していることが問題の根源である模様。
なお、コマンドの date で取得できる結果は JSTになっていることを確認済み。
(追記: Amazon Linuxでglibcが更新されると /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を変更する