Zone method from time package doesn't return updated timezone if timezone is changed during process execution

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

Zone method from time package doesn't return updated timezone if timezone is changed during process execution

问题

我已经为您翻译了以下的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("时区", z)
	}
}

希望对您有所帮助!

英文:

I have written below a simple Go code to get the system timezone. It works fine and returns the system's current timezone. The issue is if I change the timezone in-between process execution then it doesn't return the updated timezone. It returns only the old timezone.

package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

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

答案1

得分: 3

如果你查看一下time包的源代码,你会发现本地位置(local Location)在应用程序启动时只设置一次,通过sync.Once来实现(更准确地说,是在第一次调用.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是与平台相关的,因为不同的平台处理时区的方式不同;例如,在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偏移量。

英文:

if you have a look at the source code of the time package, you can find that the local Location is set once at the start of the application, by a sync.Once (or more precisely: when the tz information is obtained by a call to .get() for the first time):

// 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 &amp;utcLoc
	}
	if l == &amp;localLoc {
		localOnce.Do(initLocal)
	}
	return l
}

Now, initLocal is platform-dependent since different platforms handle time zones differently; for example for Windows you have:

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

From here on, you could work your way through the source code to get an idea how you can implement this for your application. For example on Windows, you could get the UTC offset in minutes by calling the Bias and DaylightBias fields of the syscall.Timezoneinformation struct.

答案2

得分: 0

感谢,@MrFuppes

通过从Golang调用Win32 API,问题得到解决。以下是代码片段。

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

希望对你有帮助!

英文:

Thanks, @MrFuppes

The issue got resolved by calling Win32 API from Golang. Below is the code snippet.

package main
import (
&quot;fmt&quot;
&quot;time&quot;
&quot;syscall&quot;
&quot;strconv&quot;
&quot;unicode/utf16&quot;
)
func main() {
for index := 0; index &lt; 10; index++ {
now := time.Now()
timeZone, _ := now.Zone()
fmt.Println(&quot;timezone&quot;, timeZone)
var itz syscall.Timezoneinformation
if _, err := syscall.GetTimeZoneInformation(&amp;itz); err != nil {
fmt.Println(&quot;GetTimeZoneInformation failed&quot;)
}
fmt.Println(strconv.Itoa(int(itz.Bias)))
var newBytes []uint16
const intBits = 4 + 4*(^uint(0)&gt;&gt;63)
if intBits == 4 {
//For 32 bit
bytes := itz.StandardName
for i := 0; i &lt; 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(&quot;Timezone StandardName: &quot;, tzName)
}
}

huangapple
  • 本文由 发表于 2021年7月9日 14:58:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/68312495.html
匿名

发表评论

匿名网友

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

确定