github.com/wangyougui/gf/v2@v2.6.5/os/gtime/gtime_time_zone.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/wangyougui/gf. 6 7 package gtime 8 9 import ( 10 "os" 11 "strings" 12 "sync" 13 "time" 14 15 "github.com/wangyougui/gf/v2/errors/gcode" 16 "github.com/wangyougui/gf/v2/errors/gerror" 17 ) 18 19 var ( 20 setTimeZoneMu sync.Mutex 21 setTimeZoneName string 22 zoneMap = make(map[string]*time.Location) 23 zoneMu sync.RWMutex 24 ) 25 26 // SetTimeZone sets the time zone for current whole process. 27 // The parameter `zone` is an area string specifying corresponding time zone, 28 // eg: Asia/Shanghai. 29 // 30 // PLEASE VERY NOTE THAT: 31 // 1. This should be called before package "time" import. 32 // 2. This function should be called once. 33 // 3. Please refer to issue: https://github.com/golang/go/issues/34814 34 func SetTimeZone(zone string) (err error) { 35 setTimeZoneMu.Lock() 36 defer setTimeZoneMu.Unlock() 37 if setTimeZoneName != "" && !strings.EqualFold(zone, setTimeZoneName) { 38 return gerror.NewCodef( 39 gcode.CodeInvalidOperation, 40 `process timezone already set using "%s"`, 41 setTimeZoneName, 42 ) 43 } 44 defer func() { 45 if err == nil { 46 setTimeZoneName = zone 47 } 48 }() 49 50 // It is already set to time.Local. 51 if strings.EqualFold(zone, time.Local.String()) { 52 return 53 } 54 55 // Load zone info from specified name. 56 location, err := time.LoadLocation(zone) 57 if err != nil { 58 err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `time.LoadLocation failed for zone "%s"`, zone) 59 return err 60 } 61 62 // Update the time.Local for once. 63 time.Local = location 64 65 // Update the timezone environment for *nix systems. 66 var ( 67 envKey = "TZ" 68 envValue = location.String() 69 ) 70 if err = os.Setenv(envKey, envValue); err != nil { 71 err = gerror.WrapCodef( 72 gcode.CodeUnknown, 73 err, 74 `set environment failed with key "%s", value "%s"`, 75 envKey, envValue, 76 ) 77 } 78 return 79 } 80 81 // ToLocation converts current time to specified location. 82 func (t *Time) ToLocation(location *time.Location) *Time { 83 newTime := t.Clone() 84 newTime.Time = newTime.Time.In(location) 85 return newTime 86 } 87 88 // ToZone converts current time to specified zone like: Asia/Shanghai. 89 func (t *Time) ToZone(zone string) (*Time, error) { 90 if location, err := t.getLocationByZoneName(zone); err == nil { 91 return t.ToLocation(location), nil 92 } else { 93 return nil, err 94 } 95 } 96 97 func (t *Time) getLocationByZoneName(name string) (location *time.Location, err error) { 98 zoneMu.RLock() 99 location = zoneMap[name] 100 zoneMu.RUnlock() 101 if location == nil { 102 location, err = time.LoadLocation(name) 103 if err != nil { 104 err = gerror.Wrapf(err, `time.LoadLocation failed for name "%s"`, name) 105 } 106 if location != nil { 107 zoneMu.Lock() 108 zoneMap[name] = location 109 zoneMu.Unlock() 110 } 111 } 112 return 113 } 114 115 // Local converts the time to local timezone. 116 func (t *Time) Local() *Time { 117 newTime := t.Clone() 118 newTime.Time = newTime.Time.Local() 119 return newTime 120 }