go - 如何获取本地时区的全名?
问题描述
例如,服务器时区是“欧洲/马德里”,我这样做:
now := time.Now()
fmt.Printf("%v", now.Location().String()) // prints "Local"
zone, _ := now.Zone()
fmt.Printf("%v", zone) // prints "CEST"
但我想要“欧洲/马德里”
时区:https ://en.wikipedia.org/wiki/List_of_tz_database_time_zones
编辑
此处提供了完整的跨平台(windows、linux、mac)答案:https ://github.com/thlib/go-timezone-local
所有功劳归于 colm.anseo和MrFuppes提供以下答案:
解决方案
IANA 时区可在大多数操作系统 (*) 上使用。Go
标准库也提供它:
runtime.GOROOT() + "/lib/time/zoneinfo.zip"
按名称选择时区以及该名称是否记录在任何地方都由操作系统决定:
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
本地操作系统时间(timezone.go) - 但这可以用TZ
环境变量覆盖。
因此,可以通过符号链接目标路径推断本地操作系统时区的名称,如下所示:
// 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
推荐阅读
- scheme - 有没有办法在列表中没有列表的情况下进行打印?
- python - 如何在微服务中存储版本化的 XSLT 文件
- c - malloc() 是否在循环中重用相同的内存地址?
- unit-testing - 使用 pytest 测试 Flask 应用程序时找不到 404
- javascript - 如何在 JavaScript 中使用 KD-Tree 比较 2 个数据集?
- javascript - 是否可以在输入字段中显示反应组件?
- c# - C# WPF - 使用 VS2019 安装向导为计算机上的每个用户使用本地数据库 sqlite 部署应用程序
- ios - Xamarin.iOS 中的 OneSignal - 屏幕锁定时没有通知声音
- python - Dask read_parquet 添加了一个额外的列 dir0
- javascript - 如何从外部修改 Angular 生成的 DOM(无需访问源代码)?