[インデックス 12818] ファイルの概要
このコミットは、Go言語の標準ライブラリであるtime
パッケージにおける、Windows環境でのタイムゾーン情報(特に夏時間:DST)の取り扱いに関するバグ修正です。具体的には、夏時間(DST)が設定されていないタイムゾーンのローカル時間計算が正しく行われない問題を解決しています。
コミット
commit d3c92b7c903064f31c6f0aec4c3be5cfd30b0e53
Author: Alex Brainman <alex.brainman@gmail.com>
Date: Tue Apr 3 11:39:38 2012 +1000
time: fix handling of locations with no dst on windows
Fixes #3437.
R=rsc
CC=golang-dev
https://golang.org/cl/5967063
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d3c92b7c903064f31c6f0aec4c3be5cfd30b0e53
元コミット内容
time: fix handling of locations with no dst on windows
Fixes #3437.
R=rsc
CC=golang-dev
https://golang.org/cl/5967063
変更の背景
このコミットは、Go言語のtime
パッケージがWindows上で夏時間(Daylight Saving Time, DST)を持たないタイムゾーンを扱う際に発生していたバグを修正するために行われました。具体的には、Issue #3437で報告された問題に対応しています。
Goのtime
パッケージは、OSが提供するタイムゾーン情報を使用してローカル時間を計算します。Windowsシステムでは、タイムゾーン情報はTIME_ZONE_INFORMATION
構造体(またはDYNAMIC_TIME_ZONE_INFORMATION
)によって管理され、夏時間の開始・終了規則などが含まれています。しかし、夏時間を持たないタイムゾーン(例:UTC、一部の地域)の場合、これらの規則は適用されません。
問題は、time
パッケージが夏時間を持たないタイムゾーンを初期化する際に、内部的なタイムゾーン遷移情報(zoneTrans
)が適切に設定されていなかったことに起因します。これにより、夏時間のないタイムゾーンであっても、誤った時間計算が行われる可能性がありました。特に、time.LoadLocation
などでタイムゾーンをロードした際に、内部状態が不完全なままとなり、その後の時間計算で予期せぬ結果を招くことが考えられます。
この修正は、夏時間のないタイムゾーンが正しく初期化され、常に標準時として扱われるようにすることで、この問題を解決します。
前提知識の解説
タイムゾーンと夏時間 (DST)
- タイムゾーン: 地球上の特定の地域で共通して使用される標準時を定義する領域です。UTC(協定世界時)からのオフセット(例: UTC+9)で表されます。
- 夏時間 (Daylight Saving Time, DST): 特定の期間(通常は夏の間)に時間を1時間進める制度です。これにより、日中の明るい時間を有効活用し、エネルギー消費を抑えるなどの目的があります。夏時間が導入されている地域では、年に2回(開始時と終了時)時刻が変更されます。
Go言語のtime
パッケージ
Go言語のtime
パッケージは、時刻の表現、時間間隔の計算、タイムゾーンの処理など、時間に関する機能を提供します。
time.Time
構造体: 特定の時点を表します。time.Location
構造体: タイムゾーン情報を表します。time.LoadLocation
関数を使って、名前(例: "America/New_York")やシステム情報からタイムゾーンをロードできます。- 内部的には、
time.Location
はタイムゾーンのオフセット、略称、そして夏時間による遷移情報(zoneTrans
)を保持しています。
Windowsのタイムゾーン情報
Windowsオペレーティングシステムは、レジストリにタイムゾーン情報を格納しており、Win32 APIを通じてアクセスできます。
GetTimeZoneInformation
関数: システムの現在のタイムゾーン情報を取得します。TIME_ZONE_INFORMATION
構造体: タイムゾーンの標準時と夏時間のオフセット、名称、夏時間の開始・終了日時などの情報を含みます。夏時間がない場合は、夏時間関連のフィールドがゼロまたは無効な値になります。
zoneTrans
とzoneTransCache
Goのtime
パッケージ内部では、タイムゾーンの遷移(夏時間の開始・終了など)を効率的に処理するために、zoneTrans
という構造体とzoneTransCache
というキャッシュ機構を使用しています。
zoneTrans
: 特定の時刻(when
)におけるタイムゾーンのオフセットや略称などの情報(index
)を保持します。夏時間のあるタイムゾーンでは、複数のzoneTrans
エントリが存在し、時間の経過とともに適用されるルールが切り替わります。zoneTransCache
: タイムゾーンの計算を高速化するためのキャッシュです。cacheStart
、cacheEnd
、cacheZone
などのフィールドを持ち、特定の時間範囲におけるタイムゾーン情報を保持します。
夏時間のないタイムゾーンの場合、タイムゾーンの遷移は発生しないため、zoneTrans
は1つのエントリのみを持つべきです。このエントリは、そのタイムゾーンの標準時を表します。
技術的詳細
このコミットの技術的詳細は、Go言語のtime
パッケージがWindowsのタイムゾーン情報を初期化する際のロジックにあります。
src/pkg/time/zoneinfo_windows.go
ファイルは、Windows固有のタイムゾーン情報処理を担当しています。initLocalFromTZI
関数は、Windows APIから取得したsyscall.Timezoneinformation
構造体(これはTIME_ZONE_INFORMATION
構造体に対応します)を基に、Goのtime.Location
構造体を初期化します。
夏時間がないタイムゾーンの場合、initLocalFromTZI
関数内の特定の条件分岐に入ります。この条件分岐は、i.DaylightDate.Month == 0
(夏時間の開始月が0、つまり夏時間がないことを示す)の場合に実行されます。
修正前のコードでは、この夏時間がない場合の処理において、l.tx
(zoneTrans
のスライス)が初期化されていませんでした。l.tx
はタイムゾーンの遷移情報を保持する重要なフィールドであり、夏時間がない場合でも、少なくとも標準時を表す1つのエントリが必要です。
このコミットでは、夏時間がないタイムゾーンの初期化パスに以下の3行が追加されました。
l.tx = make([]zoneTrans, 1)
l.tx[0].when = l.cacheStart
l.tx[0].index = 0
これにより、以下の点が保証されます。
l.tx
の初期化:l.tx
がzoneTrans
型のスライスとして適切に初期化され、1つの要素を保持するようになります。- 単一の遷移エントリ:
l.tx[0]
に、タイムゾーンの開始時刻(l.cacheStart
、通常はGoの時間の最小値)から適用される単一のタイムゾーン情報が設定されます。 - 標準時インデックス:
l.tx[0].index = 0
は、このエントリが標準時(std
)に対応するタイムゾーン情報を使用することを示します。std
は、initLocalFromTZI
関数内で定義される、標準時のオフセットと略称を持つzone
構造体です。
この修正により、夏時間のないタイムゾーンがロードされた際に、time.Location
オブジェクトが完全な内部状態を持つようになり、その後の時間計算が正しく行われるようになります。特に、time.Time
オブジェクトのIn
メソッドなど、タイムゾーン変換を行う関数が、夏時間のないタイムゾーンに対しても期待通りに動作するようになります。
コアとなるコードの変更箇所
変更はsrc/pkg/time/zoneinfo_windows.go
ファイル内のinitLocalFromTZI
関数に集中しています。
--- a/src/pkg/time/zoneinfo_windows.go
+++ b/src/pkg/time/zoneinfo_windows.go
@@ -83,6 +83,9 @@ func initLocalFromTZI(i *syscall.Timezoneinformation) {
l.cacheStart = -1 << 63
l.cacheEnd = 1<<63 - 1
l.cacheZone = std
+ l.tx = make([]zoneTrans, 1)
+ l.tx[0].when = l.cacheStart
+ l.tx[0].index = 0
return
}
コアとなるコードの解説
上記のコードスニペットは、initLocalFromTZI
関数内で、夏時間(DST)が設定されていないタイムゾーンを処理する部分です。
if i.DaylightDate.Month == 0 { ... }
: この条件は、Windowsのタイムゾーン情報(i
)において、夏時間の開始月が0である場合に真となります。これは、そのタイムゾーンが夏時間を持たないことを意味します。l.cacheStart = -1 << 63
:l
はtime.Location
構造体です。cacheStart
は、このタイムゾーン情報が有効な開始時刻を示します。-1 << 63
はGoのint64
型の最小値であり、事実上「常に有効」であることを意味します。l.cacheEnd = 1<<63 - 1
:cacheEnd
は有効な終了時刻を示し、1<<63 - 1
はint64
型の最大値であり、これも「常に有効」であることを意味します。l.cacheZone = std
:cacheZone
は、このキャッシュ期間中に適用されるタイムゾーン情報(オフセット、略称など)を指します。std
は、この関数内で定義されている標準時(Standard Time)のzone
構造体です。- 追加された行:
l.tx = make([]zoneTrans, 1)
:l.tx
はtime.Location
構造体のフィールドで、zoneTrans
型のスライスです。これは、タイムゾーンの遷移(夏時間の開始・終了など)を記録するために使用されます。夏時間がない場合でも、少なくとも標準時を表す1つのエントリが必要です。この行は、そのためのスライスを初期化し、1つの要素を保持するようにします。l.tx[0].when = l.cacheStart
: スライスの最初の要素(インデックス0)のwhen
フィールドに、このタイムゾーン情報が適用される開始時刻を設定します。l.cacheStart
と同じく、事実上「常に」適用されることを意味します。l.tx[0].index = 0
: スライスの最初の要素のindex
フィールドに0
を設定します。これは、このzoneTrans
エントリが、time.Location
構造体内のzone
スライス(l.zone
)のインデックス0にあるタイムゾーン情報(この場合はstd
、つまり標準時)を参照することを示します。
これらの追加により、夏時間を持たないタイムゾーンがGoのtime
パッケージにロードされた際に、そのtime.Location
オブジェクトが内部的に完全な状態となり、時間計算が正しく行われるようになります。
関連リンク
- Go Issue #3437: https://github.com/golang/go/issues/3437
- Go CL 5967063: https://golang.org/cl/5967063
参考にした情報源リンク
- Go言語の
time
パッケージのドキュメント: https://pkg.go.dev/time - Windows API
TIME_ZONE_INFORMATION
構造体に関するMicrosoft Learnドキュメント: https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-time_zone_information - Go言語のソースコード(
src/pkg/time/zoneinfo_windows.go
) - Go言語のソースコード(
src/pkg/time/zoneinfo.go
) -zoneTrans
などの概念理解のため
[インデックス 12818] ファイルの概要
このコミットは、Go言語の標準ライブラリであるtime
パッケージにおける、Windows環境でのタイムゾーン情報(特に夏時間:DST)の取り扱いに関するバグ修正です。具体的には、夏時間(DST)が設定されていないタイムゾーンのローカル時間計算が正しく行われない問題を解決しています。
コミット
commit d3c92b7c903064f31c6f0aec4c3be5cfd30b0e53
Author: Alex Brainman <alex.brainman@gmail.com>
Date: Tue Apr 3 11:39:38 2012 +1000
time: fix handling of locations with no dst on windows
Fixes #3437.
R=rsc
CC=golang-dev
https://golang.org/cl/5967063
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d3c92b7c903064f31c6f0aec4c3be5cfd30b0e53
元コミット内容
time: fix handling of locations with no dst on windows
Fixes #3437.
R=rsc
CC=golang-dev
https://golang.org/cl/5967063
変更の背景
このコミットは、Go言語のtime
パッケージがWindows上で夏時間(Daylight Saving Time, DST)を持たないタイムゾーンを扱う際に発生していたバグを修正するために行われました。具体的には、Issue #3437で報告された問題に対応しています。
Goのtime
パッケージは、OSが提供するタイムゾーン情報を使用してローカル時間を計算します。Windowsシステムでは、タイムゾーン情報はTIME_ZONE_INFORMATION
構造体(またはDYNAMIC_TIME_ZONE_INFORMATION
)によって管理され、夏時間の開始・終了規則などが含まれています。しかし、夏時間を持たないタイムゾーン(例:UTC、一部の地域)の場合、これらの規則は適用されません。
問題は、time
パッケージが夏時間を持たないタイムゾーンを初期化する際に、内部的なタイムゾーン遷移情報(zoneTrans
)が適切に設定されていなかったことに起因します。これにより、夏時間のないタイムゾーンであっても、誤った時間計算が行われる可能性がありました。特に、time.LoadLocation
などでタイムゾーンをロードした際に、内部状態が不完全なままとなり、その後の時間計算で予期せぬ結果を招くことが考えられます。
この修正は、夏時間のないタイムゾーンが正しく初期化され、常に標準時として扱われるようにすることで、この問題を解決します。
前提知識の解説
タイムゾーンと夏時間 (DST)
- タイムゾーン: 地球上の特定の地域で共通して使用される標準時を定義する領域です。UTC(協定世界時)からのオフセット(例: UTC+9)で表されます。
- 夏時間 (Daylight Saving Time, DST): 特定の期間(通常は夏の間)に時間を1時間進める制度です。これにより、日中の明るい時間を有効活用し、エネルギー消費を抑えるなどの目的があります。夏時間が導入されている地域では、年に2回(開始時と終了時)時刻が変更されます。
Go言語のtime
パッケージ
Go言語のtime
パッケージは、時刻の表現、時間間隔の計算、タイムゾーンの処理など、時間に関する機能を提供します。
time.Time
構造体: 特定の時点を表します。time.Location
構造体: タイムゾーン情報を表します。time.LoadLocation
関数を使って、名前(例: "America/New_York")やシステム情報からタイムゾーンをロードできます。- 内部的には、
time.Location
はタイムゾーンのオフセット、略称、そして夏時間による遷移情報(zoneTrans
)を保持しています。
Windowsのタイムゾーン情報
Windowsオペレーティングシステムは、レジストリにタイムゾーン情報を格納しており、Win32 APIを通じてアクセスできます。
GetTimeZoneInformation
関数: システムの現在のタイムゾーン情報を取得します。TIME_ZONE_INFORMATION
構造体: タイムゾーンの標準時と夏時間のオフセット、名称、夏時間の開始・終了日時などの情報を含みます。夏時間がない場合は、夏時間関連のフィールドがゼロまたは無効な値になります。
zoneTrans
とzoneTransCache
Goのtime
パッケージ内部では、タイムゾーンの遷移(夏時間の開始・終了など)を効率的に処理するために、zoneTrans
という構造体とzoneTransCache
というキャッシュ機構を使用しています。
zoneTrans
: 特定の時刻(when
)におけるタイムゾーンのオフセットや略称などの情報(index
)を保持します。夏時間のあるタイムゾーンでは、複数のzoneTrans
エントリが存在し、時間の経過とともに適用されるルールが切り替わります。zoneTransCache
: タイムゾーンの計算を高速化するためのキャッシュです。cacheStart
、cacheEnd
、cacheZone
などのフィールドを持ち、特定の時間範囲におけるタイムゾーン情報を保持します。
夏時間のないタイムゾーンの場合、タイムゾーンの遷移は発生しないため、zoneTrans
は1つのエントリのみを持つべきです。このエントリは、そのタイムゾーンの標準時を表します。
技術的詳細
このコミットの技術的詳細は、Go言語のtime
パッケージがWindowsのタイムゾーン情報を初期化する際のロジックにあります。
src/pkg/time/zoneinfo_windows.go
ファイルは、Windows固有のタイムゾーン情報処理を担当しています。initLocalFromTZI
関数は、Windows APIから取得したsyscall.Timezoneinformation
構造体(これはTIME_ZONE_INFORMATION
構造体に対応します)を基に、Goのtime.Location
構造体を初期化します。
夏時間がないタイムゾーンの場合、initLocalFromTZI
関数内の特定の条件分岐に入ります。この条件分岐は、i.DaylightDate.Month == 0
(夏時間の開始月が0、つまり夏時間がないことを示す)の場合に実行されます。
修正前のコードでは、この夏時間がない場合の処理において、l.tx
(zoneTrans
のスライス)が初期化されていませんでした。l.tx
はタイムゾーンの遷移情報を保持する重要なフィールドであり、夏時間がない場合でも、少なくとも標準時を表す1つのエントリが必要です。
このコミットでは、夏時間がないタイムゾーンの初期化パスに以下の3行が追加されました。
l.tx = make([]zoneTrans, 1)
l.tx[0].when = l.cacheStart
l.tx[0].index = 0
これにより、以下の点が保証されます。
l.tx
の初期化:l.tx
がzoneTrans
型のスライスとして適切に初期化され、1つの要素を保持するようになります。- 単一の遷移エントリ:
l.tx[0]
に、タイムゾーンの開始時刻(l.cacheStart
、通常はGoの時間の最小値)から適用される単一のタイムゾーン情報が設定されます。 - 標準時インデックス:
l.tx[0].index = 0
は、このエントリが標準時(std
)に対応するタイムゾーン情報を使用することを示します。std
は、initLocalFromTZI
関数内で定義される、標準時のオフセットと略称を持つzone
構造体です。
この修正により、夏時間のないタイムゾーンがロードされた際に、time.Location
オブジェクトが完全な内部状態を持つようになり、その後の時間計算が正しく行われるようになります。特に、time.Time
オブジェクトのIn
メソッドなど、タイムゾーン変換を行う関数が、夏時間のないタイムゾーンに対しても期待通りに動作するようになります。
コアとなるコードの変更箇所
変更はsrc/pkg/time/zoneinfo_windows.go
ファイル内のinitLocalFromTZI
関数に集中しています。
--- a/src/pkg/time/zoneinfo_windows.go
+++ b/src/pkg/time/zoneinfo_windows.go
@@ -83,6 +83,9 @@ func initLocalFromTZI(i *syscall.Timezoneinformation) {
l.cacheStart = -1 << 63
l.cacheEnd = 1<<63 - 1
l.cacheZone = std
+ l.tx = make([]zoneTrans, 1)
+ l.tx[0].when = l.cacheStart
+ l.tx[0].index = 0
return
}
コアとなるコードの解説
上記のコードスニペットは、initLocalFromTZI
関数内で、夏時間(DST)が設定されていないタイムゾーンを処理する部分です。
if i.DaylightDate.Month == 0 { ... }
: この条件は、Windowsのタイムゾーン情報(i
)において、夏時間の開始月が0である場合に真となります。これは、そのタイムゾーンが夏時間を持たないことを意味します。l.cacheStart = -1 << 63
:l
はtime.Location
構造体です。cacheStart
は、このタイムゾーン情報が有効な開始時刻を示します。-1 << 63
はGoのint64
型の最小値であり、事実上「常に有効」であることを意味します。l.cacheEnd = 1<<63 - 1
:cacheEnd
は有効な終了時刻を示し、1<<63 - 1
はint64
型の最大値であり、これも「常に有効」であることを意味します。l.cacheZone = std
:cacheZone
は、このキャッシュ期間中に適用されるタイムゾーン情報(オフセット、略称など)を指します。std
は、この関数内で定義されている標準時(Standard Time)のzone
構造体です。- 追加された行:
l.tx = make([]zoneTrans, 1)
:l.tx
はtime.Location
構造体のフィールドで、zoneTrans
型のスライスです。これは、タイムゾーンの遷移(夏時間の開始・終了など)を記録するために使用されます。夏時間がない場合でも、少なくとも標準時を表す1つのエントリが必要です。この行は、そのためのスライスを初期化し、1つの要素を保持するようにします。l.tx[0].when = l.cacheStart
: スライスの最初の要素(インデックス0)のwhen
フィールドに、このタイムゾーン情報が適用される開始時刻を設定します。l.cacheStart
と同じく、事実上「常に」適用されることを意味します。l.tx[0].index = 0
: スライスの最初の要素のindex
フィールドに0
を設定します。これは、このzoneTrans
エントリが、time.Location
構造体内のzone
スライス(l.zone
)のインデックス0にあるタイムゾーン情報(この場合はstd
、つまり標準時)を参照することを示します。
これらの追加により、夏時間を持たないタイムゾーンがGoのtime
パッケージにロードされた際に、そのtime.Location
オブジェクトが内部的に完全な状態となり、時間計算が正しく行われるようになります。
関連リンク
- Go Issue #3437: https://github.com/golang/go/issues/3437
- Go CL 5967063: https://golang.org/cl/5967063
参考にした情報源リンク
- Go言語の
time
パッケージのドキュメント: https://pkg.go.dev/time - Windows API
TIME_ZONE_INFORMATION
構造体に関するMicrosoft Learnドキュメント: https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-time_zone_information - Go言語のソースコード(
src/pkg/time/zoneinfo_windows.go
) - Go言語のソースコード(
src/pkg/time/zoneinfo.go
) -zoneTrans
などの概念理解のため