github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/util/tz.go (about) 1 // Copyright 2020 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package util 15 16 import ( 17 "path/filepath" 18 "strings" 19 "time" 20 21 "github.com/pingcap/log" 22 tiTypes "github.com/pingcap/tidb/pkg/types" 23 "github.com/pingcap/tidb/pkg/util/timeutil" 24 cerror "github.com/pingcap/tiflow/pkg/errors" 25 "go.uber.org/zap" 26 ) 27 28 // GetTimezone returns the timezone specified by the name 29 func GetTimezone(name string) (tz *time.Location, err error) { 30 switch strings.ToLower(name) { 31 case "", "system", "local": 32 tz, err = GetLocalTimezone() 33 err = cerror.WrapError(cerror.ErrLoadTimezone, err) 34 if err == nil { 35 log.Info("Use the timezone of the TiCDC server machine", 36 zap.String("timezoneName", name), 37 zap.String("timezone", tz.String())) 38 } 39 default: 40 tz, err = time.LoadLocation(name) 41 err = cerror.WrapError(cerror.ErrLoadTimezone, err) 42 if err == nil { 43 log.Info("Load the timezone specified by the user", 44 zap.String("timezoneName", name), 45 zap.String("timezone", tz.String())) 46 } 47 } 48 return 49 } 50 51 // GetTimezoneFromZonefile read the timezone from file 52 func GetTimezoneFromZonefile(zonefile string) (tz *time.Location, err error) { 53 // the linked path of `/etc/localtime` sample: 54 // MacOS: /var/db/timezone/zoneinfo/Asia/Shanghai 55 // Linux: /usr/share/zoneinfo/Asia/Shanghai 56 region := filepath.Base(filepath.Dir(zonefile)) 57 zone := filepath.Base(zonefile) 58 var tzName string 59 if region == "zoneinfo" { 60 tzName = zone 61 } else { 62 tzName = filepath.Join(region, zone) 63 } 64 tz, err = time.LoadLocation(tzName) 65 err = cerror.WrapError(cerror.ErrLoadTimezone, err) 66 return 67 } 68 69 // GetLocalTimezone returns the timezone in local system 70 func GetLocalTimezone() (*time.Location, error) { 71 if time.Local.String() != "Local" { 72 return time.Local, nil 73 } 74 str := timeutil.InferSystemTZ() 75 return GetTimezoneFromZonefile(str) 76 } 77 78 // GetTimeZoneName returns the timezone name in a time.Location. 79 func GetTimeZoneName(tz *time.Location) string { 80 if tz == nil { 81 return "" 82 } 83 return tz.String() 84 } 85 86 // ConvertTimezone converts the timestamp to the specified timezone 87 func ConvertTimezone(timestamp string, location string) (string, error) { 88 t, err := tiTypes.ParseTimestamp(tiTypes.StrictContext, timestamp) 89 if err != nil { 90 return "", err 91 } 92 93 var tz *time.Location 94 switch strings.ToLower(location) { 95 case "", "system", "local": 96 tz, err = GetLocalTimezone() 97 default: 98 tz, err = time.LoadLocation(location) 99 } 100 if err != nil { 101 log.Info("cannot load timezone location", 102 zap.String("location", location), zap.Error(err)) 103 return "", err 104 } 105 106 err = t.ConvertTimeZone(tz, time.UTC) 107 if err != nil { 108 return "", err 109 } 110 111 return t.String(), nil 112 }