Введение в работу с датами и временем в Go
Работа с датами и временем — одна из ключевых задач в любом серьёзном приложении. Будь то логирование событий, расчёт тайм-аутов, работа с расписаниями или анализ временных рядов, язык Go предоставляет мощный и элегантный инструментарий в стандартном пакете time. В этой статье мы разберём работу с датами и временем в Go от А до Я: от создания объектов времени до сложных операций с часовыми поясами и таймерами.
Основы: структура time.Time и создание дат
Центральный элемент пакета time — структура time.Time. Она представляет момент времени с наносекундной точностью и информацией о часовом поясе.
Получение текущего времени
Самый частый сценарий — получить текущий момент:
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println("Текущее время:", now)
}
Создание конкретной даты
Для создания даты используется функция time.Date(). Обратите внимание: в Go месяцы задаются через константы (time.January, time.February и т.д.) или числом от 1 до 12.
func main() {
// 15 марта 2025 года, 14:30:00, UTC
specificDate := time.Date(2025, time.March, 15, 14, 30, 0, 0, time.UTC)
fmt.Println("Конкретная дата:", specificDate)
// Создание с наносекундами
preciseDate := time.Date(2025, 3, 15, 14, 30, 0, 123456789, time.UTC)
fmt.Println("Точная дата:", preciseDate)
}
Форматирование и парсинг дат
В Go используется уникальный подход к форматированию: вместо кодов типа %Y-%m-%d вы используете эталонное время Mon Jan 2 15:04:05 MST 2006 (которое читается как 01 02 03 04 05 06 07 — год, месяц, день, час, минута, секунда, год).
Форматирование (time → строка)
Метод Format() преобразует время в строку по заданному шаблону:
func main() {
now := time.Now()
// Стандартные форматы
fmt.Println("RFC3339:", now.Format(time.RFC3339))
fmt.Println("Дата:", now.Format("2006-01-02"))
fmt.Println("Время:", now.Format("15:04:05"))
fmt.Println("Полный формат:", now.Format("02.01.2006 15:04:05"))
fmt.Println("С днём недели:", now.Format("Mon, 02 Jan 2006"))
}
Парсинг (строка → time.Time)
Функция time.Parse() разбирает строку в структуру времени. Важно: шаблон должен точно соответствовать формату входной строки.
func main() {
// Парсинг с известным форматом
dateStr := "2025-03-15 14:30:00"
parsed, err := time.Parse("2006-01-02 15:04:05", dateStr)
if err != nil {
panic(err)
}
fmt.Println("Распарсено:", parsed)
// Парсинг с часовым поясом
dateWithZone := "2025-03-15T14:30:00+03:00"
parsedWithZone, _ := time.Parse(time.RFC3339, dateWithZone)
fmt.Println("С часовым поясом:", parsedWithZone)
}
Арифметика времени: интервалы и сравнения
Пакет time предоставляет тип Duration для представления интервалов времени и методы для арифметических операций.
Сложение и вычитание
func main() {
now := time.Now()
// Добавление 2 часов 30 минут
future := now.Add(2*time.Hour + 30*time.Minute)
fmt.Println("Через 2.5 часа:", future)
// Вычитание 7 дней
past := now.Add(-7 * 24 * time.Hour)
fmt.Println("Неделю назад:", past)
// Использование AddDate для работы с календарными датами
nextMonth := now.AddDate(0, 1, 0)
fmt.Println("Через месяц:", nextMonth)
}
Вычисление разницы между датами
Метод Sub() возвращает Duration:
func main() {
start := time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)
end := time.Date(2025, 12, 31, 23, 59, 59, 0, time.UTC)
diff := end.Sub(start)
fmt.Printf("Разница: %v часов\n", diff.Hours())
fmt.Printf("Разница: %v минут\n", diff.Minutes())
fmt.Printf("Разница: %v секунд\n", diff.Seconds())
// Более удобный способ
fmt.Println("Длительность:", diff)
}
Сравнение дат
func main() {
a := time.Date(2025, 3, 15, 0, 0, 0, 0, time.UTC)
b := time.Date(2025, 6, 20, 0, 0, 0, 0, time.UTC)
fmt.Println("a до b?", a.Before(b)) // true
fmt.Println("a после b?", a.After(b)) // false
fmt.Println("a равно b?", a.Equal(b)) // false
// Проверка, находится ли дата в интервале
if a.Before(b) && b.After(a) {
fmt.Println("b находится после a")
}
}
Таймеры, тикеры и работа с задержками
Go предоставляет удобные примитивы для работы с временными событиями в конкурентной среде.
time.Sleep — простая задержка
func main() {
fmt.Println("Начало работы...")
time.Sleep(2 * time.Second)
fmt.Println("Прошло 2 секунды")
}
time.Timer — однократное событие
func main() {
timer := time.NewTimer(3 * time.Second)
select {
case <-timer.C:
fmt.Println("Таймер сработал через 3 секунды")
}
// Сброс таймера
timer.Reset(1 * time.Second)
<-timer.C
fmt.Println("Таймер сб