時間の取り扱いは非常に複雑です。時間に関する一般的な誤った考えは以下のものがあります。

  1. 1日は24時間で構成されているということ。
  2. 1時間は60分を含んでいるということ。
  3. 1週間は7日で構成されているということ。
  4. 1年は365日で構成されているということ。

例えば、1 は特定の時点に24時間を追加しても常に新しいカレンダー日が得られるとは限らないことを示しています。

したがって、時間を取り扱う際は常に"time" パッケージを使用し、これらの誤った考えをより安全かつ正確に取り扱うのに役立ちます。

time.Timeを使用して瞬時の時間を表現する

瞬時の時間を扱う際は、time.Time とそのメソッドを使用して時間の比較、加算、減算を行います。

お勧めしない方法:

func isActive(now, start, stop int) bool {
  return start <= now && now < stop
}

推奨される方法:

func isActive(now, start, stop time.Time) bool {
  return (start.Before(now) || start.Equal(now)) && now.Before(stop)
}

time.Durationを使用して時間の長さを表現する

時間の長さを扱う際は、time.Duration を使用します。

お勧めしない方法:

func poll(delay int) {
  for {
    // ...
    time.Sleep(time.Duration(delay) * time.Millisecond)
  }
}
poll(10) // 秒またはミリ秒でしょうか?

推奨される方法:

func poll(delay time.Duration) {
  for {
    // ...
    time.Sleep(delay)
  }
}
poll(10*time.Second)

最初の例に戻り、瞬時の時間に24時間を追加する際は、使用するメソッドは意図に依存します。現在の日の翌日に同じ時間点を取得したい場合は、Time.AddDate を使用する必要があります。しかし、前回の時間よりも24時間後であることを確認したい場合は、Time.Add を使用する必要があります。

newDay := t.AddDate(0 /* years */, 0 /* months */, 1 /* days */)
maybeNewDay := t.Add(24 * time.Hour)

time.Timeおよびtime.Durationの外部システムとの使用

外部システムとのやり取りにおいては、可能な限りtime.Durationおよびtime.Timeを使用してください。例えば以下のような場合です:

これらのやり取りにおいてtime.Durationを使用できない場合は、intまたはfloat64を使用し、フィールド名に単位を含めます。

例えば、encoding/jsontime.Durationをサポートしていないため、フィールド名に単位を含めます。

非推奨:

// {"interval": 2}
type Config struct {
  Interval int `json:"interval"`
}

推奨:

// {"intervalMillis": 2000}
type Config struct {
  IntervalMillis int `json:"intervalMillis"`
}

これらのやり取りにおいてtime.Timeを使用できない場合は、別途合意がない限り、stringを使用し、タイムスタンプをRFC 3339形式に従ってフォーマットします。デフォルトでTime.UnmarshalTextはこの形式を使用し、time.RFC3339経由でTime.Formatおよびtime.Parseに使用できます。

実用上の問題ではありませんが、"time"パッケージは閏秒タイムスタンプの解析をサポートしておらず(8728)、計算において閏秒を考慮していません(15190)。2つの時間の差を比較する場合、その間で発生した閏秒は含まれませんのでご注意ください。