サマータイムを勝手に Amazon Linux 2 に導入してみる

最近(2018/8) サマータイム導入が議論されていて、賛否両論いろいろあるみたいですが、
Linux の多くのディストリビューション(以下 OS)では、すでに対応済みになっています。
元々は国際化対応 (internationalization,i18n) の中で、国ごとの時刻表示に対応する
必要があり、ロケール の一環としてサマータイム対応されています。
各国のサマータイムの情報や、時差の情報は IP アドレスの割り当て等を管理している
IANA で収集していて、Time Zone Database (以下、tzdata) として公開しています。
[1] , [2]
日本でも GHQ 占領時代に一時サマータイムが実施されたことがあり [3] 、その時の
データが収録されています。 [4] JDT (Japan Daylight Saving Time) という、
日本のタイムゾーンを表す3文字コードも収録されています。 [5]
なので、少なくとも OS 上は、サマータイムが制定されていつから始まり、いつ終わる
のかが決定されれば、アップデートに従って tzdata が更新されてサマータイム対応完了
となるはずです。ただし、DBMS などの個々のミドルウェアに関しては時刻に関する
扱いが異なる可能性があるため注意が必要です。
例えば JAVA は OS とは別に tzdata を持っており、別途対応するようになっています。
それでは、試験的にサマータイムを導入してみたいと思います。

環境

今回実施した環境は以下の通りです。

  • ディストリビューション
    Amazon Linux 2
  • AMI
    amzn2-ami-hvm-2.0.20180622.1-x86_64-gp2 (ami-a9d09ed1)
    (yum update 実施済み)
  • リージョン
    us-west-2 (オレゴン)
  • インスタンスタイプ
    m5.large
  • kernel
    kernel-4.14.59-68.43.amzn2.x86_64
  • glibc
    glibc-2.26-28.amzn2.0.1.x86_64
  • tzdata
    tzdata-2018c-1.amzn2.noarch

ほかのディストリビューションでも RHEL,CentOS,Fedora 等 RedHat 系であれば、
ほぼ同じ手順で実施できると思います。

準備

配布物ではデータはバイナリ形式で配布されているため、ソースからリビルドします。
まず rpmdevtools をインストールします。後述の

sudo yum install -y rpmdevtools.noarch

次に rpm パッケージビルド用のツリーを作成します。

rpmdev-setuptree

tzdata のソースパッケージをダウンロードします。

yumdownloader --source tzdata

リビルド用の依存パッケージもインストールします。

sudo yum-builddep -y tzdata

ソースパッケージの展開

ソースパッケージを展開します。

rpm -ivh tzdata-2018c-1.amzn2.src.rpm

SPECS ディレクトリに移動します。

cd ~/rpmbuild/SPECS

今回ソースを書き換えたいので、一旦ソースを展開します。

rpmbuild -bp tzdata.spec

BUILD ディレクトリに移動します。

cd ~/rpmbuild/BUILD

tzdata-2018c というディレクトリができているので、後でパッチにできるように
一旦退避します。

cp -rf tzdata-2018c tzdata-2018c.orig

タイムゾーンデータの書き換え

それでは書き換えましょう。
とりあえず tzdata-2018c ディレクトリに移動します。

cd tzdata-2018c

今回はテストということで、特にこだわりがないので、アメリカ東部時間から
コピーして修正した以下の2行を asia ファイルに追記しました。
各項目の詳しい意味などを知りたい方は、man 8 zic [6] 等をご参照ください。

diff -urpN tzdata-2018c.orig/asia tzdata-2018c/asia
--- tzdata-2018c.orig/asia      2018-08-10 00:36:59.134904538 +0000
+++ tzdata-2018c/asia   2018-08-10 01:13:46.414776249 +0000
@@ -1475,6 +1475,8 @@ Rule      Japan   1948    only    -       May     Sat>=1  24:00
 Rule   Japan   1948    1951    -       Sep     Sun>=9   0:00   0       S
 Rule   Japan   1949    only    -       Apr     Sat>=1  24:00   1:00    D
 Rule   Japan   1950    1951    -       May     Sat>=1  24:00   1:00    D
+Rule   Japan   2018    max     -       Mar     Sun>=8  2:00    1:00    D
+Rule   Japan   2018    max     -       Nov     Sun>=1  2:00    0       S

 # From Hideyuki Suzuki (1998-11-09):
 # 'Tokyo' usually stands for the former location of Tokyo Astronomical

差分をパッチにして SOURCES ディレクトリに保存します。

diff -urpN tzdata-2018c.orig tzdata-2018c > jp_dst_test.patch
mv jp_dst_test.patch ../SOURCES/

パッケージのビルド

SPECS ディレクトリに移動します。

cd ~/rpmbuild/SPECS

先ほど作成した、パッチが反映されるように tzdata.spec ファイルを変更します。
差分は以下の通りです。

diff -urpN tzdata.spec.orig tzdata.spec
--- tzdata.spec.orig    2018-08-10 01:40:52.947461616 +0000
+++ tzdata.spec 2018-08-10 01:44:11.139083595 +0000
@@ -11,6 +11,7 @@ Source0: ftp://ftp.iana.org/tz/releases/
 Source1: ftp://ftp.iana.org/tz/releases/tzcode%{tzcode_version}.tar.gz

 Patch002: 0002-Fix-have-snprintf-error.patch
+Patch003: jp_dst_test.patch

 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 BuildRequires: gawk, glibc, perl
@@ -43,6 +44,7 @@ This package contains timezone informati
 %prep
 %setup -q -c -a 1
 %patch002 -p1
+%patch003 -p1

 mkdir javazic
 tar zxf %{SOURCE3} -C javazic

パッケージをビルドします。

rpmbuild -ba tzdata.spec

パッケージのインストール

無事ビルドできたようなので、 RPMS/noarch ディレクトリに移動します。
.. code-block:: sh

cd ~/rpmbuild/RPMS/noarch/

パッケージを置き換えます。
今回パッケージ名等を修正しなかったので、”–replacepkgs –replacefiles” という
あまり使用しないオプションを追加してパッケージの置き換えを実施しています。

sudo rpm -ivh --replacepkgs --replacefiles tzdata-2018c-1.amzn2.noarch.rpm

動作確認

zdump コマンドでデータが反映されていることを確認します。

zdump -v Japan
................
Japan  Sat Mar 10 16:59:59 2018 UT = Sun Mar 11 01:59:59 2018 JST isdst=0 gmtoff=32400
Japan  Sat Mar 10 17:00:00 2018 UT = Sun Mar 11 03:00:00 2018 JDT isdst=1 gmtoff=36000
Japan  Sat Nov  3 15:59:59 2018 UT = Sun Nov  4 01:59:59 2018 JDT isdst=1 gmtoff=36000
Japan  Sat Nov  3 16:00:00 2018 UT = Sun Nov  4 01:00:00 2018 JST isdst=0 gmtoff=32400
Japan  Sat Mar  9 16:59:59 2019 UT = Sun Mar 10 01:59:59 2019 JST isdst=0 gmtoff=32400
................

環境変数 TZ を設定して date コマンドで サマータイムが反映されていることを確認します。
通常、UTC に対して +9:00 されますが、+10:00 になっていることが確認できました。
また、タイムゾーンの表示もサマータイムを示す JDT に変わっています。

TZ=Japan date && date
Fri Aug 10 12:26:06 JDT 2018
Fri Aug 10 02:26:06 UTC 2018

いくつかのミドルウェアでも確認してみる

php でも大丈夫そうです。参考までに date コマンドも一緒に出力しています。

TZ=Japan date ;  php -r 'date_default_timezone_set("Japan"); print_r(localti
me(time(),TRUE));'
Fri Aug 10 14:09:13 JDT 2018
Array
(
    [tm_sec] => 13
    [tm_min] => 9
    [tm_hour] => 14
    [tm_mday] => 10
    [tm_mon] => 7
    [tm_year] => 118
    [tm_wday] => 5
    [tm_yday] => 221
    [tm_isdst] => 1
)

ruby でも大丈夫そうです。

TZ=Japan date ; TZ=Japan ruby -e 'puts Time.now.localtime'
Fri Aug 10 14:19:55 JDT 2018
2018-08-10 14:19:55 +1000

python も同様

TZ=Japan date ; TZ=Japan python -c 'import time; print(time.localtime())'
Fri Aug 10 14:24:32 JDT 2018
time.struct_time(tm_year=2018, tm_mon=8, tm_mday=10, tm_hour=14, tm_min=24, tm_sec=32, tm_wday=4, tm_yday=222, tm_isdst=1)

node これも問題なさそうです。

TZ=Japan date ; TZ=Japan node -e 'd=new Date(); console.log(d.getFullYear()+
"-"+(d.getMonth()+1)+"-"+d.getDate()+" "+d.getHours()+":"+d.getMinutes()+":"+d.getSeconds())'
Fri Aug 10 15:01:10 JDT 2018
2018-8-10 15:1:10

最後に

以上、OS 的にはサマータイムに対応する機構がすでに実装されているため、
データを追加するだけで問題なく、サマータイムに対応できることが確認できました。
そのため、サマータイムが実施されても tzdata を更新することで基本的には対応完了
となります。
ただ、ドキュメントや運用ルールなどシステム外の部分に対してはいろいろ対応が必要
かと思います。また OS に同梱されているミドルウェアなどでは別途確認、対応が必要に
なるケースがあるかと思います。ご注意ください。
以上です。

[1] IANA Time Zone Database
[2] GiHhub Time zone database and code
[3] ウィキペディア 夏時間
[4] https://github.com/eggert/tz/blob/5c005615f3f8beaa3eaf4a67ab9c87dc702e1781/asia#L1607
[5] https://github.com/eggert/tz/blob/5c005615f3f8beaa3eaf4a67ab9c87dc702e1781/asia#L1650
[6] jman project zic 8

コメントを残す

メールアドレスが公開されることはありません。

Time limit is exhausted. Please reload CAPTCHA.