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

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

このコミットは、Go言語の標準ライブラリであるtimeパッケージにおけるTime型のデフォルトの文字列フォーマットを変更するものです。具体的には、Time.String()メソッドが返す時刻文字列の形式が更新され、より多くの情報(特にナノ秒までの小数秒)を含むようになり、かつ文字列としての比較と時刻としての比較が単一のタイムゾーン内で一致するように改善されています。

コミット

commit d599accafa0ddd1a598f87c419099f82d5910004
Author: Russ Cox <rsc@golang.org>
Date:   Tue Feb 14 11:17:48 2012 -0500

    time: use "2006-01-02 15:04:05.999999999 -0700 MST" as String format
    
    This change shows all the information present
    in the Time value (now including fractional seconds)
    and also arranges the fields so that, within a single time zone,
    string comparison and time comparison agree.
    
    R=golang-dev, rogpeppe, r
    CC=golang-dev
    https://golang.org/cl/5654078

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

https://github.com/golang/go/commit/d599accafa0ddd1a598f87c419099f82d5910004

元コミット内容

このコミットは、Go言語のtimeパッケージにおいて、Time型のString()メソッドが使用するデフォルトのフォーマット文字列を、"Mon Jan _2 15:04:05 -0700 MST 2006"から"2006-01-02 15:04:05.999999999 -0700 MST"に変更するものです。この変更により、Time値に含まれるすべての情報(特に小数秒)が文字列に表現されるようになり、さらに単一のタイムゾーン内であれば、生成された文字列の辞書順比較が時刻の時系列順比較と一致するようになります。

変更の背景

Go言語のtimeパッケージは、時刻と日付を扱うための堅牢な機能を提供します。Time型のString()メソッドは、Time値を人間が読める形式の文字列に変換する際に使用されます。このコミット以前のデフォルトフォーマットでは、ナノ秒以下の小数秒情報が失われたり、文字列の比較順序と時刻の比較順序が一致しない場合がありました。

この変更の主な背景は以下の2点です。

  1. 情報量の増加: 以前のフォーマットでは、Time値が持つナノ秒までの詳細な時刻情報が文字列に反映されませんでした。特に、高精度な時刻比較やログ記録において、この情報は重要です。新しいフォーマットでは、2006-01-02 15:04:05.999999999のように、小数秒(ナノ秒まで)が明示的に含まれるようになります。
  2. 文字列比較と時刻比較の一致: 以前のフォーマット"Mon Jan _2 15:04:05 -0700 MST 2006"では、曜日や月の略称が先頭に来るため、異なる日付の時刻文字列を辞書順で比較しても、必ずしも時系列順にならないという問題がありました。例えば、"Tue Jan 02..."と"Mon Jan 01..."では、文字列としては"Mon"が先にきますが、日付としては"Jan 01"が先です。新しいフォーマット"2006-01-02 15:04:05.999999999 -0700 MST"は、年、月、日、時、分、秒、小数秒、タイムゾーンオフセット、タイムゾーン名の順に並んでおり、ISO 8601に似た形式を採用しています。これにより、単一のタイムゾーン内であれば、文字列を辞書順で比較するだけで、時刻の前後関係を正しく判断できるようになります。これは、特にログファイルのソートや、時刻をキーとするデータ構造での利用において非常に有用です。

前提知識の解説

このコミットを理解するためには、以下のGo言語のtimeパッケージに関する知識が不可欠です。

  • time.Time: Go言語で時刻と日付を表現するための構造体です。特定の瞬間をUTC(協定世界時)からのオフセットで表現し、タイムゾーン情報も保持します。
  • time.Format()メソッド: Time型のメソッドで、指定されたレイアウト文字列に基づいて時刻を文字列にフォーマットします。Go言語のtimeパッケージのフォーマットは独特で、基準となる時刻2006-01-02 15:04:05.999999999 -0700 MST(通称「モナリザの誕生日」)の各要素をレイアウト文字列に記述することで、対応する時刻要素がフォーマットされます。
    • 2006: 年 (Year)
    • 01: 月 (Month, 1-12)
    • 02: 日 (Day, 1-31)
    • 15: 時 (Hour, 0-23)
    • 04: 分 (Minute)
    • 05: 秒 (Second)
    • .999999999: ナノ秒 (Nanosecond)
    • -0700: タイムゾーンオフセット (Offset from UTC)
    • MST: タイムゾーン略称 (Time zone abbreviation)
    • Mon: 曜日略称 (Day of week abbreviation)
    • Jan: 月略称 (Month abbreviation)
    • _2: 日 (Day, 1-31, スペース埋め)
  • time.String()メソッド: Time型のメソッドで、fmt.Printfmt.PrintlnなどでTime型の値を直接出力する際に暗黙的に呼び出されるメソッドです。このメソッドは内部でt.Format(layout)を呼び出し、特定のデフォルトレイアウトで時刻を文字列化します。このコミットは、このString()メソッドが使用するデフォルトレイアウトを変更するものです。

技術的詳細

このコミットの技術的な核心は、time.Time型のString()メソッドが使用するフォーマット文字列の変更です。

変更前: "Mon Jan _2 15:04:05 -0700 MST 2006"

変更後: "2006-01-02 15:04:05.999999999 -0700 MST"

この変更により、以下の点が実現されます。

  1. 小数秒の表現: 新しいフォーマット文字列に.999999999が含まれることで、Time値が持つナノ秒までの精度が文字列に反映されるようになります。これにより、例えばtime.Now()で取得した現在の時刻を文字列化する際に、ミリ秒やマイクロ秒、ナノ秒といった詳細な情報が失われなくなります。
  2. 辞書順と時系列順の一致:
    • 旧フォーマットは、曜日、月、日、時、分、秒、タイムゾーンオフセット、タイムゾーン名、年の順でした。この順序では、異なる日付の時刻を文字列として比較した場合、例えば「月曜日」が「火曜日」より先にくるため、時系列順とは一致しませんでした。
    • 新フォーマットは、年、月、日、時、分、秒、小数秒、タイムゾーンオフセット、タイムゾーン名の順です。これは、最も大きな単位である年から始まり、徐々に小さな単位へと続くため、文字列を辞書順で比較するだけで、単一のタイムゾーン内であれば時刻の時系列順を正確に判断できます。これは、データベースのインデックスキーやログのソートなど、多くの場面で非常に重要な特性です。
  3. ISO 8601との親和性: 新しいフォーマットは、日付部分がYYYY-MM-DD形式であり、時刻部分もHH:MM:SS.fffffffff形式であるため、国際標準であるISO 8601形式(例: 2006-01-02T15:04:05.999999999-07:00)と非常に似ています。これにより、Goの時刻文字列が他のシステムや標準と連携しやすくなります。

この変更は、src/pkg/time/format.goファイル内のString()メソッドの実装に直接影響を与えます。また、src/pkg/time/example_test.goのコメントも、新しいフォーマットに合わせて更新されています。これは、Goのドキュメントや例が常に最新の動作を反映していることを保証するためです。

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

このコミットによる主要なコード変更は、以下の2つのファイルにあります。

  1. src/pkg/time/example_test.go

    --- a/src/pkg/time/example_test.go
    +++ b/src/pkg/time/example_test.go
    @@ -51,7 +51,7 @@ func ExampleMonth() {
     	}\n
     }\n
     \n
    -// Go launched at Tue Nov 10 15:00:00 -0800 PST 2009
    +// Go launched at 2009-11-10 15:00:00 -0800 PST
     func ExampleDate() {
     	t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)\n
     	fmt.Printf("Go launched at %s\\n", t.Local())\n
    

    この変更は、ExampleDate()関数のコメント行を、新しいデフォルトフォーマットに合わせて更新しています。これは機能的な変更ではなく、ドキュメントの整合性を保つためのものです。

  2. src/pkg/time/format.go

    --- a/src/pkg/time/format.go
    +++ b/src/pkg/time/format.go
    @@ -344,9 +344,9 @@ func formatNano(nanosec, n int, trim bool) string {
     }\n
     \n
     // String returns the time formatted using the format string
    -//	"Mon Jan _2 15:04:05 -0700 MST 2006"\n
    +//	"2006-01-02 15:04:05.999999999 -0700 MST"\n
     func (t Time) String() string {
    -\treturn t.Format("Mon Jan _2 15:04:05 -0700 MST 2006")\n
    +\treturn t.Format("2006-01-02 15:04:05.999999999 -0700 MST")\n
     }\n
     \n
     type buffer []byte\n
    

    これが機能的な変更の核心です。Time型のString()メソッド内で呼び出されるt.Format()に渡すレイアウト文字列が、旧フォーマットから新フォーマットへと変更されています。これにより、Time型の値が文字列に変換される際のデフォルトの形式が変更されます。

コアとなるコードの解説

src/pkg/time/format.go内のString()メソッドは、Go言語のtime.Time型が文字列として表現される際のデフォルトの挙動を定義しています。

// String returns the time formatted using the format string
//	"2006-01-02 15:04:05.999999999 -0700 MST"
func (t Time) String() string {
	return t.Format("2006-01-02 15:04:05.999999999 -0700 MST")
}

このコードは非常にシンプルで、Time型のレシーバtに対して、ハードコードされた特定のフォーマット文字列"2006-01-02 15:04:05.999999999 -0700 MST"を引数としてFormat()メソッドを呼び出し、その結果を返しています。

  • func (t Time) String() string: これはTime型に紐付けられたメソッドであり、Goのfmtパッケージが値を文字列に変換する際に自動的に呼び出すインターフェース(Stringerインターフェース)を満たしています。
  • return t.Format(...): 実際のフォーマット処理はFormat()メソッドに委譲されています。Format()メソッドは、Goのtimeパッケージの独特なフォーマットルール(基準時刻の各要素をレイアウト文字列に記述する)に従って、Time値を指定された形式の文字列に変換します。

この変更により、開発者が明示的にFormat()メソッドを呼び出さない限り、Time型の値は新しい、より情報量が多く、かつ辞書順と時系列順が一致する形式で文字列化されるようになります。これは、Go言語の時刻処理におけるデフォルトの「良い挙動」を強化するものです。

関連リンク

  • Go言語 timeパッケージのドキュメント:
  • Go Playground (Go言語のコードをオンラインで実行できる環境):
    • https://go.dev/play/
    • このコミット前後のGoのバージョンでtime.Now().String()の出力を比較することで、変更の影響を視覚的に確認できます。
  • ISO 8601 (日付と時刻の表記に関する国際標準):

参考にした情報源リンク

  • Go言語の公式リポジトリ:
  • Go Code Review (Gerrit):
    • https://golang.org/cl/5654078
    • コミットメッセージに記載されているGerritのリンクです。ここには、この変更に関する議論やレビューコメントが含まれている可能性があります。
  • Go言語のブログやメーリングリスト:
    • Go言語の設計思想や特定の変更に関する議論は、公式ブログやgolang-devメーリングリストで公開されることがあります。このコミットの背景にある詳細な議論は、これらのアーカイブから見つけることができるかもしれません。
  • Go言語の書籍やチュートリアル:
    • timeパッケージの基本的な使い方やフォーマットルールについて、より詳細な解説が提供されています。
  • Stack OverflowなどのQ&Aサイト:
    • Goのtimeパッケージのフォーマットに関する一般的な疑問や、この変更がもたらす影響についての議論が見られることがあります。