пятница, 13 ноября 2020 г.

Go style guides: используйте "time", чтобы управлять временем

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

  1. В сутках 24 часа
  2. В часе 60 минут
  3. В неделе 7 дней
  4. В году 365 дней и другие

Например, 1 означает, что добавление 24 часов к моменту времени не всегда дает новый календарный день.

Поэтому всегда используйте пакет "time" при работе со временем, потому что он помогает справиться с этими неверными предположениями более безопасным и точным образом.

Использование time.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 во взаимодействии с внешними системами. Например:

  • Флаги командной строки: 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 в этих взаимодействиях, если не согласована альтернатива, используйте строковые и форматные метки времени, как определено в RFC 3339. Этот формат используется по умолчанию Time.UnmarshalText и доступен для использования во Time.Format и time.Parse по time.RFC3339.

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


Читайте также:


Комментариев нет:

Отправить комментарий