Преобразование UTC в местное время в Go

Как преобразовать время UTC в местное время?

Я создал карту с разницей UTC для всех стран, в которых мне нужно местное время. Затем я добавляю эту разницу как продолжительность к текущему времени (UTC) и печатаю результат, надеясь, что это местное время этой конкретной страны.

По некоторым причинам результат неверный. Например, для Венгрии разница составляет один час. Любая идея, почему я получаю неверные результаты?

package main

import "fmt"
import "time"

func main() {

    m := make(map[string]string)
    m["Hungary"] = "+01.00h"

    offSet, err := time.ParseDuration(m["Hungary"])
    if err != nil {
        panic(err)
    }
    t := time.Now().UTC().Add(offSet)
    nice := t.Format("15:04")

    fmt.Println(nice)
}

person hey    schedule 14.08.2014    source источник
comment
Что именно не работает? Ваш код выводит время часов через час после UTC.   -  person JimB    schedule 15.08.2014
comment
Я ожидал получить местное время в Венгрии, то есть UTC+1, но есть разница в час между временем, сообщаемым tz [1], которое я считаю правильным, и временем, сгенерированным go [1] timeanddate.com/worldclock/hungary/budapest   -  person hey    schedule 15.08.2014
comment
Время игровой площадки начинается с 2009-11-10 23:00:00 +0000 UTC   -  person OneOfOne    schedule 15.08.2014
comment
@OneOfOne Я на самом деле тестирую его на своей машине, поэтому нет ссылки на игровую площадку.   -  person hey    schedule 15.08.2014
comment
В вашей системе уже есть база данных часовых поясов. Используйте 1_   -  person JimB    schedule 15.08.2014
comment
@JimB Мне нужно указать одно или несколько местное время по странам. Я не уверен, что смогу сделать это, используя time.Location, поскольку он обеспечивает смещение/часовой пояс по регионам (например, Европа/Лондон, а не Великобритания или Шотландия и т. д.)?   -  person hey    schedule 15.08.2014
comment
@hey, хорошо, я это вижу, но вы, вероятно, хотите сопоставить их с time.Locations, а не с пользовательской продолжительностью.   -  person JimB    schedule 15.08.2014


Ответы (3)


Имейте в виду, что на игровой площадке время установлено на 2009-11-10 23:00:00 +0000 UTC, поэтому оно работает.

Однако правильный способ - использовать time.LoadLocation, вот пример:

var countryTz = map[string]string{
    "Hungary": "Europe/Budapest",
    "Egypt":   "Africa/Cairo",
}

func timeIn(name string) time.Time {
    loc, err := time.LoadLocation(countryTz[name])
    if err != nil {
        panic(err)
    }
    return time.Now().In(loc)
}

func main() {
    utc := time.Now().UTC().Format("15:04")
    hun := timeIn("Hungary").Format("15:04")
    eg := timeIn("Egypt").Format("15:04")
    fmt.Println(utc, hun, eg)
}
person OneOfOne    schedule 14.08.2014
comment
он по-прежнему отображает неправильное время по сравнению с timeanddate.com/worldclock/hungary/budapest . На моей машине написано 23:21, но на самом деле кажется 00:24. Я получаю ту же разницу с моим кодом, поэтому возникает вопрос. - person hey; 15.08.2014
comment
или вы могли бы time.LoadLocation("Europe/Budapest") - person JimB; 15.08.2014
comment
play.golang.org/p/n_D9fA6WBQ правильно работает в моей системе и печатает правильное время, может часы на компе сбились? ты случайно не в Египте? - person OneOfOne; 15.08.2014
comment
Я уже сделал карту со страной → UTC(s), так как мне нужно указать все местное время(а) в конкретной стране. Я предполагаю, что использование time.Loadlocation потребует еще одной карты? Невозможно получить местное время с учетом смещения UTC? - person hey; 15.08.2014
comment
Вы должны реализовать это так же, как m:= map[string]string{"Hungary": "Europe/Budapest"}, а затем передать это в LoadLocation, я обновлю код. - person OneOfOne; 15.08.2014
comment
да, я понял ... просто UTC показался мне более универсальным, и у меня уже была карта страны [UTC]. Поиск местоположения всех стран может занять много времени. Что касается моего местоположения, я протестировал код как на своей машине, так и на удаленном сервере, и я получил тот же результат (разница в 1 час). Оба они установлены на BST, который, я думаю, UTC + 1. - person hey; 15.08.2014
comment
@ эй, хотя это кажется более универсальным, но самостоятельное отслеживание летнего времени (особенно потому, что некоторые правительства могут менять его несколько раз в год, как здесь, в Египте) может очень быстро запутаться. - person OneOfOne; 15.08.2014
comment
ааа ... Я не знал, что летнее время так испорчено. - person hey; 15.08.2014
comment
Спасибо, что показали использование метода time.Time.In. Это и его цель совершенно ускользнули от меня, когда я думал, что знаю, как использовать пакет времени. Как обычно, когда я думаю, что столкнулся с ошибкой в ​​пакете golang, я действительно обнаружил предположение, которое делал. - person WeakPointer; 23.05.2018
comment
Список стран: en.wikipedia.org/wiki/List_of_tz_database_time_zones - person Ninh Pham; 21.02.2021

Ваш подход ошибочен. В стране может быть несколько часовых поясов, например, США и Россия. Из-за летнего времени (DST) часовой пояс может иметь более одного времени, например, Венгрия. Венгрия — это UTC +1:00, а также UTC+2:00 для перехода на летнее время.

Для каждого местоположения, для которого требуется местное время для данного времени UTC, используйте местоположение часового пояса IANA (tzdata). Например,

package main

import (
    "fmt"
    "time"
)

func main() {
    utc := time.Now().UTC()
    fmt.Println(utc)
    local := utc
    location, err := time.LoadLocation("Europe/Budapest")
    if err == nil {
        local = local.In(location)
    }
    fmt.Println("UTC", utc.Format("15:04"), local.Location(), local.Format("15:04"))
    local = utc
    location, err = time.LoadLocation("America/Los_Angeles")
    if err == nil {
        local = local.In(location)
    }
    fmt.Println("UTC", utc.Format("15:04"), local.Location(), local.Format("15:04"))
}

Выход:

2014-08-14 23:57:09.151377514 +0000 UTC
UTC 23:57 Europe/Budapest 01:57
UTC 23:57 America/Los_Angeles 16:57

Использованная литература:

База данных часовых поясов IANA

база данных tz

часовые пояса базы данных tz

Часовой пояс

Время в Венгрии

person peterSO    schedule 14.08.2014

Избавьте себя от возни с определенными зонами, используйте локацию «Локальная». Вот полный и практический пример локального преобразования и преобразования UTC:

package main

import (
    "fmt"
    "log"
    "time"
)

const (
    dateTimeFormat = "2006-01-02 15:04 MST"
    dateFormat    = "2006-01-02"
    timeFormat    = "15:04"
)

// A full cycle example of receiving local date and time,
// handing off to a database, retrieving as UTC, and formatting as local datetime
// This should be good in *any* timezone
func main() {
    // If using a form for entry, I strongly suggest a controlled format input like
    // <input type="date" ... > and <input type="time" ... >
    locallyEnteredDate := "2017-07-16"
    locallyEnteredTime := "14:00"

    // Build a time object from received fields (time objects include zone info)
    // We are assuming the code is running on a server that is in the same zone as the current user
    zone, _ := time.Now().Zone() // get the local zone
    dateTimeZ := locallyEnteredDate + " " + locallyEnteredTime + " " + zone
    dte, err := time.Parse(dateTimeFormat, dateTimeZ)
    if err != nil {
        log.Fatal("Error parsing entered datetime", err)
    }
    fmt.Println("dte:", dte) // dte is a legit time object
    // Perhaps we are saving this in a database.
    // A good database driver should save the time object as UTC in a time with zone field,
    // and return a time object with UTC as zone.

    // For the sake of this example, let's assume an object identical to `dte` is returned
    // dte := ReceiveFromDatabase()

    // Convert received date to local.
    // Note the use of the convenient "Local" location https://golang.org/pkg/time/#LoadLocation.
    localLoc, err := time.LoadLocation("Local")
    if err != nil {
        log.Fatal(`Failed to load location "Local"`)
    }
    localDateTime := dte.In(localLoc)

    fmt.Println("Date:", localDateTime.Format(dateFormat))
    fmt.Println("Time:", localDateTime.Format(timeFormat))
}
person Rohanthewiz    schedule 17.07.2017
comment
Да, я дал дополнительную информацию в этом ответе, но это поможет новичкам увидеть полную картину работы с датой, временем и зонами. - person Rohanthewiz; 17.07.2017
comment
Работать со временем очень сложно. Хорошей практикой является четкое указание часовых поясов, когда вам нужно иметь с ними дело. В ОП упоминается несколько стран, есть большая вероятность, что им нужно учитывать разные часовые пояса. Ваша враждебность по отношению к людям, которые все еще учатся, не ценится. - person Dynom; 21.11.2019