Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 12038] ファイルの概要

このコミットは、Go言語の標準ライブラリの一部であるlib/timeディレクトリに、タイムゾーン情報(zoneinfo)を管理するためのREADMEファイルとupdate.bashスクリプトを追加するものです。これにより、Goが使用するタイムゾーンデータが、IANA Time Zone Databaseの最新情報に基づいて適切に更新される仕組みが導入されました。特に、生成されるタイムゾーンファイルのサイズを最適化し、特定の互換性要件を満たすための重要な変更が含まれています。

コミット

commit 228d941157e744c1416cafc354c8d33bdd068de0
Author: Russ Cox <rsc@golang.org>
Date:   Sat Feb 18 20:33:58 2012 -0500

    lib/time: add README, update.bash script
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/5674104

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/228d941157e744c1416cafc354c8d33bdd068de0

元コミット内容

lib/time: add README, update.bash script

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/5674104

変更の背景

Go言語のtimeパッケージは、日付と時刻の処理においてタイムゾーン情報を正確に扱うために、IANA Time Zone Database(tzdata)に依存しています。このデータベースは、世界中のタイムゾーンのルール(夏時間を含む)を定義しており、定期的に更新されます。Goのアプリケーションが常に最新かつ正確なタイムゾーン情報を使用できるようにするためには、このデータをGoのビルドプロセスや実行環境に組み込む必要があります。

このコミットが行われた2012年当時、Goはタイムゾーンデータをどのように取得・更新するかについて、より堅牢なメカニズムを必要としていました。特に、Goのtimeパッケージが内部的に利用するzoneinfoファイルは、IANAデータベースからコンパイルされたものです。このコミットは、以下の目的で導入されました。

  1. タイムゾーンデータの出所を明確にする: READMEファイルを追加することで、lib/time/zoneinfoディレクトリ内のデータがIANA Time Zone Databaseに由来すること、およびそのパブリックドメインとしての性質を明示します。
  2. タイムゾーンデータの更新プロセスを自動化・標準化する: update.bashスクリプトを提供することで、IANAの公式リポジトリから最新のtzcode(タイムゾーンコンパイラなどのツール)とtzdata(タイムゾーンデータ)をダウンロードし、Goが利用できるzoneinfo形式にコンパイルする手順を自動化します。これにより、手動での更新作業の負担を軽減し、一貫性を保つことができます。
  3. 生成されるzoneinfoファイルのサイズと互換性を管理する: update.bashスクリプトには、zic(タイムゾーン情報コンパイラ)の挙動を調整し、生成されるzoneinfoファイルが64ビットのタイムスタンプ情報を含まないようにする重要なステップが含まれています。これは、ファイルサイズの肥大化を防ぎ、当時のGoのランタイムやシステムが32ビット形式のzoneinfoファイルを前提としていた可能性、または2038年問題(Unix時間における32ビット符号付き整数のオーバーフロー問題)が顕在化する前の段階での最適化として重要でした。

前提知識の解説

IANA Time Zone Database (tzdata)

IANA Time Zone Database(通称 tzdatazoneinfo database、または Olson database)は、世界中のタイムゾーンの歴史的な変化、夏時間(Daylight Saving Time, DST)のルール、およびUTCオフセットに関する情報を集約した、共同で維持されているデータベースです。これは、コンピュータシステムが正確な時刻とタイムゾーン変換を行うために広く利用されています。

  • tzdata: タイムゾーンのルールや歴史的な変更に関する実際のデータが含まれています。これは通常、人間が読めるテキストファイル形式で配布されます。
  • tzcode: tzdataを処理し、バイナリ形式のzoneinfoファイルを生成するためのツール群(zicコンパイラなど)が含まれています。

zic (Time Zone Information Compiler)

zicは、IANA Time Zone Databaseのソースファイル(テキスト形式)を、システムが効率的に読み込めるバイナリ形式のzoneinfoファイルにコンパイルするためのツールです。これらのバイナリファイルは、通常/usr/share/zoneinfoのようなディレクトリに配置され、オペレーティングシステムやプログラミング言語のライブラリによって利用されます。

32ビット/64ビットタイムスタンプと2038年問題

Unix時間(エポック秒)は、1970年1月1日00:00:00 UTCからの経過秒数を表すものです。多くのシステムでは、これを32ビットの符号付き整数で表現してきました。しかし、32ビット符号付き整数の最大値は2,147,483,647であり、これは2038年1月19日03:14:07 UTCに到達します。この時刻を超えると、32ビットシステムではタイムスタンプがオーバーフローし、負の値として解釈されるなどの問題が発生する可能性があります。これが「2038年問題」です。

zoneinfoファイルも、内部的にタイムスタンプを保持しており、これが32ビット形式か64ビット形式かによってファイルサイズや互換性に影響が出ます。このコミットの時点では、まだ2038年問題が差し迫ったものではなかったため、ファイルサイズを抑えるために32ビット形式のzoneinfoファイルを生成することが望ましいと判断された可能性があります。

Go言語のtimeパッケージ

Go言語の標準ライブラリであるtimeパッケージは、日付、時刻、期間、タイムゾーンの処理を提供します。time.Time構造体は、特定の時点を表し、そのタイムゾーン情報(time.Location)を含みます。time.Locationは、システム上のzoneinfoファイルからロードされるか、組み込みのタイムゾーンデータを使用します。

技術的詳細

このコミットの核となるのは、lib/time/update.bashスクリプトです。このスクリプトは、Goが使用するタイムゾーンデータを自動的に更新するための包括的なワークフローを定義しています。

  1. バージョン指定: スクリプトの冒頭で、ダウンロードするtzcodetzdataのバージョンがCODEDATA変数で明示的に指定されています(例: CODE=2011i, DATA=2011n)。これにより、特定の安定したバージョンのデータを使用することが保証されます。

  2. 作業ディレクトリの準備: rm -rf zoneinfo workで既存のzoneinfoディレクトリと一時作業ディレクトリworkを削除し、mkdir zoneinfo workで新しいディレクトリを作成します。その後、cd workで作業ディレクトリに移動します。

  3. データのダウンロード: curl -O http://www.iana.org/time-zones/repository/releases/tzcode$CODE.tar.gzcurl -O http://www.iana.org/time-zones/repository/releases/tzdata$DATA.tar.gzコマンドを使用して、IANAの公式リポジトリから指定されたバージョンのtzcodetzdataのアーカイブファイルをダウンロードします。

  4. アーカイブの展開: ダウンロードしたtar.gzファイルをtar xzfコマンドで展開します。これにより、workディレクトリ内にtzcodetzdataのソースファイルが配置されます。

  5. zic.cのパッチ適用(64ビット出力の無効化): perl -p -i -e 's/pass <= 2/pass <= 1/' zic.cというコマンドが実行されます。これは非常に重要なステップです。

    • zic.ctzcodeに含まれるzicコンパイラのC言語ソースコードです。
    • pass <= 2という文字列は、zicのコンパイルプロセスにおける特定の「パス」(段階)を指します。通常、pass 2は64ビットのタイムスタンプ情報を含むzoneinfoファイルを生成するために使用されます。
    • このperlコマンドは、zic.c内のpass <= 2という記述をpass <= 1に置換します。これにより、zicは64ビットのタイムスタンプを生成するパスを実行しなくなり、結果として生成されるzoneinfoファイルは32ビット形式に限定されます。
    • スクリプト内のコメント「We don't need those until 2037.」が示すように、これは2038年問題が現実のものとなるまでの間、ファイルサイズを小さく保つための意図的な最適化です。64ビットのタイムスタンプはファイルサイズを約3倍に増加させるとされています。
  6. タイムゾーンファイルのコンパイル: make CFLAGS=-DSTD_INSPIRED AWK=awk TZDIR=../zoneinfo posix_onlyコマンドが実行されます。

    • これは、展開されたtzcodeのソースを使用してzicをビルドし、タイムゾーンデータをコンパイルするプロセスです。
    • CFLAGS=-DSTD_INSPIRED: コンパイルフラグで、zicの挙動に影響を与える可能性があります。
    • AWK=awk: awkコマンドのパスを指定します。
    • TZDIR=../zoneinfo: 生成されたバイナリzoneinfoファイルをworkディレクトリの親ディレクトリにあるzoneinfoディレクトリに出力するよう指定します。
    • posix_only: POSIX互換のタイムゾーンファイルのみを生成するよう指示します。これにより、非標準のタイムゾーンが除外され、ファイルセットが簡潔になります。
  7. 生成されたファイルのサイズ検証: size=$(ls -l ../zoneinfo/America/Los_Angeles | awk '{print $5}')で、コンパイルされたAmerica/Los_Angelesタイムゾーンファイルのサイズを取得します。 if [ $size -gt 1200 ]; then ...で、そのサイズが1200バイトを超えているかどうかをチェックします。もし超えている場合、「zone file too large; 64-bit edit failed?」というエラーメッセージを出力し、スクリプトを終了します。これは、前述のperlコマンドによる64ビット出力の無効化が正しく機能したことを確認するための重要な健全性チェックです。

  8. バージョン管理システムへの追加/削除: cd ..で親ディレクトリに戻り、hg addremove zoneinfoを実行します。これは、Goが当時使用していたMercurial(hg)バージョン管理システムに対して、新しく生成されたzoneinfoディレクトリ内のファイルを追加または削除するコマンドです。これにより、リポジトリが最新のタイムゾーンファイルの状態を反映するようになります。

  9. クリーンアップ: スクリプトの最後に、-work引数が指定されていない限り、一時作業ディレクトリworkrm -rf workで削除します。

コアとなるコードの変更箇所

lib/time/README

--- /dev/null
+++ b/lib/time/README
@@ -0,0 +1,9 @@
+The zoneinfo directory contains time zone files compiled using
+the code and data maintained as part of the IANA Time Zone Database.
+The IANA asserts that the database is in the public domain.
+
+For more information, see
+http://www.iana.org/time-zones
+ftp://ftp.iana.org/tz/code/tz-link.htm
+http://tools.ietf.org/html/draft-lear-iana-timezone-database-05
+

lib/time/update.bash

--- /dev/null
+++ b/lib/time/update.bash
@@ -0,0 +1,45 @@
+#!/bin/sh
+# Copyright 2012 The Go Authors.  All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# This script rebuilds the time zone files using files
+# downloaded from the ICANN/IANA distribution.
+
+# Versions to use.
+CODE=2011i
+DATA=2011n
+
+set -e
+rm -rf zoneinfo work
+mkdir zoneinfo work
+cd work
+curl -O http://www.iana.org/time-zones/repository/releases/tzcode$CODE.tar.gz
+curl -O http://www.iana.org/time-zones/repository/releases/tzdata$DATA.tar.gz
+tar xzf tzcode$CODE.tar.gz
+tar xzf tzdata$DATA.tar.gz
+
+# Turn off 64-bit output in time zone files.
+# We don't need those until 2037.
+perl -p -i -e 's/pass <= 2/pass <= 1/' zic.c
+
+make CFLAGS=-DSTD_INSPIRED AWK=awk TZDIR=../zoneinfo posix_only
+
+# America/Los_Angeles should not be bigger than 1100 bytes.
+# If it is, we probably failed to disable the 64-bit output, which
+# triples the size of the files.
+size=$(ls -l ../zoneinfo/America/Los_Angeles | awk '{print $5}')
+if [ $size -gt 1200 ]; then
+	echo 'zone file too large; 64-bit edit failed?' >&2
+	exit 2
+fi
+
+cd ..
+hg addremove zoneinfo
+echo
+if [ "$1" == "-work" ]; then 
+	echo Left workspace behind in work/.\n
+else
+	rm -rf work
+fi
+echo New time zone files in zoneinfo/.\n

コアとなるコードの解説

lib/time/README

この新しいREADMEファイルは、lib/time/zoneinfoディレクトリに格納されているタイムゾーンデータの出所を明確にしています。

  • IANA Time Zone Database: データがIANA Time Zone Databaseからコンパイルされたものであることを明記しています。これは、Goが公式かつ信頼できるタイムゾーン情報源を使用していることを示します。
  • Public Domain: IANAがデータベースをパブリックドメインであると主張していることを記載しており、Goプロジェクトでの利用におけるライセンス上の懸念を解消します。
  • 関連リンク: IANAのタイムゾーンに関する公式ウェブサイト、FTPサイト、および関連するIETFドラフトへのリンクを提供しており、ユーザーや開発者が詳細情報を参照できるようにしています。

lib/time/update.bash

このシェルスクリプトは、Goのタイムゾーンデータを自動的に更新するための包括的な手順を実装しています。

  • スクリプトヘッダとライセンス: #!/bin/shでシェルスクリプトであることを宣言し、Goプロジェクトの標準的なBSDスタイルのライセンス情報が含まれています。

  • 目的のコメント: スクリプトの目的が「ICANN/IANAディストリビューションからダウンロードしたファイルを使用してタイムゾーンファイルを再構築する」と明確に記述されています。

  • バージョン変数 (CODE, DATA): CODE=2011iDATA=2011nは、それぞれダウンロードするtzcodetzdataの特定のバージョンを指定しています。これにより、スクリプトの実行時に常に同じバージョンのデータが使用され、再現性が保証されます。

  • エラー時の終了 (set -e): set -eは、スクリプト内の任意のコマンドが失敗した場合に、スクリプトが即座に終了するように設定します。これにより、部分的な成功や不完全な更新を防ぎ、エラーが発生した際には早期に検知できます。

  • 作業ディレクトリの準備と移動: rm -rf zoneinfo workmkdir zoneinfo workは、以前の実行で残った可能性のあるzoneinfoディレクトリと一時作業ディレクトリworkをクリーンアップし、新しいディレクトリを作成します。cd workで、以降の操作がこの一時ディレクトリ内で行われるようにします。

  • データのダウンロードと展開: curl -O ...コマンドは、IANAの公式リポジトリからtzcodetzdataの圧縮アーカイブをダウンロードします。tar xzf ...は、これらのアーカイブを展開し、ソースファイルを作業ディレクトリに配置します。

  • 64ビット出力の無効化 (perlコマンド): perl -p -i -e 's/pass <= 2/pass <= 1/' zic.cは、このスクリプトの最も技術的に重要な部分です。

    • zic.cは、タイムゾーンファイルをコンパイルするzicツールのCソースコードです。
    • pass <= 2は、zicがタイムゾーンデータを処理する際の内部的な段階(パス)を指します。pass 2は通常、2038年問題に対応するために64ビットのタイムスタンプを生成するロジックを含んでいます。
    • このperlコマンドは、zic.c内のpass <= 2という文字列をpass <= 1に置換します。これにより、zicは64ビットのタイムスタンプを生成するパスを実行しなくなり、結果として生成されるzoneinfoファイルは32ビット形式に限定されます。
    • コメント「We don't need those until 2037.」は、この変更の理由を説明しています。2038年問題が現実のものとなるまでは、64ビットのタイムスタンプは不要であり、ファイルサイズを小さく保つことが優先されたことを示唆しています。64ビットのタイムスタンプは、ファイルサイズを大幅に増加させます。
  • タイムゾーンファイルのコンパイル (makeコマンド): make CFLAGS=-DSTD_INSPIRED AWK=awk TZDIR=../zoneinfo posix_onlyは、展開されたtzcodeのソースからzicをビルドし、ダウンロードしたtzdataを使用してバイナリ形式のzoneinfoファイルをコンパイルします。

    • TZDIR=../zoneinfoは、生成されたzoneinfoファイルをworkディレクトリの親ディレクトリ(つまりlib/time/zoneinfo)に出力するよう指示します。
    • posix_onlyは、POSIX標準に準拠したタイムゾーンのみを生成し、非標準のタイムゾーンを省略することで、生成されるファイルセットを簡潔に保ちます。
  • サイズ検証: size=$(ls -l ../zoneinfo/America/Los_Angeles | awk '{print $5}')とそれに続くif文は、America/Los_Angelesタイムゾーンファイルのサイズをチェックします。もしサイズが1200バイトを超えている場合、64ビット出力の無効化が失敗した可能性を示唆するエラーメッセージを出力し、スクリプトを終了します。これは、perlコマンドによるパッチが正しく適用され、意図した通りに32ビット形式のzoneinfoファイルが生成されたことを確認するための重要な検証ステップです。

  • Mercurialへの変更の反映: cd ..で親ディレクトリに戻り、hg addremove zoneinfoを実行します。これは、Goプロジェクトが当時使用していたMercurialバージョン管理システムに対して、zoneinfoディレクトリ内の新規ファイルを追加し、削除されたファイルを追跡対象から外すコマンドです。これにより、リポジトリが最新のタイムゾーンファイルの状態を正確に反映するようになります。

  • クリーンアップ: if [ "$1" == "-work" ]; then ... else rm -rf work; fiは、スクリプトの引数に-workが指定されていない限り、一時作業ディレクトリworkを削除します。これにより、ビルドプロセス後に不要なファイルが残らないようにします。

関連リンク

参考にした情報源リンク