Time handling is quite complex. Common incorrect assumptions about time include the following.

  1. A day consists of 24 hours.
  2. An hour contains 60 minutes.
  3. A week consists of seven days.
  4. A year comprises 365 days.

For example, 1 indicates that adding 24 hours to a specific point in time does not always result in a new calendar day.

Therefore, when dealing with time, always use the "time" package as it helps to handle these incorrect assumptions in a safer and more accurate manner.

Using time.Time to Represent Instantaneous Time

When dealing with instantaneous time, use time.Time and its methods for comparing, adding, or subtracting time.

Not Recommended:

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

Recommended:

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

Using time.Duration to Represent Time Durations

When dealing with time durations, use time.Duration.

Not Recommended:

func poll(delay int) {
  for {
    // ...
    time.Sleep(time.Duration(delay) * time.Millisecond)
  }
}
poll(10) // Is it in seconds or milliseconds?

Recommended:

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

Returning to the first example, when adding 24 hours to an instantaneous time, the method used depends on the intent. If we want the same time point on the next calendar day (the day after the current day), we should use Time.AddDate. However, if we want to ensure that a certain moment is 24 hours later than the previous one, we should use Time.Add.

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

Using time.Time and time.Duration with External Systems

Whenever possible, use time.Duration and time.Time in interaction with external systems, for example:

When time.Duration cannot be used in these interactions, use int or float64 and include the unit in the field name.

For example, since encoding/json does not support time.Duration, the unit is included in the field name.

Not recommended:

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

Recommended:

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

When time.Time cannot be used in these interactions, unless otherwise agreed upon, use string and format timestamps according to RFC 3339. By default, Time.UnmarshalText uses this format and it can be used in Time.Format and time.Parse through time.RFC3339.

Although not a practical problem, please note that the "time" package does not support parsing leap second timestamps (8728), and does not take leap seconds into account in calculations (15190). If you compare two moments in time, the difference will not include any leap seconds that may have occurred between those two moments.