Обработка времени довольно сложна. Общие неправильные предположения о времени включают в себя следующее.

  1. Сутки состоят из 24 часов.
  2. Час содержит 60 минут.
  3. Неделя состоит из семи дней.
  4. Год включает 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 /* годы */, 0 /* месяцы */, 1 /* дни */)
maybeNewDay := t.Add(24 * time.Hour)

Использование time.Time и time.Duration с внешними системами

Взаимодействуя с внешними системами, по возможности используйте time.Duration и time.Time, например:

  • Командные флаги: flag поддерживает time.Duration через time.ParseDuration.
  • JSON: encoding/json поддерживает кодирование time.Time в строку RFC 3339 с помощью метода UnmarshalJSON.
  • SQL: database/sql поддерживает преобразование столбцов DATETIME или TIMESTAMP в time.Time и возвращает значение, если базовый драйвер поддерживает это.
  • YAML: gopkg.in/yaml.v2 поддерживает использование time.Time как строки RFC 3339 и time.Duration через time.ParseDuration.

Когда time.Duration нельзя использовать в таких взаимодействиях, используйте int или float64 и включайте единицу измерения в имя поля.

Например, поскольку encoding/json не поддерживает time.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.Format и time.Parse через time.RFC3339.

Хотя это не практическая проблема, обратите внимание, что пакет "time" не поддерживает разбор меток времени с високосными секундами (8728) и не учитывает високосные секунды при расчетах (15190). Если вы сравниваете два момента времени, разница не будет включать в себя високосные секунды, которые могли произойти между этими двумя моментами.