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

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

このコミットは、Go言語の標準ライブラリである time パッケージに Since 関数を追加するものです。Since 関数は、指定された過去の時刻 t から現在までの経過時間を Duration 型で返します。これは time.Now().Sub(t) の短縮形として提供され、コードの可読性と利便性を向上させます。

コミット

commit 20812c490736e18c454c807ed1c65304bd8b7e5d
Author: Sameer Ajmani <sameer@golang.org>
Date:   Wed Jan 18 15:25:00 2012 -0500

    time: add Since, which returns the time elapsed since some past time t.
    
    R=rsc, r
    CC=golang-dev
    https://golang.org/cl/5532088
---
 src/pkg/time/time.go | 32 +++++++++++++++++++-------------\
 1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/src/pkg/time/time.go b/src/pkg/time/time.go
index 33d557f736..39d4b95dd0 100644
--- a/src/pkg/time/time.go
+++ b/src/pkg/time/time.go
@@ -130,7 +130,7 @@ var days = [...]string{
 func (d Weekday) String() string { return days[d] }\n \n // Computations on time.\n-// \n+//\n // The zero value for a Time is defined to be\n //\tJanuary 1, year 1, 00:00:00.000000000 UTC\n // which (1) looks like a zero, or as close as you can get in a date\n@@ -138,16 +138,16 @@ func (d Weekday) String() string { return days[d] }\n // be a suitable \"not set\" sentinel, unlike Jan 1 1970, and (3) has a\n // non-negative year even in time zones west of UTC, unlike 1-1-0\n // 00:00:00 UTC, which would be 12-31-(-1) 19:00:00 in New York.\n-// \n+//\n // The zero Time value does not force a specific epoch for the time\n // representation.  For example, to use the Unix epoch internally, we\n // could define that to distinguish a zero value from Jan 1 1970, that\n // time would be represented by sec=-1, nsec=1e9.  However, it does\n // suggest a representation, namely using 1-1-1 00:00:00 UTC as the\n // epoch, and that\'s what we do.\n-// \n+//\n // The Add and Sub computations are oblivious to the choice of epoch.\n-// \n+//\n // The presentation computations - year, month, minute, and so on - all\n // rely heavily on division and modulus by positive constants.  For\n // calendrical calculations we want these divisions to round down, even\n@@ -172,7 +172,7 @@ func (d Weekday) String() string { return days[d] }\n //\t}\n //\n // everywhere.\n-// \n+//\n // The calendar runs on an exact 400 year cycle: a 400-year calendar\n // printed for 1970-2469 will apply as well to 2470-2869.  Even the days\n // of the week match up.  It simplifies the computations to choose the\n@@ -182,22 +182,22 @@ func (d Weekday) String() string { return days[d] }\n // is the 100th year, and the missed missed leap year is the 400th year.\n // So we\'d prefer instead to print a calendar for 2001-2400 and reuse it\n // for 2401-2800.\n-// \n+//\n // Finally, it\'s convenient if the delta between the Unix epoch and\n // long-ago epoch is representable by an int64 constant.\n-// \n+//\n // These three considerations—choose an epoch as early as possible, that\n // uses a year equal to 1 mod 400, and that is no more than 2⁶³ seconds\n // earlier than 1970—bring us to the year -292277022399.  We refer to\n // this year as the absolute zero year, and to times measured as a uint64\n // seconds since this year as absolute times.\n-// \n+//\n // Times measured as an int64 seconds since the year 1—the representation\n // used for Time\'s sec field—are called internal times.\n-// \n+//\n // Times measured as an int64 seconds since the year 1970 are called Unix\n // times.\n-// \n+//\n // It is tempting to just use the year 1 as the absolute epoch, defining\n // that the routines are only valid for years >= 1.  However, the\n // routines would then be invalid when displaying the epoch in time zones\n@@ -205,7 +205,7 @@ func (d Weekday) String() string { return days[d] }\n // printing the zero time correctly isn\'t supported in half the time\n // zones.  By comparison, it\'s reasonable to mishandle some times in\n // the year -292277022399.\n-// \n+//\n // All this is opaque to clients of the API and can be changed if a\n // better implementation presents itself.\n \n@@ -288,8 +288,8 @@ func (t Time) Weekday() Weekday {\n }\n \n // ISOWeek returns the ISO 8601 year and week number in which t occurs.\n-// Week ranges from 1 to 53. Jan 01 to Jan 03 of year n might belong to \n-// week 52 or 53 of year n-1, and Dec 29 to Dec 31 might belong to week 1 \n+// Week ranges from 1 to 53. Jan 01 to Jan 03 of year n might belong to\n+// week 52 or 53 of year n-1, and Dec 29 to Dec 31 might belong to week 1\n // of year n+1.\n func (t Time) ISOWeek() (year, week int) {\n \tyear, month, day, yday := t.date(true)\n@@ -566,6 +566,12 @@ func (t Time) Sub(u Time) Duration {\n \treturn Duration(t.sec-u.sec)*Second + Duration(t.nsec-u.nsec)\n }\n \n+// Since returns the time elapsed since t.\n+// It is shorthand for time.Now().Sub(t).\n+func Since(t Time) Duration {\n+\treturn Now().Sub(t)\n+}\n+\n // AddDate returns the time corresponding to adding the\n // given number of years, months, and days to t.\n // For example, AddDate(-1, 2, 3) applied to January 1, 2011\n```

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

[https://github.com/golang/go/commit/20812c490736e18c454c807ed1c65304bd8b7e5d](https://github.com/golang/go/commit/20812c490736e18c454c807ed1c65304bd8b7e5d)

## 元コミット内容

time: add Since, which returns the time elapsed since some past time t.

R=rsc, r CC=golang-dev https://golang.org/cl/5532088


## 変更の背景

このコミットの背景には、Go言語の `time` パッケージにおける時間計算の利便性向上が挙げられます。既存の `time.Now().Sub(t)` というパターンは、ある時点 `t` から現在までの経過時間を計算する際によく用いられる表現でした。しかし、この操作は非常に頻繁に行われるため、より簡潔で直感的なAPIを提供することで、開発者の負担を軽減し、コードの可読性を向上させることが目的でした。

`time.Now().Sub(t)` は機能的には問題ありませんが、`Since(t)` という専用の関数を用意することで、その意図がより明確になります。これは、Go言語のAPI設計哲学である「明確さ」と「簡潔さ」に合致する変更と言えます。同様のパターンは他のプログラミング言語やライブラリでも見られ、一般的な時間計測のユースケースに対応するための標準的なアプローチです。

また、Go言語の初期段階では、APIが活発に開発・改善されており、このようなユーティリティ関数の追加は、ユーザーからのフィードバックや一般的なプログラミングパターンに基づいて行われることがよくありました。この `Since` 関数の追加も、そうした改善の一環として行われたと考えられます。

## 前提知識の解説

このコミットを理解するためには、Go言語の `time` パッケージに関する以下の基本的な概念を理解しておく必要があります。

1.  **`time.Time` 型**:
    *   Go言語で特定の日時を表す構造体です。
    *   内部的には、エポック(基準となる日時)からの経過秒数とナノ秒数で時間を表現しています。
    *   タイムゾーン情報も保持できます。
    *   `time.Now()` 関数は現在のローカル時刻を `time.Time` 型で返します。

2.  **`time.Duration` 型**:
    *   Go言語で時間の長さを表す型です。
    *   `int64` 型のナノ秒数として表現されます。
    *   例えば、`time.Second`、`time.Minute`、`time.Hour` などの定数を使って、人間が理解しやすい形で時間の長さを指定できます。
    *   `time.Time` 型の減算 (`Sub` メソッド) の結果は `time.Duration` 型になります。

3.  **`time.Time.Sub(u Time) Duration` メソッド**:
    *   `Time` 型のレシーバ `t` に対して、別の `Time` 型の引数 `u` を減算し、その時間差を `Duration` 型で返します。
    *   `t.Sub(u)` は `t` が `u` より後の時刻であれば正の `Duration` を、`u` が `t` より後の時刻であれば負の `Duration` を返します。
    *   このコミット以前は、ある時点からの経過時間を知るには `time.Now().Sub(startTime)` のように記述する必要がありました。

4.  **Go言語の標準ライブラリの設計思想**:
    *   Go言語の標準ライブラリは、シンプルさ、効率性、そして実用性を重視して設計されています。
    *   よく使われるパターンや操作に対しては、簡潔なAPIを提供することが推奨されます。
    *   この `Since` 関数の追加は、まさにこの設計思想に沿ったものです。

これらの概念を理解することで、`Since` 関数がなぜ追加されたのか、そしてそれがどのように機能するのかをより深く把握できます。

## 技術的詳細

このコミットは、`src/pkg/time/time.go` ファイルに `Since` 関数を追加するものです。技術的な変更点は非常にシンプルで、既存の機能の組み合わせによって新しいユーティリティ関数を提供しています。

`Since` 関数の定義は以下の通りです。

```go
// Since returns the time elapsed since t.
// It is shorthand for time.Now().Sub(t).
func Since(t Time) Duration {
	return Now().Sub(t)
}
  • 関数シグネチャ: func Since(t Time) Duration
    • t Time: 過去の時刻を表す time.Time 型の引数を受け取ります。
    • Duration: t から現在までの経過時間を time.Duration 型で返します。
  • 実装: return Now().Sub(t)
    • Now(): time パッケージのグローバル関数 Now() を呼び出し、現在の時刻(time.Time 型)を取得します。
    • .Sub(t): 取得した現在の時刻に対して、引数 t を減算する Sub メソッドを呼び出します。この結果が Duration 型として返されます。

この実装は、Since 関数が単に time.Now().Sub(t) の糖衣構文(syntactic sugar)であることを明確に示しています。新しいロジックや複雑な計算は一切導入されていません。既存の Now() 関数と Time.Sub() メソッドを組み合わせることで、より表現力豊かなAPIを提供しています。

コミットの差分には、Since 関数の追加以外にも、既存のコメント行の末尾にある不要な空白文字が削除されている箇所が複数見られます。これは、コードの整形やスタイルガイドへの準拠を目的としたクリーンアップ作業の一環であり、Since 関数の機能とは直接関係ありませんが、コミットの全体的な品質向上に寄与しています。

この変更は、Go言語の標準ライブラリが、単に機能を提供するだけでなく、開発者がより自然で読みやすいコードを書けるように、継続的に改善されていることを示しています。

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

src/pkg/time/time.go ファイルの以下の部分が追加されました。

// Since returns the time elapsed since t.
// It is shorthand for time.Now().Sub(t).
func Since(t Time) Duration {
	return Now().Sub(t)
}

また、既存のコメント行の末尾にあった不要な空白文字が削除されています。例えば、以下のような変更です。

- //
+ //

コアとなるコードの解説

追加された Since 関数は、Go言語の time パッケージにおける時間計測の一般的なパターンを簡潔に表現するためのユーティリティ関数です。

// Since returns the time elapsed since t.
// It is shorthand for time.Now().Sub(t).
func Since(t Time) Duration {
	return Now().Sub(t)
}
  • // Since returns the time elapsed since t.:

    • これは関数のドキュメンテーションコメントです。Go言語では、エクスポートされる(大文字で始まる)関数や変数、型には、その目的と動作を説明するコメントを記述することが慣例となっています。
    • このコメントは、Since 関数が「t から経過した時間を返す」ことを明確に述べています。
  • // It is shorthand for time.Now().Sub(t).:

    • この行は、Since 関数の実装が time.Now().Sub(t) の短縮形であることを説明しています。これは、関数の内部的な動作を理解する上で非常に重要です。
    • 開発者はこのコメントを読むことで、Since 関数が新しい複雑なロジックを導入するものではなく、既存の2つの関数呼び出しを組み合わせたものであることをすぐに理解できます。これにより、関数の振る舞いに対する予測可能性が高まります。
  • func Since(t Time) Duration { ... }:

    • 関数の定義です。Since という名前は、その目的(「〜以来」)を直接的に示しており、非常に自己記述的です。
    • 引数 ttime.Time 型であり、時間を計測し始める「過去の時点」を表します。
    • 戻り値は time.Duration 型であり、これは時間の長さを表すGoの型です。
  • return Now().Sub(t):

    • 関数の本体であり、実際の処理が行われる部分です。
    • Now(): time パッケージの Now 関数を呼び出します。この関数は、現在のローカル時刻を time.Time 型で返します。
    • .Sub(t): Now() が返した現在の時刻オブジェクトに対して、Sub メソッドを呼び出します。Sub メソッドは、引数として渡された time.Time 型の時刻 t を現在の時刻から減算し、その差を time.Duration 型で返します。

このコードは、Go言語の「シンプルさ」と「明示性」という設計原則をよく表しています。複雑なアルゴリズムを隠蔽するのではなく、一般的な操作をより読みやすく、書きやすい形で提供することに焦点を当てています。これにより、開発者は時間計測のロジックをより直感的に記述できるようになります。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメンテーション (pkg.go.dev)
  • GitHub上のGo言語リポジトリのコミット履歴
  • Go言語の設計に関する一般的な情報源