improve function SetTimeZone for package gtime (#2389)

* improve logging feature, add LevelPrint configuration for glog.Logger; add package internal/instance

* improve command build

* add default logger for panic message printing if no logger set

* up

* fix scheduler when timer triggers in less than one second for package gcron

* up

* improve function SetTimeZone for package gtime

* improve function SetTimeZone for package gtime

* improve function SetTimeZone for package gtime

* up
This commit is contained in:
John Guo 2023-01-09 14:36:42 +08:00 committed by GitHub
parent ae4f14c2e2
commit 4bb88027d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 63 additions and 53 deletions

View File

@ -12,7 +12,6 @@ package gtime
import (
"context"
"fmt"
"os"
"regexp"
"strconv"
"strings"
@ -102,28 +101,6 @@ var (
}
)
// SetTimeZone sets the time zone for current whole process.
// The parameter `zone` is an area string specifying corresponding time zone,
// eg: Asia/Shanghai.
//
// This should be called before package "time" import.
// Please refer to issue: https://github.com/golang/go/issues/34814
func SetTimeZone(zone string) (err error) {
location, err := time.LoadLocation(zone)
if err != nil {
err = gerror.Wrapf(err, `time.LoadLocation failed for zone "%s"`, zone)
return err
}
var (
envKey = "TZ"
envValue = location.String()
)
if err = os.Setenv(envKey, envValue); err != nil {
err = gerror.Wrapf(err, `set environment failed with key "%s", value "%s"`, envKey, envValue)
}
return
}
// Timestamp retrieves and returns the timestamp in seconds.
func Timestamp() int64 {
return Now().Timestamp()

View File

@ -7,21 +7,72 @@
package gtime
import (
"os"
"strings"
"sync"
"time"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
)
var (
// locationMap is time zone name to its location object.
// Time zone name is like: Asia/Shanghai.
locationMap = make(map[string]*time.Location)
// locationMu is used for concurrent safety for `locationMap`.
locationMu = sync.RWMutex{}
setTimeZoneMu sync.Mutex
setTimeZoneName string
zoneMap = make(map[string]*time.Location)
zoneMu sync.RWMutex
)
// SetTimeZone sets the time zone for current whole process.
// The parameter `zone` is an area string specifying corresponding time zone,
// eg: Asia/Shanghai.
//
// PLEASE VERY NOTE THAT:
// 1. This should be called before package "time" import.
// 2. This function should be called once.
// 3. Please refer to issue: https://github.com/golang/go/issues/34814
func SetTimeZone(zone string) (err error) {
setTimeZoneMu.Lock()
defer setTimeZoneMu.Unlock()
if setTimeZoneName != "" && !strings.EqualFold(zone, setTimeZoneName) {
return gerror.NewCodef(
gcode.CodeInvalidOperation,
`process timezone already set using "%s"`,
setTimeZoneName,
)
}
defer func() {
if err == nil {
setTimeZoneName = zone
}
}()
// Load zone info from specified name.
location, err := time.LoadLocation(zone)
if err != nil {
err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `time.LoadLocation failed for zone "%s"`, zone)
return err
}
// Update the time.Local for once.
time.Local = location
// Update the timezone environment for *nix systems.
var (
envKey = "TZ"
envValue = location.String()
)
if err = os.Setenv(envKey, envValue); err != nil {
err = gerror.WrapCodef(
gcode.CodeUnknown,
err,
`set environment failed with key "%s", value "%s"`,
envKey, envValue,
)
}
return
}
// ToLocation converts current time to specified location.
func (t *Time) ToLocation(location *time.Location) *Time {
newTime := t.Clone()
@ -39,18 +90,18 @@ func (t *Time) ToZone(zone string) (*Time, error) {
}
func (t *Time) getLocationByZoneName(name string) (location *time.Location, err error) {
locationMu.RLock()
location = locationMap[name]
locationMu.RUnlock()
zoneMu.RLock()
location = zoneMap[name]
zoneMu.RUnlock()
if location == nil {
location, err = time.LoadLocation(name)
if err != nil {
err = gerror.Wrapf(err, `time.LoadLocation failed for name "%s"`, name)
}
if location != nil {
locationMu.Lock()
locationMap[name] = location
locationMu.Unlock()
zoneMu.Lock()
zoneMap[name] = location
zoneMu.Unlock()
}
}
return

View File

@ -78,9 +78,3 @@ func Benchmark_Datetime(b *testing.B) {
gtime.Datetime()
}
}
func Benchmark_SetTimeZone(b *testing.B) {
for i := 0; i < b.N; i++ {
gtime.SetTimeZone("Asia/Shanghai")
}
}

View File

@ -17,12 +17,8 @@ import (
func ExampleSetTimeZone() {
gtime.SetTimeZone("Asia/Shanghai")
fmt.Println(gtime.Datetime())
gtime.SetTimeZone("Asia/Tokyo")
fmt.Println(gtime.Datetime())
// May Output:
// 2018-08-08 08:08:08
// 2018-08-08 09:08:08
}
func ExampleTimestamp() {

View File

@ -15,14 +15,6 @@ import (
"github.com/gogf/gf/v2/test/gtest"
)
func Test_SetTimeZone(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
t.Assert(gtime.SetTimeZone("Asia/Shanghai"), nil)
t.AssertNE(gtime.SetTimeZone("testzone"), nil)
// t.Assert(time.Local.String(), "Asia/Shanghai")
})
}
func Test_TimestampStr(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
t.AssertGT(len(gtime.TimestampMilliStr()), 0)