Работа с датами и временем в Go: от основ до продвинутых техник
Язык программирования Go (Golang) предлагает мощный и интуитивно понятный пакет time для работы с датами и временем. В отличие от многих других языков, Go использует уникальный подход к форматированию, основанный на эталонной дате (Mon Jan 2 15:04:05 MST 2006). В этой статье мы подробно разберём все ключевые аспекты: от создания объектов времени до работы с таймерами и временными зонами. Материал будет полезен как новичкам, так и опытным разработчикам, переходящим на Go.
1. Основы: создание, получение и вывод времени
Центральный тип для работы — time.Time. Получить текущий момент можно с помощью time.Now(). Для создания конкретной даты используется time.Date().
package main
import (
"fmt"
"time"
)
func main() {
// Текущее время
now := time.Now()
fmt.Println("Сейчас:", now)
// Создание конкретной даты (год, месяц, день, час, мин, сек, наносек, Location)
specific := time.Date(2025, time.January, 15, 10, 30, 0, 0, time.UTC)
fmt.Println("Конкретная дата:", specific)
// Извлечение компонентов
fmt.Println("Год:", now.Year())
fmt.Println("Месяц:", now.Month())
fmt.Println("День:", now.Day())
fmt.Println("Час:", now.Hour())
fmt.Println("Минута:", now.Minute())
fmt.Println("Секунда:", now.Second())
fmt.Println("День недели:", now.Weekday())
}
Вывод программы покажет текущее время и его компоненты. Обратите внимание: time.Now() возвращает время в локальной временной зоне системы.
2. Форматирование и парсинг: отличительная особенность Go
В Go форматирование дат происходит не через символы типа YYYY-MM-DD, а через эталонную дату: Mon Jan 2 15:04:05 MST 2006 (или 01/02 03:04:05PM '06 -0700). Запомните эту магическую строку — она выглядит как 1 2 3 4 5 6 -7.
- 1 — месяц (01, Jan, January)
- 2 — день (02, 2)
- 3 — час в 12-часовом формате (03, 3)
- 4 — минута (04, 4)
- 5 — секунда (05, 5)
- 6 — год (06, 2006)
- -7 — часовой пояс (MST, -0700, -07:00)
Форматирование (Time → String)
now := time.Now()
// Стандартные форматы
fmt.Println(now.Format("2006-01-02 15:04:05")) // 2025-01-15 10:30:45
fmt.Println(now.Format("02.01.2006")) // 15.01.2025
fmt.Println(now.Format(time.RFC3339)) // 2025-01-15T10:30:45Z
fmt.Println(now.Format("Mon, 02 Jan 2006 15:04:05 MST")) // Wed, 15 Jan 2025 10:30:45 UTC
Парсинг (String → Time)
// Парсинг строки в time.Time
dateStr := "2025-01-15 10:30:45"
layout := "2006-01-02 15:04:05"
parsedTime, err := time.Parse(layout, dateStr)
if err != nil {
panic(err)
}
fmt.Println("Распарсено:", parsedTime)
// Парсинг с часовым поясом
dateWithZone := "2025-01-15T10:30:45+03:00"
parsedWithZone, _ := time.Parse(time.RFC3339, dateWithZone)
fmt.Println("С зоной:", parsedWithZone)
Если вам нужно распарсить дату в определённой временной зоне, используйте time.ParseInLocation().
3. Операции с датами: Duration, Add, Sub и сравнение
Тип time.Duration представляет интервал времени. Go предоставляет константы: Nanosecond, Microsecond, Millisecond, Second, Minute, Hour.
now := time.Now()
// Добавление времени
future := now.Add(72 * time.Hour) // +3 дня
fmt.Println("Через 72 часа:", future)
// Вычитание времени
past := now.Add(-30 * time.Minute) // 30 минут назад
fmt.Println("30 минут назад:", past)
// Разница между датами
diff := future.Sub(now)
fmt.Printf("Разница: %v (часов: %.0f)\n", diff, diff.Hours())
// Сравнение дат
if future.After(now) {
fmt.Println("future позже now")
}
if now.Before(future) {
fmt.Println("now раньше future")
}
if now.Equal(now) {
fmt.Println("now равно самому себе")
}
Также доступны методы AddDate(years, months, days int) для календарных операций и Truncate()/Round() для округления времени.
4. Таймеры, тикеры и работа с временными зонами
Go предоставляет встроенные механизмы для работы с событиями по времени.
Таймер (Timer) — однократное событие
timer := time.NewTimer(2 * time.Second)
fmt.Println("Таймер запущен, ждём 2 секунды...")
<-timer.C // Блокируется до срабатывания
fmt.Println("Таймер сработал!")
timer.Stop() // Остановить до срабатывания
Тикер (Ticker) — периодические события
ticker := time.NewTicker(1 * time.Second)
done := make(chan bool)
go func() {
for i := 0; i < 5; i++ {
fmt.Println("Тик:", <-ticker.C)
}
done <- true
}()
<-done
ticker.Stop()
fmt.Println("Тикер остановлен")
Временные зоны (Location)
// Загрузка временной зоны
loc, err := time.LoadLocation("Europe/Moscow")
if err != nil {
panic(err)
}
now := time.Now()
fmt.Println("Локальное:",