在golang中设置全局时区

i86rm4rw  于 2023-02-01  发布在  Go
关注(0)|答案(4)|浏览(193)

我正在尝试修改应用程序的golang时区
我看了一下time包,初始化时区发生在
时间/区域信息_unix. go@initLocal
该函数只是尝试读取环境变量TZ,如果它有效,则加载它
如果不是则返回/etc/localtime如果无效则返回UTC
到目前为止我所尝试的
1-工作正常-但我不想使用这两种方法中的任何一种-

  • 在我的docker文件中,我将一个ENV传递给容器TZ = Africa/Cairo
  • 进入容器bash,运行$ export TZ = Africa/Cairo

2-不管用

  • 在我的应用程序初始化中(应用程序初始化在一个单独的包中,该包正在main中导入),我使用OS. SetEnv("TZ","Africa/Cairo")

当我简化main并使用os.setEnv("TZ","Africa/Cairo")而不导入除"os-time"之外的任何其他包时,它可以按预期工作
关于如何使第二种方法奏效,你有什么想法吗?
Docker图像:戈兰:1.11.2

xuo3flqw

xuo3flqw1#

您可以使用os.Setenv("TZ", "Africa/Cairo")在应用内部实现您想要的功能,重要的是您必须在任何其他包使用time包中的任何内容之前调用此函数。
如何确保?创建一个除了设置时区之外不做任何其他事情的包(稍后您可能会向其中添加其他内容,但对于我们的示例来说,这就足够了)。
就像这样:

package tzinit

import (
    "os"
)

func init() {
    os.Setenv("TZ", "Africa/Cairo")
}

导入此tzinit第一个内容,如下所示:

package main

import _ "path/to/tzinit"

// Your other, "regular" imports:
import (
    "fmt"
    "os"
    "time"
    ...
)

因此,设置TZ env var将发生在任何其他包可以访问time包之前。
注意,我只为tzinit使用了一个单独的import声明,这样做的原因是因为许多代码编辑器/IDE会按字母顺序重新排列导入,这将确保导入tzinit仍然是第一个导入。

    • 一句警告**

质量标准:包初始化说明了初始化包的要求和规则,但未指定处理导入的顺序(唯一可以保证的是所有引用的包在使用之前都将被递归地初始化)。这意味着尽管当前的编译器按照所列出的那样处理它们,你不能100%的依赖它。即使是main包也有多个源文件的问题,以不同的顺序提供给编译器也可能改变初始化顺序。2规范有这样一个"建议":
为确保初始化行为可重现,建议生成系统按词法文件名顺序向编译器提供属于同一包的多个文件。
因此,为了安全起见,最好在Go应用程序启动之前设置TZ环境变量。

lxkprmvk

lxkprmvk2#

在这里添加我的答案给那些偶然发现这个页面的人。在time包中有一个全局变量,在main.go中这样使用它

package main

import "time"

func main() {
    loc, err := time.LoadLocation("Africa/Cairo")
    // handle err
    time.Local = loc // -> this is setting the global timezone
}

你的系统必须安装时区数据库。在docker中,你必须apt get/apk add tzdata。但是如果你使用go1.15,你也可以嵌入时区数据库而不需要在系统上安装tzdata

package main

import (
    "time"
    _ "time/tzdata"
)

func main() {
    loc, err := time.LoadLocation("Africa/Cairo")
    // handle err
    time.Local = loc // -> this is setting the global timezone
}
wooyq4lh

wooyq4lh3#

我可能会迟到,但是在全局环境中设置时区并不是一个可靠的方法。它应该在变量或结构中全局设置。下面是一个在变量中设置时区的示例。也见于Go Playground

package main

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

func main() {
    if err := setTimezone("America/Los_Angeles"); err != nil {
        log.Fatal(err) // most likely timezone not loaded in Docker OS
    }
    t := getTime(time.Now())
    fmt.Println(t)
}

var loc *time.Location

func setTimezone(tz string) error {
    location, err := time.LoadLocation(tz)
    if err != nil {
        return err
    }
    loc = location
    return nil
}

func getTime(t time.Time) time.Time {
    return t.In(loc)
}
frebpwbc

frebpwbc4#

请注意,如果您想在AWS time.LoadLocation上部署应用,可能会返回错误,因为它找不到数据库文件。
LoadLocation按顺序在以下位置查找IANA时区数据库:

  • 由ZONEINFO环境变量命名的目录或未压缩的zip文件
  • 在Unix系统上,系统标准安装位置
  • $GOROOT/库/时间zoneinfo.zip
  • time/tzdata包(如果已导入)

您应该导入time/tzdata包以解决此问题:

import _ "time/tzdata" // Important!

func main() {
    location, err := time.LoadLocation("Europe/Berlin")
    if err != nil {
        log.Fatal().Msgf("Err loading location: %v", err)
    }
    time.Local = location
}

相关问题