【问题标题】:Zone method from time package doesn't return updated timezone if timezone is changed during process execution如果在流程执行期间更改了时区,则时间包中的区域方法不会返回更新的时区
【发布时间】:2021-07-09 06:58:34
【问题描述】:

我在下面编写了一个简单的 Go 代码来获取系统时区。它工作正常并返回系统的当前时区。问题是如果我在流程执行之间更改时区,那么它不会返回更新的时区。它只返回旧时区。

package main

import (
    "fmt"
    "time"
)

func main() {
    
    for i := 0; i < 10; i++ {
        t := time.Now()
        zone, offset := t.Zone()
        fmt.Println(zone, offset)
        z, _ := t.Zone()
        fmt.Println("timezone", z)
    }
}

【问题讨论】:

  • 如何“更改流程执行之间的时区”?
  • @jub0bs 我认为他在谈论更改系统时区,程序执行
  • 如果您只需要处理时间,独立于系统设置,请使用 UTC;例如t := time.Now().UTC().
  • @jub0bs 这只是一个示例程序。我正在调试模式下通过添加断点并在下次调用之前更改时区来测试它。我的主程序始终在内存中作为后台进程运行,该进程以特定频率收集时区信息,因此如果用户更改系统时区,它将无法获得正确的时区。
  • @MrFuppes:我的应用程序要求是读取系统当前时区的用户当前活动数据,所以我需要读取系统当前时区。我正在阅读 UTC 时间,但也想阅读系统时区。

标签: go timezone


【解决方案1】:

如果您查看source code of the time package,您会发现本地位置在应用程序启动时设置一次,由sync.Once(或更准确地说:当tz信息第一次调用.get()获取):

// localLoc is separate so that initLocal can initialize
// it even if a client has changed Local.
var localLoc Location
var localOnce sync.Once

func (l *Location) get() *Location {
    if l == nil {
        return &utcLoc
    }
    if l == &localLoc {
        localOnce.Do(initLocal)
    }
    return l
}

现在,initLocal 依赖于平台,因为不同的平台处理时区的方式不同;例如for Windows 你有:

func initLocal() {
    var i syscall.Timezoneinformation
    if _, err := syscall.GetTimeZoneInformation(&i); err != nil {
        localLoc.name = "UTC"
        return
    }
    initLocalFromTZI(&i)
}

从这里开始,您可以通过源代码来了解如何为您的应用程序实现它。例如,在 Windows 上,您可以通过调用 syscall.Timezoneinformation 结构的 BiasDaylightBias 字段以分钟为单位获取 UTC 偏移量。

【讨论】:

    【解决方案2】:

    谢谢,@MrFuppes

    通过从 Golang 调用 Win32 API 解决了该问题。下面是代码sn-p。

    package main
    
    import (
        "fmt"
        "time"
        "syscall"
        "strconv"
        "unicode/utf16"
    )
    
    func main() {
        for index := 0; index < 10; index++ {
            now := time.Now()
            timeZone, _ := now.Zone()
            fmt.Println("timezone", timeZone)
    
            var itz syscall.Timezoneinformation
            if _, err := syscall.GetTimeZoneInformation(&itz); err != nil {
                fmt.Println("GetTimeZoneInformation failed")
            }
            fmt.Println(strconv.Itoa(int(itz.Bias)))
    
            var newBytes []uint16
            const intBits = 4 + 4*(^uint(0)>>63)
            if intBits == 4 {
                //For 32 bit
                bytes := itz.StandardName
                for i := 0; i < len(bytes); i++ {
                    c := bytes[i]
                    if c == 0 {
                        break
                    }
                    newBytes = append(newBytes, c)
                }
            } else if intBits == 8 {
                //For 64 bit
                bytes := itz.StandardName
    
                for i := 0; ; i++ {
                    c := bytes[i]
                    if c == 0 || i == 2048 {
                        break
                    }
                    newBytes = append(newBytes, c)
                }
            }
    
            tzName := string(utf16.Decode(newBytes))
            fmt.Println("Timezone StandardName: ", tzName)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-12-21
      • 1970-01-01
      • 2010-09-22
      • 2012-08-07
      • 2017-04-18
      • 1970-01-01
      • 2011-02-21
      • 2020-09-05
      相关资源
      最近更新 更多