Convert UTC to "local" time in Go

huangapple go评论94阅读模式
英文:

Convert UTC to "local" time in 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)
}
英文:

How can I convert UTC time to local time?

I've created a map with the UTC difference for all the countries I need the local time. Then I add that difference as duration to the current time (UTC) and print the result hoping that's the local time of that specific country.

For some reasons the result is wrong. For example with Hungary there is one hour difference. Any idea why I'm getting incorrect results?

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)
}

答案1

得分: 57

请注意,playground的时间设置为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)
}

以上是要翻译的内容。

英文:

Keep in mind that the playground has the time set to 2009-11-10 23:00:00 +0000 UTC, so it is working.

The proper way is to use time.LoadLocation though, here's an example:

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)
}

答案2

得分: 20

你的方法有问题。一个国家可以有多个时区,例如美国和俄罗斯。由于夏令时的存在,一个时区可以有多个时间,例如匈牙利。匈牙利的标准时间是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数据库时区

时区

匈牙利时间

英文:

Your approach is flawed. A country can have several time zones, for example, US and Russia. Because of daylight saving time (DST), a time zone can have more than one time, for example, Hungary. Hungary is UTC +1:00 and is also UTC+2:00 for DST.

For each location that you want the local time for a given UTC time, use the IANA (tzdata) time zone location. For example,

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"))
}

Output:

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

References:

IANA Time Zone Database

tz database

tz database time zones

Time zone

Time in Hungary

答案3

得分: 3

省去麻烦,使用位置"Local"而不是特定的时区。以下是一个完整且实用的本地时间和UTC转换示例:

package main

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

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

// 一个完整的循环示例,包括接收本地日期和时间、传递给数据库、以UTC格式检索,并格式化为本地日期时间
// 这在*任何*时区都适用
func main() {
	// 如果使用表单进行输入,强烈建议使用受控格式输入,例如
	// <input type="date" ...> 和 <input type="time" ...>
	locallyEnteredDate := "2017-07-16"
	locallyEnteredTime := "14:00"

	// 从接收到的字段构建一个时间对象(时间对象包括区域信息)
	// 我们假设代码运行在与当前用户相同的时区的服务器上
	zone, _ := time.Now().Zone() // 获取本地时区
	dateTimeZ := locallyEnteredDate + " " + locallyEnteredTime + " " + zone
	dte, err := time.Parse(dateTimeFormat, dateTimeZ)
	if err != nil {
		log.Fatal("解析输入的日期时间错误", err)
	}
	fmt.Println("dte:", dte) // dte 是一个合法的时间对象
	// 或许我们将其保存在数据库中。
	// 一个良好的数据库驱动程序应该将时间对象保存为带有时区的UTC时间,并返回一个带有UTC时区的时间对象。

	// 为了这个示例,假设一个与 `dte` 相同的对象被返回
	// dte := 从数据库接收()

	// 将接收到的日期转换为本地时间。
	// 注意使用方便的 "Local" 位置 https://golang.org/pkg/time/#LoadLocation。
	localLoc, err := time.LoadLocation("Local")
	if err != nil {
		log.Fatal("加载位置“Local”失败")
	}
	localDateTime := dte.In(localLoc)

	fmt.Println("日期:", localDateTime.Format(dateFormat))
	fmt.Println("时间:", localDateTime.Format(timeFormat))
}
英文:

Save yourself the hassle of messing with specific zones, use location "Local". Here's a full and practical example of local and UTC conversion:

package main
import (
&quot;fmt&quot;
&quot;log&quot;
&quot;time&quot;
)
const (
dateTimeFormat = &quot;2006-01-02 15:04 MST&quot;
dateFormat    = &quot;2006-01-02&quot;
timeFormat    = &quot;15:04&quot;
)
// 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
// &lt;input type=&quot;date&quot; ... &gt; and &lt;input type=&quot;time&quot; ... &gt;
locallyEnteredDate := &quot;2017-07-16&quot;
locallyEnteredTime := &quot;14:00&quot;
// 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 + &quot; &quot; + locallyEnteredTime + &quot; &quot; + zone
dte, err := time.Parse(dateTimeFormat, dateTimeZ)
if err != nil {
log.Fatal(&quot;Error parsing entered datetime&quot;, err)
}
fmt.Println(&quot;dte:&quot;, 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&#39;s assume an object identical to `dte` is returned
// dte := ReceiveFromDatabase()
// Convert received date to local.
// Note the use of the convenient &quot;Local&quot; location https://golang.org/pkg/time/#LoadLocation.
localLoc, err := time.LoadLocation(&quot;Local&quot;)
if err != nil {
log.Fatal(`Failed to load location &quot;Local&quot;`)
}
localDateTime := dte.In(localLoc)
fmt.Println(&quot;Date:&quot;, localDateTime.Format(dateFormat))
fmt.Println(&quot;Time:&quot;, localDateTime.Format(timeFormat))
}

huangapple
  • 本文由 发表于 2014年8月15日 05:52:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/25318154.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定