[インデックス 18392] ファイルの概要
このコミットは、Go言語の標準ライブラリtime
パッケージ内のタイムゾーン情報(zoneinfo
)に関するコードの可読性を向上させるための変更です。具体的には、タイムゾーン遷移時間の開始と終了を表すマジックナンバー(-1 << 63
と1<<63 - 1
)を、alpha
とomega
という名前付き定数に置き換えることで、コードの意図をより明確にしています。機能的な変更は一切含まれておらず、純粋なリファクタリングです。
コミット
commit fabd261fe2fe0adf5f79b9bb1069df0a93575ae9
Author: Ian Lance Taylor <iant@golang.org>
Date: Fri Jan 31 17:22:10 2014 -0800
time: use names for beginning and end of zone transition times
No functional changes, just more readable code.
LGTM=r
R=golang-codereviews, gobot, r
CC=golang-codereviews
https://golang.org/cl/59240043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/fabd261fe2fe0adf5f79b9bb1069df0a93575ae9
元コミット内容
time: use names for beginning and end of zone transition times
No functional changes, just more readable code.
LGTM=r
R=golang-codereviews, gobot, r
CC=golang-codereviews
https://golang.org/cl/59240043
変更の背景
この変更の背景には、Go言語の標準ライブラリにおけるコード品質と保守性の向上という一般的な目標があります。time
パッケージは、日付と時刻の操作、特にタイムゾーンの扱いに不可欠な部分です。タイムゾーンの遷移(夏時間への移行など)を扱う際には、時間の範囲を表現するためにint64
型の最小値と最大値が使用されていました。
以前のコードでは、これらの値がリテラル定数である-1 << 63
(math.MinInt64
に相当)と1<<63 - 1
(math.MaxInt64
に相当)として直接記述されていました。これらの数値は、int64
の最小値と最大値をビットシフト演算で表現したものであり、Go言語では一般的なイディオムですが、コードを読んだ際にその数値が具体的に何を意味するのか、即座に理解しにくいという問題がありました。
このコミットは、これらの「マジックナンバー」をalpha
とomega
という、より意味のある名前を持つ定数に置き換えることで、コードの意図を明確にし、将来の読者や開発者がコードを理解しやすくすることを目的としています。機能的な変更は伴わないため、既存の動作に影響を与えることなく、純粋にコードの可読性と保守性を向上させるリファクタリングとして実施されました。
前提知識の解説
このコミットを理解するためには、以下の前提知識が役立ちます。
- Go言語の
time
パッケージ: Go言語の標準ライブラリの一部であり、日付、時刻、期間、タイムゾーンなどを扱うための機能を提供します。特に、Location
型は特定のタイムゾーンを表し、zoneTrans
型はタイムゾーンの遷移(例: 夏時間への切り替え)に関する情報を保持します。 int64
型と最小値・最大値:int64
はGo言語における64ビット符号付き整数型です。その最小値は-2^63
、最大値は2^63 - 1
です。-1 << 63
: これはint64
の最小値をビットシフト演算で表現したものです。1
を63ビット左にシフトすると2^63
となり、それに-1
を掛けることで-2^63
、つまりint64
の最小値が得られます。1<<63 - 1
: これはint64
の最大値をビットシフト演算で表現したものです。1
を63ビット左にシフトすると2^63
となり、そこから1
を引くことで2^63 - 1
、つまりint64
の最大値が得られます。
- マジックナンバーの回避: プログラミングにおいて、コード中にその意味が明確でない数値リテラル(マジックナンバー)を直接記述することは、コードの可読性や保守性を低下させるとされています。これらの数値が何を意味するのかを理解するためには、その周辺のコードやドキュメントを詳細に調べる必要が生じるためです。名前付き定数を使用することで、この問題を解決し、コードの意図を自己記述的にすることができます。
- タイムゾーンの遷移: 多くのタイムゾーンでは、夏時間(Daylight Saving Time, DST)の導入などにより、特定の時点でオフセットが変更されます。
time
パッケージは、これらの遷移を正確に処理するために、zoneTrans
のような内部構造を使用しています。時間の「始まり」と「終わり」は、これらの遷移が適用される範囲を定義するために使用されます。
技術的詳細
このコミットの技術的な核心は、int64
の最小値と最大値を表すビットシフト演算を、より意味のある名前付き定数に置き換えることです。
具体的には、src/pkg/time/zoneinfo.go
に以下の定数が追加されました。
// alpha and omega are the beginning and end of time for zone
// transitions.
const (
alpha = -1 << 63 // math.MinInt64
omega = 1<<63 - 1 // math.MaxInt64
)
alpha
:int64
の最小値を表し、タイムゾーン遷移が適用される時間の「始まり」を意味します。これはmath.MinInt64
と同じ値です。omega
:int64
の最大値を表し、タイムゾーン遷移が適用される時間の「終わり」を意味します。これはmath.MaxInt64
と同じ値です。
これらの定数は、time
パッケージ内でタイムゾーンのキャッシュ範囲や、特定のタイムゾーン情報が見つからない場合のデフォルトの時間の範囲を設定する際に使用されていた、直接記述されたビットシフト演算の代わりに導入されました。
例えば、FixedZone
関数で新しいLocation
を作成する際や、lookup
関数で特定の時刻に対応するタイムゾーン情報を検索する際に、以前は-1 << 63
や1<<63 - 1
が使われていましたが、これらがalpha
やomega
に置き換えられました。
この変更は、コンパイル後のバイナリサイズや実行速度に影響を与えるものではなく、純粋にソースコードレベルでの改善です。定数を使用することで、コードの意図がより明確になり、将来のメンテナンスが容易になります。また、もしint64
の最小値や最大値の表現方法が変更された場合でも、この定数の定義箇所を修正するだけで済むため、変更の影響範囲を局所化できるという利点もあります(ただし、int64
の範囲が変更されることは極めて稀です)。
コアとなるコードの変更箇所
このコミットで変更された主要なファイルとコードスニペットは以下の通りです。
src/pkg/time/zoneinfo.go
--- a/src/pkg/time/zoneinfo.go
+++ b/src/pkg/time/zoneinfo.go
@@ -45,6 +45,13 @@ type zoneTrans struct {
isstd, isutc bool // ignored - no idea what these mean
}
+// alpha and omega are the beginning and end of time for zone
+// transitions.
+const (
+ alpha = -1 << 63 // math.MinInt64
+ omega = 1<<63 - 1 // math.MaxInt64
+)
+
// UTC represents Universal Coordinated Time (UTC).
var UTC *Location = &utcLoc
@@ -83,9 +90,9 @@ func FixedZone(name string, offset int) *Location {
l := &Location{
name: name,
zone: []zone{{name, offset, false}},
- tx: []zoneTrans{{-1 << 63, 0, false, false}},
- cacheStart: -1 << 63,
- cacheEnd: 1<<63 - 1,
+ tx: []zoneTrans{{alpha, 0, false, false}},
+ cacheStart: alpha,
+ cacheEnd: omega,
}
l.cacheZone = &l.zone[0]
return l
@@ -105,8 +112,8 @@ func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start
name = "UTC"
offset = 0
isDST = false
- start = -1 << 63
- end = 1<<63 - 1
+ start = alpha
+ end = omega
return
}
@@ -124,11 +131,11 @@ func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start
name = zone.name
offset = zone.offset
isDST = zone.isDST
- start = -1 << 63
+ start = alpha
if len(l.tx) > 0 {
end = l.tx[0].when
} else {
- end = 1<<63 - 1
+ end = omega
}
return
}
@@ -136,7 +143,7 @@ func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start
// Binary search for entry with largest time <= sec.
// Not using sort.Search to avoid dependencies.
tx := l.tx
- end = 1<<63 - 1
+ end = omega
lo := 0
hi := len(tx)
for hi-lo > 1 {
src/pkg/time/zoneinfo_plan9.go
--- a/src/pkg/time/zoneinfo_plan9.go
+++ b/src/pkg/time/zoneinfo_plan9.go
@@ -100,7 +100,7 @@ func loadZoneDataPlan9(s string) (l *Location, err error) {
for i := range tx {
if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
l.cacheStart = tx[i].when
- l.cacheEnd = 1<<63 - 1
+ l.cacheEnd = omega
if i+1 < len(tx) {
l.cacheEnd = tx[i+1].when
}
src/pkg/time/zoneinfo_read.go
--- a/src/pkg/time/zoneinfo_read.go
+++ b/src/pkg/time/zoneinfo_read.go
@@ -173,7 +173,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) {
if len(tx) == 0 {
// Build fake transition to cover all time.
// This happens in fixed locations like "Etc/GMT0".
- tx = append(tx, zoneTrans{when: -1 << 63, index: 0})
+ tx = append(tx, zoneTrans{when: alpha, index: 0})
}
// Committed to succeed.
@@ -185,7 +185,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) {
for i := range tx {
if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
l.cacheStart = tx[i].when
- l.cacheEnd = 1<<63 - 1
+ l.cacheEnd = omega
if i+1 < len(tx) {
l.cacheEnd = tx[i+1].when
}
src/pkg/time/zoneinfo_windows.go
--- a/src/pkg/time/zoneinfo_windows.go
+++ b/src/pkg/time/zoneinfo_windows.go
@@ -165,8 +165,8 @@ func initLocalFromTZI(i *syscall.Timezoneinformation) {
if nzone == 1 {
// No daylight savings.
std.offset = -int(i.Bias) * 60
- l.cacheStart = -1 << 63
- l.cacheEnd = 1<<63 - 1
+ l.cacheStart = alpha
+ l.cacheEnd = omega
l.cacheZone = std
l.tx = make([]zoneTrans, 1)
l.tx[0].when = l.cacheStart
コアとなるコードの解説
このコミットのコアとなる変更は、src/pkg/time/zoneinfo.go
で定義されたalpha
とomega
定数の導入と、それらの定数がtime
パッケージ内の様々な場所でint64
の最小値および最大値の直接的なビットシフト表現の代わりに使用されるようになった点です。
-
alpha
とomega
定数の定義:zoneinfo.go
の冒頭付近に、以下の定数定義が追加されました。const ( alpha = -1 << 63 // math.MinInt64 omega = 1<<63 - 1 // math.MaxInt64 )
これにより、
int64
の最小値と最大値が、それぞれalpha
とomega
という分かりやすい名前で参照できるようになりました。コメントでmath.MinInt64
とmath.MaxInt64
に相当することが明記されており、その意図が明確です。 -
FixedZone
関数での使用:FixedZone
関数は、固定オフセットのタイムゾーンを表すLocation
オブジェクトを作成します。この関数内で、タイムゾーンのキャッシュ範囲(cacheStart
とcacheEnd
)および最初のタイムゾーン遷移(tx
スライス)の開始時刻を設定する際に、alpha
とomega
が使用されるようになりました。tx: []zoneTrans{{alpha, 0, false, false}}, cacheStart: alpha, cacheEnd: omega,
これにより、このタイムゾーンが「全時間範囲」にわたって有効であることを、より直感的に表現できるようになりました。
-
Location.lookup
関数での使用:Location.lookup
関数は、特定の時刻(sec
)に対応するタイムゾーン情報(名前、オフセット、夏時間かどうか、有効期間の開始と終了)を検索します。- UTCの場合のデフォルト値として、
start
とend
にalpha
とomega
が設定されます。 - タイムゾーン遷移がない場合のデフォルトの
start
値としてalpha
が、end
値としてomega
が設定されます。 - バイナリサーチの初期化においても、
end
にomega
が設定されます。 これらの変更により、lookup
関数が扱う時間の範囲が、より明確に「全時間」を意味することが示されます。
- UTCの場合のデフォルト値として、
-
loadZoneDataPlan9
、loadZoneData
、initLocalFromTZI
関数での使用: これらの関数は、それぞれPlan 9、一般的なタイムゾーンデータファイル、Windowsのタイムゾーン情報からLocation
オブジェクトをロードまたは初期化する際に使用されます。これらの関数内でも、タイムゾーンの遷移がない場合や、キャッシュの開始・終了時刻を設定する際に、alpha
とomega
が使用されるようになりました。これにより、異なるプラットフォームやデータソースからのタイムゾーン情報ロード処理においても、時間の範囲の表現が一貫し、可読性が向上しています。
全体として、このコミットは、Go言語のtime
パッケージにおけるタイムゾーン処理の内部実装において、時間の「始まり」と「終わり」を表現する際に、よりセマンティックな名前付き定数を使用することで、コードの意図を明確にし、将来のメンテナンスを容易にすることを目的とした、クリーンアップと可読性向上のための変更です。機能的な影響は一切ありません。
関連リンク
- Go言語
time
パッケージのドキュメント: https://pkg.go.dev/time - Go言語
math
パッケージのドキュメント (MinInt64, MaxInt64): https://pkg.go.dev/math
参考にした情報源リンク
- Go言語のコミット履歴 (GitHub): https://github.com/golang/go/commits/master
- Go言語のコードレビューシステム (Gerrit): https://go.dev/cl/59240043 (このコミットに対応する変更リスト)
- Go言語の
time
パッケージのソースコード: https://github.com/golang/go/tree/master/src/time