Avatar ·

Как преобразовать Unix timestamp (метку времени Unix) в time.Time в Go?

Всем привет! Я только начал изучать Go и столкнулся с проблемой при работе с временем. У меня есть API, которое возвращает время в формате Unix timestamp (например, 1696425600). Мне нужно преобразовать это число в объект time.Time, чтобы потом отформатировать его для отображения пользователю в читаемом виде, например, "2023-10-04 15:20:00".

Я перепробовал несколько подходов, но ничего не работает. Вот что я пытался сделать:

package main

import (
    "fmt"
    "time"
)

func main() {
    timestamp := int64(1696425600)
    
    // Первая попытка - просто присвоить
    // t := time.Time(timestamp) // Ошибка: cannot convert timestamp to time.Time
    
    // Вторая попытка - через Parse
    // t, _ := time.Parse("Unix timestamp", string(timestamp)) // Тоже не работает
    
    // Третья попытка - через UnixDate
    // t, _ := time.Parse(time.UnixDate, string(timestamp)) // Ошибка формата
    
    fmt.Println("Не могу преобразовать!")
}

Я понимаю, что timestamp — это количество секунд, прошедших с 1 января 1970 года, но не могу понять, как правильно скормить это Go. В Python я бы просто написал datetime.fromtimestamp(timestamp), а в Go что-то сложнее.

Подскажите, как правильно конвертировать Unix timestamp в time.Time? И можно ли потом красиво отформатировать дату для вывода пользователю? Заранее спасибо!

<<>>

Используйте функцию time.Unix() для преобразования timestamp

В Go для преобразования Unix timestamp (количество секунд с 1 января 1970 года) в time.Time существует специальная функция — time.Unix(sec, nsec int64). Она принимает два аргумента: количество секунд и количество наносекунд (обычно 0, если у вас только секунды).

Вот правильный способ решения вашей задачи:

package main

import (
    "fmt"
    "time"
)

func main() {
    // Ваш timestamp (количество секунд с 1970-01-01)
    timestamp := int64(1696425600)
    
    // Преобразуем в time.Time
    t := time.Unix(timestamp, 0)
    
    // Выводим результат
    fmt.Println(t) // 2023-10-04 12:00:00 +0000 UTC (зависит от вашего часового пояса)
    
    // Форматируем в читаемый вид
    formatted := t.Format("2006-01-02 15:04:05")
    fmt.Println(formatted) // 2023-10-04 12:00:00
    
    // Можно также указать часовой пояс
    loc, _ := time.LoadLocation("Europe/Moscow")
    tInMoscow := t.In(loc)
    fmt.Println(tInMoscow.Format("2006-01-02 15:04:05")) // 2023-10-04 15:00:00 (MSK)
}

Подробное объяснение

Функция time.Unix() возвращает значение time.Time, соответствующее заданному Unix timestamp. Первый параметр — секунды, второй — наносекунды. Если вам нужно только до секунд, передавайте 0 в качестве второго аргумента.

Важно: time.Unix() возвращает время в UTC. Если вам нужно локальное время, используйте метод .Local() или .In(location).

Работа с миллисекундами и наносекундами

Если ваш timestamp содержит миллисекунды или наносекунды, просто разделите его:

// Timestamp в миллисекундах (например, 1696425600123)
msTimestamp := int64(1696425600123)
sec := msTimestamp / 1000          // 1696425600
nsec := (msTimestamp % 1000) * 1e6 // 123000000 наносекунд
t := time.Unix(sec, nsec)
fmt.Println(t.Format("15:04:05.000")) // 12:00:00.123

Обратное преобразование (time.Time → Unix timestamp)

Для обратной операции используйте методы .Unix() и .UnixNano():

now := time.Now()
seconds := now.Unix()      // int64 — количество секунд
millis := now.UnixMilli()  // int64 — количество миллисекунд (Go 1.17+)
nanos := now.UnixNano()    // int64 — количество наносекунд

Частые ошибки начинающих

  • Не путайте time.Unix() с time.Parse(): Parse() нужен для строковых форматов, а не для чисел.
  • Проверяйте тип данных: timestamp должен быть int64. Если у вас int или string, сначала преобразуйте.
  • Учитывайте часовой пояс: если ваше приложение работает в разных регионах, всегда явно указывайте location.

Теперь вы сможете легко работать с Unix timestamp в Go!

<<>>

Альтернативный подход: работа с timestamp как со строкой

Иногда timestamp приходит в виде строки (например, из JSON или URL-параметра). В этом случае можно сначала преобразовать строку в число, а затем использовать time.Unix():

package main

import (
    "fmt"
    "strconv"
    "time"
)

func main() {
    timestampStr := "1696425600"
    
    // Преобразуем строку в int64
    timestamp, err := strconv.ParseInt(timestampStr, 10, 64)
    if err != nil {
        fmt.Println("Ошибка парсинга:", err)
        return
    }
    
    // Конвертируем в time.Time
    t := time.Unix(timestamp, 0)
    fmt.Println(t.Format("2006-01-02 15:04:05"))
}

Обработка ошибок

Всегда проверяйте ошибки при парсинге строки — некорректный timestamp может привести к панике или неверным результатам.

Использование с JSON

Если вы получаете timestamp из JSON, можно использовать пользовательский тип с реализацией интерфейса json.Unmarshaler:

type UnixTime struct {
    time.Time
}

func (u *UnixTime) UnmarshalJSON(b []byte) error {
    var timestamp int64
    if err := json.Unmarshal(b, ×tamp); err != nil {
        return err
    }
    u.Time = time.Unix(timestamp, 0)
    return nil
}

Этот подход удобен, если в проекте много мест, где нужно десериализовать Unix timestamp из JSON.