Avatar ·

Вычитание time.Duration из time.Time в Go: как правильно?

Привет, коллеги! Я только начал изучать Go и столкнулся с проблемой при работе с датами и временем. Мне нужно отнять от текущего момента, например, 24 часа, чтобы получить время "вчера в это же время". Я пишу что-то вроде: ```go package main import ( "fmt" "time" ) func main() { now := time.Now() yesterday := now - 24 * time.Hour // Ошибка! fmt.Println(yesterday) } ``` Но компилятор выдает ошибку: `invalid operation: operator - not defined on time.Time`. Я понимаю, что `time.Time` — это структура, а не число, и напрямую вычитать из нее нельзя. Пробовал использовать `time.Duration`, но запутался. В документации написано, что `time.Time` можно складывать с `time.Duration`, но как правильно вычитать? Мне нужно получить точное значение, чтобы потом сравнить с другими датами. Подскажите, как правильно отнять интервал от времени в Go? Заранее спасибо! <<>>

Используйте метод Add() с отрицательным значением

В Go для вычитания интервала из time.Time используется метод Add(), который принимает time.Duration. Чтобы вычесть время, передайте отрицательное значение длительности. Это самый простой и идиоматичный способ.

package main

import (
	"fmt"
	"time"
)

func main() {
	now := time.Now()
	// Вычитаем 24 часа: передаём -24 * time.Hour
	yesterday := now.Add(-24 * time.Hour)
	fmt.Println("Сейчас:", now)
	fmt.Println("Вчера:", yesterday)
}

Также можно использовать time.Duration с отрицательным знаком:

duration := 24 * time.Hour
yesterday := now.Add(-duration) // эквивалентно now.Add(-24 * time.Hour)

Почему это работает?

Метод Add() определён для time.Time и возвращает новое значение, смещённое на указанную длительность. Отрицательная длительность — это просто способ сказать "назад во времени". Никаких операторов вроде - для структур не нужно, Go использует методы для таких операций.

Дополнительные примеры

  • Вычитание нескольких часов: twoHoursAgo := now.Add(-2 * time.Hour)
  • Вычитание минут и секунд: tenMinutesAgo := now.Add(-10 * time.Minute)
  • Комбинирование длительностей: complexDuration := 2*time.Hour + 30*time.Minute + 15*time.Second
    result := now.Add(-complexDuration)
  • Вычитание с учётом локали: now.In(time.UTC).Add(-24 * time.Hour)

Важные замечания

Не путайте метод Sub() — он предназначен для вычисления разницы между двумя time.Time и возвращает time.Duration. Для вычитания интервала используйте только Add() с отрицательным значением.

// Правильно: вычитание интервала
past := now.Add(-24 * time.Hour)

// Неправильно: Sub() для другой цели
diff := now.Sub(past) // diff == 24 * time.Hour

Также помните, что при работе с переходами на летнее/зимнее время Add() учитывает календарные изменения. Если вам нужно именно "вчера в то же календарное время", используйте AddDate(0, 0, -1), но это может дать другой результат из-за сдвига часов.

<<>>

Альтернативный подход: использование AddDate()

Если вам нужно вычесть не просто интервал времени, а календарный день, месяц или год, удобнее использовать метод AddDate(). Он принимает три аргумента: годы, месяцы, дни (могут быть отрицательными).

package main

import (
	"fmt"
	"time"
)

func main() {
	now := time.Now()
	// Вычитаем 1 день (календарно)
	yesterday := now.AddDate(0, 0, -1)
	fmt.Println("Вчера (календарно):", yesterday)

	// Вычитаем 1 месяц
	lastMonth := now.AddDate(0, -1, 0)
	fmt.Println("Месяц назад:", lastMonth)
}

Этот метод полезен, когда важна календарная дата, а не точное количество часов. Например, если сейчас 15 марта 14:00, то AddDate(0,0,-1) вернёт 14 марта 14:00, даже если 14 марта был переход на летнее время (в этом случае разница может быть 23 или 25 часов). Add(-24*time.Hour) всегда отнимет ровно 24 часа, что может привести к другому времени суток.

Выбирайте подход в зависимости от задачи: для точных интервалов — Add() с отрицательной длительностью, для календарных операций — AddDate().