[インデックス 11757] ファイルの概要
このコミットは、Go言語の標準ライブラリであるos
パッケージからTime
関数を削除し、時間関連の機能がtime
パッケージに集約されるように変更したものです。これにより、Go 1リリースに向けてパッケージ間の責務を明確にし、より一貫性のあるAPI設計を目指しています。具体的には、src/pkg/os/time.go
ファイルが削除され、os_test.go
から関連するテストコードが削除されました。また、この変更がGo 1のリリースノートに反映されるよう、doc/go1.html
とdoc/go1.tmpl
が更新されています。
コミット
- コミットハッシュ:
7750fc894ad8697349cc9b97bb5c0a9c2201c3ae
- Author: Brad Fitzpatrick bradfitz@golang.org
- Date: Fri Feb 10 11:44:51 2012 +1100
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/7750fc894ad8697349cc9b97bb5c0a9c2201c3ae
元コミット内容
os: remove Time; callers should use time.Time.
Part of issue 2947
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5651051
変更の背景
この変更の主な背景は、Go言語の標準ライブラリにおけるパッケージ設計の改善とAPIの一貫性の確保です。Go 1のリリースに向けて、各パッケージが明確な責務を持つように再編成が進められていました。
以前のos
パッケージには、システムコールを通じて現在の時刻を取得するTime
関数が含まれていました。しかし、Go言語にはすでに時間と日付を扱うための専用のtime
パッケージが存在します。os
パッケージはオペレーティングシステムとのインタフェースを提供することを主な目的としており、時間管理はtime
パッケージの責務と考えるのがより適切です。
このコミットは、os.Time
関数を削除し、代わりにtime
パッケージのtime.Now()
関数やtime.Time
型を使用するように促すことで、以下の目的を達成しようとしています。
- 責務の分離: 時間関連の機能を
time
パッケージに集約することで、各パッケージの役割を明確にし、コードベースのモジュール性を向上させます。 - APIの一貫性: 開発者が時間情報を扱う際に、常に
time
パッケージを使用するという一貫したパターンを提供します。これにより、学習コストが削減され、コードの可読性と保守性が向上します。 - 冗長性の排除: 複数のパッケージに類似の機能が分散している状態を解消し、冗長なコードを削減します。
コミットメッセージにある「Part of issue 2947」は、Goプロジェクトの内部的な課題追跡システムにおける特定の課題に関連する変更であることを示唆しています。これは、Go 1リリースに向けた大規模なAPI整理の一環であったと考えられます。
前提知識の解説
このコミットを理解するためには、以下のGo言語の基本的な概念とパッケージに関する知識が必要です。
- Go言語のパッケージシステム: Go言語のコードはパッケージに組織化されます。パッケージは関連する機能の集合であり、コードの再利用性、モジュール性、および名前空間の管理に役立ちます。標準ライブラリは多数のパッケージで構成されており、それぞれが特定の機能を提供します。
os
パッケージ:os
パッケージは、オペレーティングシステム(OS)の機能へのプラットフォームに依存しないインタフェースを提供します。これには、ファイル操作、プロセス管理、環境変数へのアクセスなどが含まれます。time
パッケージ:time
パッケージは、時間と日付の操作、測定、表示のための機能を提供します。これには、現在の時刻の取得、時間の加算・減算、日付のフォーマット、タイマーやティックの作成などが含まれます。syscall
パッケージ:syscall
パッケージは、低レベルのオペレーティングシステムプリミティブへのインタフェースを提供します。これは、Goの標準ライブラリがOS固有の機能にアクセスするために内部的に使用することが多いパッケージです。os.Time
関数も、内部でsyscall.Gettimeofday
を使用していました。syscall.Timeval
構造体: Unix系システムにおいて、timeval
構造体は秒とマイクロ秒で時間を表現するために使用されます。syscall.Gettimeofday
関数は、この構造体に現在の時刻を格納します。- Unixエポック (Unix Epoch): Unixエポックは、1970年1月1日00:00:00 UTC(協定世界時)を指します。多くのシステムでは、この時点からの経過秒数またはミリ秒数で時間を表現します。
os.Time
関数もUnixエポックからの秒数とナノ秒数を返していました。 - Go 1の互換性保証: Go言語は、Go 1リリース以降、後方互換性を非常に重視しています。しかし、Go 1リリース前は、APIの安定化のために破壊的な変更が行われることがありました。このコミットは、Go 1リリース前のAPI整理の一環として行われたものです。
技術的詳細
このコミットの技術的な詳細は、os
パッケージから時間取得の責務を完全に分離し、time
パッケージに一元化することにあります。
-
os.Time
関数の削除:- 以前の
os
パッケージには、Time() (sec int64, nsec int64, err error)
という関数が存在しました。 - この関数は、内部で
syscall.Gettimeofday
を呼び出し、現在の時刻をUnixエポックからの秒数とナノ秒数で返していました。 - このコミットにより、
src/pkg/os/time.go
ファイル自体が削除され、os.Time
関数は利用できなくなりました。
- 以前の
-
os_test.go
からのテストコード削除:src/pkg/os/os_test.go
ファイルから、TestTime
関数が削除されました。これは、os.Time
関数が削除されたため、そのテストも不要になったためです。- また、
os_test.go
内のdot
変数(テスト対象のファイルリスト)から"time.go"
のエントリも削除されています。
-
ドキュメントの更新:
- Go 1のリリースノートとなる
doc/go1.html
とdoc/go1.tmpl
が更新されました。 - これらのドキュメントには、
os.Time
関数が削除されたこと、そして呼び出し元はtime
パッケージのTime
型(実際にはtime.Now()
関数がtime.Time
型を返す)を使用すべきである旨が明記されました。 - 特に、「
os.Time
を使用するコードはコンパイルに失敗し、手動で更新する必要がある」という注意書きが追加されており、この変更が破壊的な変更であることを示しています。
- Go 1のリリースノートとなる
この変更により、開発者は時間情報を取得する際に、常にtime.Now()
関数を使用し、その結果として得られるtime.Time
型を扱うことになります。これにより、Goの標準ライブラリ全体で時間表現の一貫性が保たれ、よりリッチな時間操作機能(フォーマット、加算、比較など)をtime.Time
型を通じて利用できるようになります。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更箇所は以下の通りです。
-
src/pkg/os/time.go
の削除: このファイル全体が削除されました。このファイルには、os.Time()
関数の実装が含まれていました。--- a/src/pkg/os/time.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2009 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. - -package os - -import "syscall" - -// Time returns the current time, in whole seconds and -// fractional nanoseconds, plus an error if any. The current -// time is thus 1e9*sec+nsec, in nanoseconds. The zero of -// time is the Unix epoch.\n-func Time() (sec int64, nsec int64, err error) {\n-\tvar tv syscall.Timeval\n-\tif e := syscall.Gettimeofday(&tv); e != nil {\n-\t\treturn 0, 0, NewSyscallError(\"gettimeofday\", e)\n-\t}\n-\treturn int64(tv.Sec), int64(tv.Usec) * 1000, err\n-}
-
src/pkg/os/os_test.go
の変更:TestTime
関数の削除と、dot
変数からの"time.go"
の削除が行われました。--- a/src/pkg/os/os_test.go +++ b/src/pkg/os/os_test.go @@ -23,7 +23,6 @@ var dot = []string{\n "error.go",\n "file.go",\n "os_test.go",\n- "time.go",\n "types.go",\n "stat_darwin.go",\n "stat_linux.go", @@ -744,19 +743,6 @@ func TestChdirAndGetwd(t *testing.T) {\n fd.Close()\n }\n \n-func TestTime(t *testing.T) {\n-\t// Just want to check that Time() is getting something.\n-\t// A common failure mode on Darwin is to get 0, 0,\n-\t// because it returns the time in registers instead of\n-\t// filling in the structure passed to the system call.\n-\t// Too bad the compiler doesn\'t know that\n-\t// 365.24*86400 is an integer.\n-\tsec, nsec, err := Time()\n-\tif sec < (2009-1970)*36524*864 {\n-\t\tt.Errorf(\"Time() = %d, %d, %s; not plausible\", sec, nsec, err)\n-\t}\n-}\n-\n func TestSeek(t *testing.T) {\n f := newFile("TestSeek", t)\n defer Remove(f.Name())\n ```
-
doc/go1.html
およびdoc/go1.tmpl
の変更: Go 1のリリースノートに、os.Time
の削除とtime
パッケージへの移行に関する記述が追加されました。--- a/doc/go1.html +++ b/doc/go1.html @@ -1347,7 +1347,18 @@ Code that uses the old methods will fail to compile and must be updated by hand.\n The semantic change makes it difficult for the fix tool to update automatically.\n </p>\n \n-<h3 id=\"os_fileinfo\">The os.FileInfo type</h3>\n+<h3 id=\"os\">The os package</h3>\n+\n+<p>The <code>Time</code> function has been removed; callers should use\n+the <a href=\"/pkg/time/#Time\"><code>Time</code></a> type from the\n+<code>time</code> package.</p>\n+\n+<p>\n+<em>Updating</em>:\n+Code that uses <code>os.Time</code> will fail to compile and must be updated by hand.\n+</p>\n+\n+<h4 id=\"os_fileinfo\">The os.FileInfo type</h4>\n \n <p>\n Go 1 redefines the <a href=\"/pkg/os/#FileInfo\"><code>os.FileInfo</code></a> type,
doc/go1.tmpl
も同様の変更が加えられています。
コアとなるコードの解説
削除されたos.Time()
関数の実装は以下の通りでした。
package os
import "syscall"
// Time returns the current time, in whole seconds and
// fractional nanoseconds, plus an error if any. The current
// time is thus 1e9*sec+nsec, in nanoseconds. The zero of
// time is the Unix epoch.
func Time() (sec int64, nsec int64, err error) {
var tv syscall.Timeval
if e := syscall.Gettimeofday(&tv); e != nil {
return 0, 0, NewSyscallError("gettimeofday", e)
}
return int64(tv.Sec), int64(tv.Usec) * 1000, err
}
この関数は、syscall
パッケージのGettimeofday
システムコールを直接呼び出して、現在の時刻をsyscall.Timeval
構造体で取得していました。Timeval
構造体は秒(Sec
)とマイクロ秒(Usec
)のフィールドを持ちます。os.Time()
は、これらの値から秒とナノ秒を計算して返していました。
この関数が削除された理由は、Go言語の設計哲学に基づいています。Goの標準ライブラリは、特定の機能を提供するパッケージがその機能に特化し、他のパッケージとの依存関係を最小限に抑えるように設計されています。時間に関する機能はtime
パッケージが専門であり、os
パッケージが低レベルなシステムコールを通じて時間を提供する必要はありませんでした。
開発者は、os.Time()
の代わりにtime.Now()
関数を使用することで、より高レベルで抽象化されたtime.Time
型を取得できます。time.Time
型は、時刻の表現だけでなく、タイムゾーンの扱い、時刻の比較、フォーマット、期間の計算など、豊富な機能を提供します。これにより、開発者はより安全で表現力豊かな方法で時間情報を扱うことができるようになります。
例えば、以前は以下のように時刻を取得していたかもしれません。
// 以前のコード (os.Time が存在した場合)
sec, nsec, err := os.Time()
if err != nil {
// エラーハンドリング
}
// sec と nsec を使って時間情報を構築
このコミット以降は、以下のようにtime
パッケージを使用します。
// 現在の推奨されるコード
now := time.Now()
sec := now.Unix() // Unixエポックからの秒数
nsec := now.Nanosecond() // 秒未満のナノ秒
// now (time.Time 型) を使って時間情報を扱う
このように、os.Time
の削除は、Go言語の標準ライブラリの設計原則に沿った、よりクリーンで一貫性のあるAPIを提供するための重要なステップでした。
関連リンク
- Go Change List (CL): https://golang.org/cl/5651051
参考にした情報源リンク
- GitHubコミットページ: https://github.com/golang/go/commit/7750fc894ad8697349cc9b97bb5c0a9c2201c3ae
- Go Change List (CL): https://golang.org/cl/5651051
- Go言語の
os
パッケージドキュメント: https://pkg.go.dev/os - Go言語の
time
パッケージドキュメント: https://pkg.go.dev/time - Go言語の
syscall
パッケージドキュメント: https://pkg.go.dev/syscall - Go 1 Release Notes (関連セクション): https://go.dev/doc/go1 (このコミットで更新されたドキュメントの最終版)
- Unix epoch: https://en.wikipedia.org/wiki/Unix_time