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

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

このコミットは、Go言語の標準ライブラリであるtimeパッケージ内のTime構造体のフィールドの可視性を変更するものです。具体的には、Time構造体の内部フィールドが非公開(unexported)から公開(exported)に変更されています。これに伴い、timeパッケージの内部実装およびテストコードも、新しい公開フィールド名に合わせて修正されています。

変更されたファイルは以下の通りです。

  • src/lib/Makefile: timeパッケージのビルド設定に関連する変更。io.dirinstallへの依存が追加されています。
  • src/lib/time/time.go: Time構造体のフィールド名が小文字から大文字に修正され、それに伴う内部ロジックのフィールド参照も更新されています。
  • src/lib/time/time_test.go: Time構造体のフィールドを参照するテストコードが、新しい公開フィールド名に合わせて修正されています。

コミット

このコミットは、timeパッケージのTime構造体のフィールドを公開(public)にするための変更です。これにより、Timeオブジェクトの各時間要素(年、月、日、時、分、秒など)に外部から直接アクセスできるようになります。

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

https://github.com/golang/go/commit/65ad3ce1795c3c1e1a65d7eecbc9f00451068fc8

元コミット内容

make time fields public

R=r
DELTA=49  (0 added, 0 deleted, 49 changed)
OCL=23480
CL=23487

変更の背景

Go言語では、パッケージ内の識別子(変数、関数、型、構造体のフィールドなど)の可視性は、その名前の先頭文字が大文字か小文字かによって決定されます。

  • 大文字で始まる識別子: パッケージ外からアクセス可能(exported、公開)
  • 小文字で始まる識別子: パッケージ内からのみアクセス可能(unexported、非公開)

このコミットが行われた2009年1月時点のGo言語はまだ開発初期段階であり、API設計の試行錯誤が行われていました。timeパッケージのTime構造体の各フィールド(year, month, day, hour, minute, second, weekday, zoneoffset, zone)は、元々小文字で始まっており、パッケージ外からは直接アクセスできない非公開の状態でした。

しかし、時間情報を扱うTime構造体において、その内部要素(年、月、日など)に直接アクセスできることは、ユーザーが柔軟に時間データを操作したり、表示形式をカスタマイズしたりする上で非常に重要です。非公開のままでは、これらの情報にアクセスするためには、別途ゲッターメソッド(例: t.GetYear(), t.GetMonth())を提供する必要があり、APIが冗長になる可能性があります。

この変更の背景には、Time構造体の各要素をGo言語の慣習に則って直接アクセス可能にすることで、APIの使いやすさと直感性を向上させるという設計判断があったと考えられます。これにより、ユーザーはt.Yeart.Monthのように直接フィールドにアクセスできるようになり、コードの記述が簡潔になります。

前提知識の解説

Go言語の可視性(Visibility)ルール

Go言語の可視性ルールは非常にシンプルで、識別子の最初の文字が大文字か小文字かによって決まります。

  • Exported (公開): 識別子の最初の文字が大文字の場合、その識別子はパッケージ外からアクセス可能です。これは、他のプログラミング言語におけるpublicに相当します。例えば、fmt.PrintlnPrintlnは公開されているため、fmtパッケージをインポートすればどこからでも呼び出せます。構造体のフィールドが公開されている場合、myStruct.MyFieldのように直接アクセスできます。
  • Unexported (非公開): 識別子の最初の文字が小文字の場合、その識別子は定義されたパッケージ内からのみアクセス可能です。これは、他のプログラミング言語におけるprivateinternalに相当します。パッケージ外からは直接アクセスできません。

このルールは、API設計において非常に重要です。公開された識別子は、そのパッケージの外部インターフェースとなり、互換性を維持する責任が生じます。非公開の識別子は、パッケージの内部実装の詳細であり、外部からは見えないため、パッケージ開発者は自由に内部を変更できます。

Go言語のtimeパッケージ

Go言語の標準ライブラリには、日付と時刻を扱うためのtimeパッケージが用意されています。このパッケージは、時間の測定、表示、フォーマット、解析、および時間帯の処理など、幅広い機能を提供します。

  • time.Time構造体: timeパッケージの中心となる型で、特定の時点(インスタント)を表します。この構造体は、年、月、日、時、分、秒、ナノ秒、タイムゾーン情報などを内部に保持しています。
  • 時間の表現: time.Timeは、通常、協定世界時(UTC)または特定のロケーション(タイムゾーン)における時刻を表します。
  • 時間の操作: time.Timeオブジェクトは、加算(Add)、減算(Sub)、比較(Before, After, Equal)などのメソッドを提供し、時間の計算や比較を容易にします。
  • フォーマットと解析: FormatメソッドとParse関数を使用して、時刻を文字列に変換したり、文字列から時刻を解析したりできます。

このコミットは、time.Time構造体の内部フィールドを公開することで、ユーザーがより直接的に時間要素にアクセスできるようにし、timeパッケージの利便性を高めることを目的としています。

技術的詳細

このコミットの技術的な核心は、Go言語の可視性ルールをtime.Time構造体のフィールドに適用した点にあります。

  1. フィールド名の変更:

    • year -> Year
    • month -> Month
    • day -> Day
    • hour -> Hour
    • minute -> Minute
    • second -> Second
    • weekday -> Weekday
    • zoneoffset -> ZoneOffset
    • zone -> Zone

    これらの変更により、Time構造体のインスタンスtがある場合、以前はt.yearのようにアクセスしようとするとコンパイルエラーになっていましたが、変更後はt.Yearのように直接アクセスできるようになります。

  2. 内部実装の更新: src/lib/time/time.go内のSecondsToUTC, SecondsToLocalTime, Seconds, _Formatなどの関数やメソッドは、Time構造体のフィールドにアクセスする際に、新しい公開フィールド名を使用するように修正されています。例えば、t.hourt.Hourに、t.weekdayt.Weekdayに変更されています。これは、フィールド名が変更されたため、そのフィールドを参照するすべての箇所を更新する必要があるためです。

  3. テストコードの更新: src/lib/time/time_test.go内の_Same関数は、2つのTimeオブジェクトが同じであるかを比較する際に、各フィールドを比較しています。この比較も、新しい公開フィールド名に合わせてt.year == u.yearからt.Year == u.Yearのように修正されています。これにより、テストが引き続き正しく機能することが保証されます。

  4. Makefileの変更: src/lib/Makefileにおいて、time.dirinstallの依存関係にio.dirinstallが追加されています。これは、timeパッケージがioパッケージの機能に依存するようになったことを示唆しています。具体的な依存関係の詳細は、このコミットの差分からは直接読み取れませんが、Go言語の標準ライブラリは相互に依存し合っているため、このような依存関係の追加は一般的なことです。

この変更は、timeパッケージのAPI設計における重要なマイルストーンであり、Go言語の可視性ルールがどのように実際のライブラリ設計に適用されるかを示す良い例です。これにより、time.Timeオブジェクトの各要素へのアクセスがより直接的になり、Go言語の慣習に沿った自然なコード記述が可能になりました。

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

src/lib/time/time.go

Time構造体の定義部分:

--- a/src/lib/time/time.go
+++ b/src/lib/time/time.go
@@ -38,12 +38,12 @@ const (
 )
 
 type Time struct {
-	year int64;	// 2008 is 2008
-	month, day int;	// Sep-17 is 9, 17
-	hour, minute, second int;	// 10:43:12 is 10, 43, 12
-	weekday int;		// Sunday = 0, Monday = 1, ...
-	zoneoffset int;	// seconds west of UTC
-	zone string;
+	Year int64;	// 2008 is 2008
+	Month, Day int;	// Sep-17 is 9, 17
+	Hour, Minute, Second int;	// 10:43:12 is 10, 43, 12
+	Weekday int;		// Sunday = 0, Monday = 1, ...
+	ZoneOffset int;	// seconds west of UTC
+	Zone string;
 }

SecondsToUTC関数内のフィールド参照:

--- a/src/lib/time/time.go
+++ b/src/lib/time/time.go
@@ -82,14 +82,14 @@ func SecondsToUTC(sec int64) *Time {
 	}
 
 	// Time
-	t.hour = int(sec/3600);
-	t.minute = int((sec/60)%60);
-	t.second = int(sec%60);
+	t.Hour = int(sec/3600);
+	t.Minute = int((sec/60)%60);
+	t.Second = int(sec%60);
 
 	// Day 0 = January 1, 1970 was a Thursday
-	t.weekday = int((day + Thursday) % 7);
-	if t.weekday < 0 {
-		t.weekday += 7
+	t.Weekday = int((day + Thursday) % 7);
+	if t.Weekday < 0 {
+		t.Weekday += 7
 	}
 
 	// Change day from 0 = 1970 to 0 = 2001,
@@ -125,9 +125,9 @@ func SecondsToUTC(sec int64) *Time {
 	for m = 0; m < 12 && yday >= months[m]; m++ {
 		yday -= months[m]
 	}
-	t.month = m+1;
-	t.day = yday+1;
-	t.zone = "GMT";
+	t.Month = m+1;
+	t.Day = yday+1;
+	t.Zone = "GMT";

SecondsToLocalTime関数内のフィールド参照:

--- a/src/lib/time/time.go
+++ b/src/lib/time/time.go
@@ -154,8 +154,8 @@ func SecondsToLocalTime(sec int64) *Time {
 		return SecondsToUTC(sec)
 	}
 	t := SecondsToUTC(sec+int64(offset));
-	t.zone = zone;
-	t.zoneoffset = offset;
+	t.Zone = zone;
+	t.ZoneOffset = offset;
 	return t
 }

Secondsメソッド内のフィールド参照:

--- a/src/lib/time/time.go
+++ b/src/lib/time/time.go
@@ -172,7 +172,7 @@ func (t *Time) Seconds() int64 {
 	day := int64(0);
 
 	// Rewrite year to be >= 2001.
-	year := t.year;
+	year := t.Year;
 	if year < 2001 {
 		n := (2001 - year)/400 + 1;
 		year += 400*n;
@@ -199,25 +199,25 @@ func (t *Time) Seconds() int64 {
 	day += 365*n;
 
 	// Add in days this year.
-	months := months(t.year);
-	for m := 0; m < t.month-1; m++ {
+	months := months(t.Year);
+	for m := 0; m < t.Month-1; m++ {
 		day += int64(months[m])
 	}
-	day += int64(t.day - 1);
+	day += int64(t.Day - 1);
 
 	// Convert days to seconds since January 1, 2001.
 	sec := day * _SecondsPerDay;
 
 	// Add in time elapsed today.
-	sec += int64(t.hour) * 3600;
-	sec += int64(t.minute) * 60;
-	sec += int64(t.second);
+	sec += int64(t.Hour) * 3600;
+	sec += int64(t.Minute) * 60;
+	sec += int64(t.Second);
 
 	// Convert from seconds since 2001 to seconds since 1970.
 	sec += _Days1970To2001 * _SecondsPerDay;
 
 	// Account for local time zone.
-	sec -= int64(t.zoneoffset);
+	sec -= int64(t.ZoneOffset);
 	return sec
 }

_Format関数内のフィールド参照:

--- a/src/lib/time/time.go
+++ b/src/lib/time/time.go
@@ -289,39 +289,39 @@ func _Format(t *Time, fmt string) string {
 			i++;
 			switch fmt[i] {
 			case 'A':	// %A full weekday name
-				bp = _AddString(buf, bp, _LongDayNames[t.weekday]);
+				bp = _AddString(buf, bp, _LongDayNames[t.Weekday]);
 			case 'a':	// %a abbreviated weekday name
-				bp = _AddString(buf, bp, _ShortDayNames[t.weekday]);
+				bp = _AddString(buf, bp, _ShortDayNames[t.Weekday]);
 			case 'b':	// %b abbreviated month name
-				bp = _AddString(buf, bp, _ShortMonthNames[t.month-1]);
+				bp = _AddString(buf, bp, _ShortMonthNames[t.Month-1]);
 			case 'd':	// %d day of month (01-31)
-				_Decimal(buf[bp:bp+2], t.day);
+				_Decimal(buf[bp:bp+2], t.Day);
 				bp += 2;
 			case 'e':	// %e day of month ( 1-31)
-				if t.day >= 10 {
-					_Decimal(buf[bp:bp+2], t.day)
+				if t.Day >= 10 {
+					_Decimal(buf[bp:bp+2], t.Day)
 				} else {
 					buf[bp] = ' ';
-					buf[bp+1] = byte(t.day + '0')
+					buf[bp+1] = byte(t.Day + '0')
 				}
 				bp += 2;
 			case 'H':	// %H hour 00-23
-				_Decimal(buf[bp:bp+2], t.hour);
+				_Decimal(buf[bp:bp+2], t.Hour);
 				bp += 2;
 			case 'M':	// %M minute 00-59
-				_Decimal(buf[bp:bp+2], t.minute);
+				_Decimal(buf[bp:bp+2], t.Minute);
 				bp += 2;
 			case 'S':	// %S second 00-59
-				_Decimal(buf[bp:bp+2], t.second);
+				_Decimal(buf[bp:bp+2], t.Second);
 				bp += 2;
 			case 'Y':	// %Y year 2008
-				_Decimal(buf[bp:bp+4], int(t.year));
+				_Decimal(buf[bp:bp+4], int(t.Year));
 				bp += 4;
 			case 'y':	// %y year 08
-				_Decimal(buf[bp:bp+2], int(t.year%100));
+				_Decimal(buf[bp:bp+2], int(t.Year%100));
 				bp += 2;
 			case 'Z':
-				bp = _AddString(buf, bp, t.zone);
+				bp = _AddString(buf, bp, t.Zone);
 			default:
 				buf[bp] = '%';
 				buf[bp+1] = fmt[i];

src/lib/time/time_test.go

_Same関数内のフィールド比較:

--- a/src/lib/time/time_test.go
+++ b/src/lib/time/time_test.go
@@ -30,15 +30,15 @@ var localtests = []_TimeTest {
 }
 
 func _Same(t, u *Time) bool {
-	return t.year == u.year
-		&& t.month == u.month
-		&& t.day == u.day
-		&& t.hour == u.hour
-		&& t.minute == u.minute
-		&& t.second == u.second
-		&& t.weekday == u.weekday
-		&& t.zoneoffset == u.zoneoffset
-		&& t.zone == u.zone
+	return t.Year == u.Year
+		&& t.Month == u.Month
+		&& t.Day == u.Day
+		&& t.Hour == u.Hour
+		&& t.Minute == u.Minute
+		&& t.Second == u.Second
+		&& t.Weekday == u.Weekday
+		&& t.ZoneOffset == u.ZoneOffset
+		&& t.Zone == u.Zone
 }

コアとなるコードの解説

このコミットの主要な変更は、src/lib/time/time.goファイル内のTime構造体の定義と、その構造体のフィールドを参照するすべてのコード箇所にあります。

  1. Time構造体のフィールド名の変更: 最も重要な変更は、Time構造体の各フィールド名が小文字から大文字に変更されたことです。 例: year -> Year, month -> Month, hour -> Hour など。 Go言語の可視性ルールにより、これによりこれらのフィールドはパッケージ外から直接アクセス可能な「公開(exported)」フィールドとなりました。これは、time.Timeオブジェクトの各時間要素(年、月、日など)に、myTime.YearmyTime.Monthのように直接アクセスできるようになったことを意味します。以前は、これらのフィールドは非公開であったため、パッケージ外からアクセスするには、別途ゲッターメソッド(例: myTime.GetYear())が必要でした。この変更により、APIの使いやすさと簡潔性が向上しました。

  2. 内部ロジックのフィールド参照の更新: SecondsToUTC, SecondsToLocalTime, Seconds, _Formatといったtimeパッケージ内の関数やメソッドは、Time構造体のフィールドを操作しています。フィールド名が変更されたため、これらの関数やメソッド内のすべてのフィールド参照も、新しい大文字で始まる名前に更新されています。例えば、t.hour = int(sec/3600)t.Hour = int(sec/3600)に変更されています。これは、コンパイルエラーを避けるために必須の変更です。

  3. テストコードの更新: src/lib/time/time_test.go内の_Same関数は、2つのTime構造体が等しいかどうかを比較するために、そのすべてのフィールドを比較しています。この関数内のフィールド参照も、新しい公開フィールド名に合わせて更新されています。これにより、Time構造体のフィールドが公開された後も、既存のテストが正しく機能し、変更が意図した通りであることを保証します。

これらの変更は、Go言語のAPI設計における重要な原則、すなわち「外部に公開するものは大文字で始める」という慣習に沿ったものです。これにより、time.Time構造体はよりGo言語らしい、直感的で使いやすいAPIを提供できるようになりました。

関連リンク

参考にした情報源リンク

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

このコミットは、Go言語の標準ライブラリであるtimeパッケージ内のTime構造体のフィールドの可視性を変更するものです。具体的には、Time構造体の内部フィールドが非公開(unexported)から公開(exported)に変更されています。これに伴い、timeパッケージの内部実装およびテストコードも、新しい公開フィールド名に合わせて修正されています。

変更されたファイルは以下の通りです。

  • src/lib/Makefile: timeパッケージのビルド設定に関連する変更。io.dirinstallへの依存が追加されています。
  • src/lib/time/time.go: Time構造体のフィールド名が小文字から大文字に修正され、それに伴う内部ロジックのフィールド参照も更新されています。
  • src/lib/time/time_test.go: Time構造体のフィールドを参照するテストコードが、新しい公開フィールド名に合わせて修正されています。

コミット

このコミットは、timeパッケージのTime構造体のフィールドを公開(public)にするための変更です。これにより、Timeオブジェクトの各時間要素(年、月、日、時、分、秒など)に外部から直接アクセスできるようになります。

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

https://github.com/golang/go/commit/65ad3ce1795c3c1e1a65d7eecbc9f00451068fc8

元コミット内容

make time fields public

R=r
DELTA=49  (0 added, 0 deleted, 49 changed)
OCL=23480
CL=23487

変更の背景

Go言語では、パッケージ内の識別子(変数、関数、型、構造体のフィールドなど)の可視性は、その名前の先頭文字が大文字か小文字かによって決定されます。

  • 大文字で始まる識別子: パッケージ外からアクセス可能(exported、公開)
  • 小文字で始まる識別子: パッケージ内からのみアクセス可能(unexported、非公開)

このコミットが行われた2009年1月時点のGo言語はまだ開発初期段階であり、API設計の試行錯誤が行われていました。timeパッケージのTime構造体の各フィールド(year, month, day, hour, minute, second, weekday, zoneoffset, zone)は、元々小文字で始まっており、パッケージ外からは直接アクセスできない非公開の状態でした。

しかし、時間情報を扱うTime構造体において、その内部要素(年、月、日など)に直接アクセスできることは、ユーザーが柔軟に時間データを操作したり、表示形式をカスタマイズしたりする上で非常に重要です。非公開のままでは、これらの情報にアクセスするためには、別途ゲッターメソッド(例: t.GetYear(), t.GetMonth())を提供する必要があり、APIが冗長になる可能性があります。

この変更の背景には、Time構造体の各要素をGo言語の慣習に則って直接アクセス可能にすることで、APIの使いやすさと直感性を向上させるという設計判断があったと考えられます。これにより、ユーザーはt.Yeart.Monthのように直接フィールドにアクセスできるようになり、コードの記述が簡潔になります。

前提知識の解説

Go言語の可視性(Visibility)ルール

Go言語の可視性ルールは非常にシンプルで、識別子の最初の文字が大文字か小文字かによって決まります。

  • Exported (公開): 識別子の最初の文字が大文字の場合、その識別子はパッケージ外からアクセス可能です。これは、他のプログラミング言語におけるpublicに相当します。例えば、fmt.PrintlnPrintlnは公開されているため、fmtパッケージをインポートすればどこからでも呼び出せます。構造体のフィールドが公開されている場合、myStruct.MyFieldのように直接アクセスできます。
  • Unexported (非公開): 識別子の最初の文字が小文字の場合、その識別子は定義されたパッケージ内からのみアクセス可能です。これは、他のプログラミング言語におけるprivateinternalに相当します。パッケージ外からは直接アクセスできません。

このルールは、API設計において非常に重要です。公開された識別子は、そのパッケージの外部インターフェースとなり、互換性を維持する責任が生じます。非公開の識別子は、パッケージの内部実装の詳細であり、外部からは見えないため、パッケージ開発者は自由に内部を変更できます。

Go言語のtimeパッケージ

Go言語の標準ライブラリには、日付と時刻を扱うためのtimeパッケージが用意されています。このパッケージは、時間の測定、表示、フォーマット、解析、および時間帯の処理など、幅広い機能を提供します。

  • time.Time構造体: timeパッケージの中心となる型で、特定の時点(インスタント)を表します。この構造体は、年、月、日、時、分、秒、ナノ秒、タイムゾーン情報などを内部に保持しています。
  • 時間の表現: time.Timeは、通常、協定世界時(UTC)または特定のロケーション(タイムゾーン)における時刻を表します。
  • 時間の操作: time.Timeオブジェクトは、加算(Add)、減算(Sub)、比較(Before, After, Equal)などのメソッドを提供し、時間の計算や比較を容易にします。
  • フォーマットと解析: FormatメソッドとParse関数を使用して、時刻を文字列に変換したり、文字列から時刻を解析したりできます。

このコミットは、time.Time構造体の内部フィールドを公開することで、ユーザーがより直接的に時間要素にアクセスできるようにし、timeパッケージの利便性を高めることを目的としています。

技術的詳細

このコミットの技術的な核心は、Go言語の可視性ルールをtime.Time構造体のフィールドに適用した点にあります。

  1. フィールド名の変更:

    • year -> Year
    • month -> Month
    • day -> Day
    • hour -> Hour
    • minute -> Minute
    • second -> Second
    • weekday -> Weekday
    • zoneoffset -> ZoneOffset
    • zone -> Zone

    これらの変更により、Time構造体のインスタンスtがある場合、以前はt.yearのようにアクセスしようとするとコンパイルエラーになっていましたが、変更後はt.Yearのように直接アクセスできるようになります。

  2. 内部実装の更新: src/lib/time/time.go内のSecondsToUTC, SecondsToLocalTime, Seconds, _Formatなどの関数やメソッドは、Time構造体のフィールドにアクセスする際に、新しい公開フィールド名を使用するように修正されています。例えば、t.hourt.Hourに、t.weekdayt.Weekdayに変更されています。これは、フィールド名が変更されたため、そのフィールドを参照するすべての箇所を更新する必要があるためです。

  3. テストコードの更新: src/lib/time/time_test.go内の_Same関数は、2つのTimeオブジェクトが同じであるかを比較する際に、各フィールドを比較しています。この比較も、新しい公開フィールド名に合わせてt.year == u.yearからt.Year == u.Yearのように修正されています。これにより、テストが引き続き正しく機能することが保証されます。

  4. Makefileの変更: src/lib/Makefileにおいて、time.dirinstallの依存関係にio.dirinstallが追加されています。これは、timeパッケージがioパッケージの機能に依存するようになったことを示唆しています。具体的な依存関係の詳細は、このコミットの差分からは直接読み取れませんが、Go言語の標準ライブラリは相互に依存し合っているため、このような依存関係の追加は一般的なことです。

この変更は、timeパッケージのAPI設計における重要なマイルストーンであり、Go言語の可視性ルールがどのように実際のライブラリ設計に適用されるかを示す良い例です。これにより、time.Timeオブジェクトの各要素へのアクセスがより直接的になり、Go言語の慣習に沿った自然なコード記述が可能になりました。

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

src/lib/time/time.go

Time構造体の定義部分:

--- a/src/lib/time/time.go
+++ b/src/lib/time/time.go
@@ -38,12 +38,12 @@ const (
 )
 
 type Time struct {
-	year int64;	// 2008 is 2008
-	month, day int;	// Sep-17 is 9, 17
-	hour, minute, second int;	// 10:43:12 is 10, 43, 12
-	weekday int;		// Sunday = 0, Monday = 1, ...
-	zoneoffset int;	// seconds west of UTC
-	zone string;
+	Year int64;	// 2008 is 2008
+	Month, Day int;	// Sep-17 is 9, 17
+	Hour, Minute, Second int;	// 10:43:12 is 10, 43, 12
+	Weekday int;		// Sunday = 0, Monday = 1, ...
+	ZoneOffset int;	// seconds west of UTC
+	Zone string;
 }

SecondsToUTC関数内のフィールド参照:

--- a/src/lib/time/time.go
+++ b/src/lib/time/time.go
@@ -82,14 +82,14 @@ func SecondsToUTC(sec int64) *Time {
 	}
 
 	// Time
-	t.hour = int(sec/3600);
-	t.minute = int((sec/60)%60);
-	t.second = int(sec%60);
+	t.Hour = int(sec/3600);
+	t.Minute = int((sec/60)%60);
+	t.Second = int(sec%60);
 
 	// Day 0 = January 1, 1970 was a Thursday
-	t.weekday = int((day + Thursday) % 7);
-	if t.weekday < 0 {
-		t.weekday += 7
+	t.Weekday = int((day + Thursday) % 7);
+	if t.Weekday < 0 {
+		t.Weekday += 7
 	}
 
 	// Change day from 0 = 1970 to 0 = 2001,
@@ -125,9 +125,9 @@ func SecondsToUTC(sec int64) *Time {
 	for m = 0; m < 12 && yday >= months[m]; m++ {
 		yday -= months[m]
 	}
-	t.month = m+1;
-	t.day = yday+1;
-	t.zone = "GMT";
+	t.Month = m+1;
+	t.Day = yday+1;
+	t.Zone = "GMT";

SecondsToLocalTime関数内のフィールド参照:

--- a/src/lib/time/time.go
+++ b/src/lib/time/time.go
@@ -154,8 +154,8 @@ func SecondsToLocalTime(sec int64) *Time {
 		return SecondsToUTC(sec)
 	}
 	t := SecondsToUTC(sec+int64(offset));
-	t.zone = zone;
-	t.zoneoffset = offset;
+	t.Zone = zone;
+	t.ZoneOffset = offset;
 	return t
 }

Secondsメソッド内のフィールド参照:

--- a/src/lib/time/time.go
+++ b/src/lib/time/time.go
@@ -172,7 +172,7 @@ func (t *Time) Seconds() int64 {
 	day := int64(0);
 
 	// Rewrite year to be >= 2001.
-	year := t.year;
+	year := t.Year;
 	if year < 2001 {
 		n := (2001 - year)/400 + 1;
 		year += 400*n;
@@ -199,25 +199,25 @@ func (t *Time) Seconds() int64 {
 	day += 365*n;
 
 	// Add in days this year.
-	months := months(t.year);
-	for m := 0; m < t.month-1; m++ {
+	months := months(t.Year);
+	for m := 0; m < t.Month-1; m++ {
 		day += int64(months[m])
 	}
-	day += int64(t.day - 1);
+	day += int64(t.Day - 1);
 
 	// Convert days to seconds since January 1, 2001.
 	sec := day * _SecondsPerDay;
 
 	// Add in time elapsed today.
-	sec += int64(t.hour) * 3600;
-	sec += int64(t.minute) * 60;
-	sec += int64(t.second);
+	sec += int64(t.Hour) * 3600;
+	sec += int64(t.Minute) * 60;
+	sec += int64(t.Second);
 
 	// Convert from seconds since 2001 to seconds since 1970.
 	sec += _Days1970To2001 * _SecondsPerDay;
 
 	// Account for local time zone.
-	sec -= int64(t.zoneoffset);
+	sec -= int64(t.ZoneOffset);
 	return sec
 }

_Format関数内のフィールド参照:

--- a/src/lib/time/time.go
+++ b/src/lib/time/time.go
@@ -289,39 +289,39 @@ func _Format(t *Time, fmt string) string {
 			i++;
 			switch fmt[i] {
 			case 'A':	// %A full weekday name
-				bp = _AddString(buf, bp, _LongDayNames[t.weekday]);
+				bp = _AddString(buf, bp, _LongDayNames[t.Weekday]);
 			case 'a':	// %a abbreviated weekday name
-				bp = _AddString(buf, bp, _ShortDayNames[t.weekday]);
+				bp = _AddString(buf, bp, _ShortDayNames[t.Weekday]);
 			case 'b':	// %b abbreviated month name
-				bp = _AddString(buf, bp, _ShortMonthNames[t.month-1]);
+				bp = _AddString(buf, bp, _ShortMonthNames[t.Month-1]);
 			case 'd':	// %d day of month (01-31)
-				_Decimal(buf[bp:bp+2], t.day);
+				_Decimal(buf[bp:bp+2], t.Day);
 				bp += 2;
 			case 'e':	// %e day of month ( 1-31)
-				if t.day >= 10 {
-					_Decimal(buf[bp:bp+2], t.day)
+				if t.Day >= 10 {
+					_Decimal(buf[bp:bp+2], t.Day)
 				} else {
 					buf[bp] = ' ';
-					buf[bp+1] = byte(t.day + '0')
+					buf[bp+1] = byte(t.Day + '0')
 				}
 				bp += 2;
 			case 'H':	// %H hour 00-23
-				_Decimal(buf[bp:bp+2], t.hour);
+				_Decimal(buf[bp:bp+2], t.Hour);
 				bp += 2;
 			case 'M':	// %M minute 00-59
-				_Decimal(buf[bp:bp+2], t.minute);
+				_Decimal(buf[bp:bp+2], t.Minute);
 				bp += 2;
 			case 'S':	// %S second 00-59
-				_Decimal(buf[bp:bp+2], t.second);
+				_Decimal(buf[bp:bp+2], t.Second);
 				bp += 2;
 			case 'Y':	// %Y year 2008
-				_Decimal(buf[bp:bp+4], int(t.year));
+				_Decimal(buf[bp:bp+4], int(t.Year));
 				bp += 4;
 			case 'y':	// %y year 08
-				_Decimal(buf[bp:bp+2], int(t.year%100));
+				_Decimal(buf[bp:bp+2], int(t.Year%100));
 				bp += 2;
 			case 'Z':
-				bp = _AddString(buf, bp, t.zone);
+				bp = _AddString(buf, bp, t.Zone);
 			default:
 				buf[bp] = '%';
 				buf[bp+1] = fmt[i];

src/lib/time/time_test.go

_Same関数内のフィールド比較:

--- a/src/lib/time/time_test.go
+++ b/src/lib/time/time_test.go
@@ -30,15 +30,15 @@ var localtests = []_TimeTest {
 }
 
 func _Same(t, u *Time) bool {
-	return t.year == u.year
-		&& t.month == u.month
-		&& t.day == u.day
-		&& t.hour == u.hour
-		&& t.minute == u.minute
-		&& t.second == u.second
-		&& t.weekday == u.weekday
-		&& t.zoneoffset == u.zoneoffset
-		&& t.zone == u.zone
+	return t.Year == u.Year
+		&& t.Month == u.Month
+		&& t.Day == u.Day
+		&& t.Hour == u.Hour
+		&& t.Minute == u.Minute
+		&& t.Second == u.Second
+		&& t.Weekday == u.Weekday
+		&& t.ZoneOffset == u.ZoneOffset
+		&& t.Zone == u.Zone
 }

コアとなるコードの解説

このコミットの主要な変更は、src/lib/time/time.goファイル内のTime構造体の定義と、その構造体のフィールドを参照するすべてのコード箇所にあります。

  1. Time構造体のフィールド名の変更: 最も重要な変更は、Time構造体の各フィールド名が小文字から大文字に変更されたことです。 例: year -> Year, month -> Month, hour -> Hour など。 Go言語の可視性ルールにより、これによりこれらのフィールドはパッケージ外から直接アクセス可能な「公開(exported)」フィールドとなりました。これは、time.Timeオブジェクトの各時間要素(年、月、日など)に、myTime.YearmyTime.Monthのように直接アクセスできるようになったことを意味します。以前は、これらのフィールドは非公開であったため、パッケージ外からアクセスするには、別途ゲッターメソッド(例: myTime.GetYear())が必要でした。この変更により、APIの使いやすさと簡潔性が向上しました。

  2. 内部ロジックのフィールド参照の更新: SecondsToUTC, SecondsToLocalTime, Seconds, _Formatといったtimeパッケージ内の関数やメソッドは、Time構造体のフィールドを操作しています。フィールド名が変更されたため、これらの関数やメソッド内のすべてのフィールド参照も、新しい大文字で始まる名前に更新されています。例えば、t.hour = int(sec/3600)t.Hour = int(sec/3600)に変更されています。これは、コンパイルエラーを避けるために必須の変更です。

  3. テストコードの更新: src/lib/time/time_test.go内の_Same関数は、2つのTime構造体が等しいかどうかを比較するために、そのすべてのフィールドを比較しています。この関数内のフィールド参照も、新しい公開フィールド名に合わせて更新されています。これにより、Time構造体のフィールドが公開された後も、既存のテストが正しく機能し、変更が意図した通りであることを保証します。

これらの変更は、Go言語のAPI設計における重要な原則、すなわち「外部に公開するものは大文字で始める」という慣習に沿ったものです。これにより、time.Time構造体はよりGo言語らしい、直感的で使いやすいAPIを提供できるようになりました。

関連リンク

参考にした情報源リンク