如何获取当地时区的全名?
How to get the full name of the local timezone?
例如服务器时区是“Europe/Madrid”,我这样做:
now := time.Now()
fmt.Printf("%v", now.Location().String()) // prints "Local"
zone, _ := now.Zone()
fmt.Printf("%v", zone) // prints "CEST"
但我想要“Europe/Madrid”
时区:https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
编辑
完全跨平台(windows、linux、mac)此处提供答案:https://github.com/thlib/go-timezone-local
所有功劳归功于 colm.anseo and MrFuppes 提供以下答案:
IANA timezones 在大多数 OSes (*) 上可用。 Go
标准库也提供了它:
runtime.GOROOT() + "/lib/time/zoneinfo.zip"
name选择时区以及这个名字是否记录在任何地方取决于OS:
ls -al /etc/localtime
# MacOS
/etc/localtime -> /var/db/timezone/zoneinfo/America/New_York
# Linux
/etc/localtime -> ../usr/share/zoneinfo/America/New_York
因此在上述情况下可以推断出名称。
注意:Go
默认使用 /etc/localtime
作为本地 OS 时间 (timezone.go) - 但可以用 TZ
环境覆盖变量。
因此可以通过符号链接目标路径推断出本地 OS 时区的名称:
// tz.go
//go:build !windows
// +build !windows
const localZoneFile = "/etc/localtime" // symlinked file - set by OS
var ValidateLocationName = true // set to false to disable time.LoadLocation validation check
func LocalTZLocationName() (name string, err error) {
var ok bool
if name, ok = os.LookupEnv("TZ"); ok {
if name == "" { // if blank - Go treats this as UTC
return "UTC", nil
}
if ValidateLocationName {
_, err = time.LoadLocation(name) // optional validation of name
}
return
}
fi, err := os.Lstat(localZoneFile)
if err != nil {
err = fmt.Errorf("failed to stat %q: %w", localZoneFile, err)
return
}
if (fi.Mode() & os.ModeSymlink) == 0 {
err = fmt.Errorf("%q is not a symlink - cannot infer name", localZoneFile)
return
}
p, err := os.Readlink(localZoneFile)
if err != nil {
return
}
name, err = inferFromPath(p) // handles 1 & 2 part zone names
return
}
func inferFromPath(p string) (name string, err error) {
dir, lname := path.Split(p)
if len(dir) == 0 || len(lname) == 0 {
err = fmt.Errorf("cannot infer timezone name from path: %q", p)
return
}
_, fname := path.Split(dir[:len(dir)-1])
if fname == "zoneinfo" {
name = lname // e.g. /usr/share/zoneinfo/Japan
} else {
name = fname + string(os.PathSeparator) + lname // e.g. /usr/share/zoneinfo/Asia/Tokyo
}
if ValidateLocationName {
_, err = time.LoadLocation(name) // optional validation of name
}
return
}
// tz_windows.go
//go:build windows
// +build windows
func LocalTZLocationName() (string, error) {
return "", fmt.Errorf("local timezone name inference not available on Windows")
}
(*) 对于 Windows
根据 Go 源 (zoneinfo_windows.go),区域信息是从 Go 标准库加载的,由于:
// BUG(brainman,rsc): On Windows, the operating system does not provide complete
// time zone information.
// The implementation assumes that this year's rules for daylight savings
// time apply to all previous and future years as well.
Window 的注册表项:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation
存储本地时区 - 但似乎不存储长格式位置名称:
TimeZoneKeyName=Eastern Standard Time
在 Windows 上,该过程也并不过分复杂。作为 ,您可以读取相应的注册表项以获取 Windows 使用的时区名称。然后将其映射到适当的 IANA 时区名称。
从注册表读取 tz
package main
import (
"log"
"golang.org/x/sys/windows/registry"
)
var winTZtoIANA = map[string]string{
// just includes my time zone; to be extended...
"W. Europe Standard Time": "Europe/Berlin",
}
func main() {
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\CurrentControlSet\Control\TimeZoneInformation`, registry.QUERY_VALUE)
if err != nil {
log.Fatal(err)
}
defer k.Close()
winTZname, _, err := k.GetStringValue("TimeZoneKeyName")
if err != nil {
log.Fatal(err)
}
log.Printf("local time zone in Windows: %v\n", winTZname)
if IANATZname, ok := winTZtoIANA[winTZname]; ok {
log.Printf("local time zone IANA name: %v\n", IANATZname)
} else {
log.Fatalf("could not find IANA tz name for %v", winTZname)
}
}
或者,您可以读取tzutil /g
的输出:
cmd := exec.Command("tzutil", "/g")
winTZname, err := cmd.Output() // note: winTZname is []byte, need to convert to string
if err != nil {
// handle error
}
您可以在 Python 中找到解决给定问题的综合 mapping here. It's based on Lennart Regebro's tzlocal 包。
例如服务器时区是“Europe/Madrid”,我这样做:
now := time.Now()
fmt.Printf("%v", now.Location().String()) // prints "Local"
zone, _ := now.Zone()
fmt.Printf("%v", zone) // prints "CEST"
但我想要“Europe/Madrid”
时区:https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
编辑
完全跨平台(windows、linux、mac)此处提供答案:https://github.com/thlib/go-timezone-local
所有功劳归功于 colm.anseo and MrFuppes 提供以下答案:
IANA timezones 在大多数 OSes (*) 上可用。 Go
标准库也提供了它:
runtime.GOROOT() + "/lib/time/zoneinfo.zip"
name选择时区以及这个名字是否记录在任何地方取决于OS:
ls -al /etc/localtime
# MacOS
/etc/localtime -> /var/db/timezone/zoneinfo/America/New_York
# Linux
/etc/localtime -> ../usr/share/zoneinfo/America/New_York
因此在上述情况下可以推断出名称。
注意:Go
默认使用 /etc/localtime
作为本地 OS 时间 (timezone.go) - 但可以用 TZ
环境覆盖变量。
因此可以通过符号链接目标路径推断出本地 OS 时区的名称:
// tz.go
//go:build !windows
// +build !windows
const localZoneFile = "/etc/localtime" // symlinked file - set by OS
var ValidateLocationName = true // set to false to disable time.LoadLocation validation check
func LocalTZLocationName() (name string, err error) {
var ok bool
if name, ok = os.LookupEnv("TZ"); ok {
if name == "" { // if blank - Go treats this as UTC
return "UTC", nil
}
if ValidateLocationName {
_, err = time.LoadLocation(name) // optional validation of name
}
return
}
fi, err := os.Lstat(localZoneFile)
if err != nil {
err = fmt.Errorf("failed to stat %q: %w", localZoneFile, err)
return
}
if (fi.Mode() & os.ModeSymlink) == 0 {
err = fmt.Errorf("%q is not a symlink - cannot infer name", localZoneFile)
return
}
p, err := os.Readlink(localZoneFile)
if err != nil {
return
}
name, err = inferFromPath(p) // handles 1 & 2 part zone names
return
}
func inferFromPath(p string) (name string, err error) {
dir, lname := path.Split(p)
if len(dir) == 0 || len(lname) == 0 {
err = fmt.Errorf("cannot infer timezone name from path: %q", p)
return
}
_, fname := path.Split(dir[:len(dir)-1])
if fname == "zoneinfo" {
name = lname // e.g. /usr/share/zoneinfo/Japan
} else {
name = fname + string(os.PathSeparator) + lname // e.g. /usr/share/zoneinfo/Asia/Tokyo
}
if ValidateLocationName {
_, err = time.LoadLocation(name) // optional validation of name
}
return
}
// tz_windows.go
//go:build windows
// +build windows
func LocalTZLocationName() (string, error) {
return "", fmt.Errorf("local timezone name inference not available on Windows")
}
(*) 对于 Windows
根据 Go 源 (zoneinfo_windows.go),区域信息是从 Go 标准库加载的,由于:
// BUG(brainman,rsc): On Windows, the operating system does not provide complete
// time zone information.
// The implementation assumes that this year's rules for daylight savings
// time apply to all previous and future years as well.
Window 的注册表项:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation
存储本地时区 - 但似乎不存储长格式位置名称:
TimeZoneKeyName=Eastern Standard Time
在 Windows 上,该过程也并不过分复杂。作为
从注册表读取 tz
package main
import (
"log"
"golang.org/x/sys/windows/registry"
)
var winTZtoIANA = map[string]string{
// just includes my time zone; to be extended...
"W. Europe Standard Time": "Europe/Berlin",
}
func main() {
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\CurrentControlSet\Control\TimeZoneInformation`, registry.QUERY_VALUE)
if err != nil {
log.Fatal(err)
}
defer k.Close()
winTZname, _, err := k.GetStringValue("TimeZoneKeyName")
if err != nil {
log.Fatal(err)
}
log.Printf("local time zone in Windows: %v\n", winTZname)
if IANATZname, ok := winTZtoIANA[winTZname]; ok {
log.Printf("local time zone IANA name: %v\n", IANATZname)
} else {
log.Fatalf("could not find IANA tz name for %v", winTZname)
}
}
或者,您可以读取tzutil /g
的输出:
cmd := exec.Command("tzutil", "/g")
winTZname, err := cmd.Output() // note: winTZname is []byte, need to convert to string
if err != nil {
// handle error
}
您可以在 Python 中找到解决给定问题的综合 mapping here. It's based on Lennart Regebro's tzlocal 包。