Как в Go принято работать со временем и в каких форматах его хранить/передавать?

Ответ

Основным типом для работы со временем в Go является time.Time из стандартной библиотеки. Выбор формата для хранения или передачи зависит от конкретной задачи.

1. В коде (в памяти)

Всегда используйте time.Time. Это не просто число или строка, а полноценная структура, которая хранит время с наносекундной точностью и информацию о временной зоне (location). Это позволяет избежать ошибок при арифметических операциях и сравнениях.

2. В базах данных

  • Предпочтительный способ: Использовать нативные типы данных БД, такие как TIMESTAMP WITH TIME ZONE (PostgreSQL) или DATETIME (MySQL). Большинство драйверов баз данных (database/sql) умеют автоматически конвертировать time.Time в нужный формат и обратно.
  • Альтернатива: Хранить время как BIGINT, используя Unix Timestamp (количество секунд или миллисекунд с 1 января 1970 года). Недостаток: теряется информация о временной зоне.

3. При передаче по сети (JSON/API)

  • Стандарт: Строка в формате RFC3339 / ISO 8601. Это общепринятый стандарт, который однозначен, читаем человеком и включает информацию о смещении временной зоны. В Go для этого есть константа time.RFC3339.
    • Пример: "2023-10-27T10:00:00Z" (Z означает UTC).
  • Альтернатива: Число (JSON Number), представляющее Unix Timestamp.

Пример работы с форматами:

import (
    "fmt"
    "time"
)

func main() {
    // Рекомендуется работать с временем в UTC, чтобы избежать путаницы
    now := time.Now().UTC()

    // 1. Форматирование в строку для API (RFC3339)
    rfcString := now.Format(time.RFC3339)
    fmt.Println("Для API (RFC3339):", rfcString)

    // 2. Получение Unix timestamp для хранения в виде числа
    unixTimestamp := now.Unix()
    fmt.Println("Unix Timestamp (секунды):", unixTimestamp)

    // 3. Парсинг времени из строки
    parsedTime, err := time.Parse(time.RFC3339, rfcString)
    if err != nil {
        panic(err)
    }
    fmt.Println("Время совпадает после парсинга:", now.Equal(parsedTime))
}