diff options
author | Jay Lee <BusyJayLee@gmail.com> | 2020-09-18 05:49:09 +0000 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2020-09-19 05:19:50 +0000 |
commit | 58fe2cd4022c77946ce4b598cf3e30ccc8367143 (patch) | |
tree | 122147a11d9983438a795baf9a8f2f3e25db6017 /src/time | |
parent | ccf581f126e03590993454b62d2676b759120adf (diff) | |
download | go-58fe2cd4022c77946ce4b598cf3e30ccc8367143.tar.gz go-58fe2cd4022c77946ce4b598cf3e30ccc8367143.zip |
time: support colon at start of TZ value
According to POSIX, there are three formats for TZ variable. When
it refers to timezone file, it should starts with a colon. This commit
removes the colon if it exists, so that it keeps compatible with both
the spec and the old behavior.
Change-Id: I30cfeaea530d24e174de309952338cb1146694a5
GitHub-Last-Rev: 11d83d11ca2eca9d542036cf5e23559388fd323e
GitHub-Pull-Request: golang/go#27570
Reviewed-on: https://go-review.googlesource.com/c/go/+/134217
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Trust: Dmitri Shuralyov <dmitshur@golang.org>
Diffstat (limited to 'src/time')
-rw-r--r-- | src/time/zoneinfo_unix.go | 27 | ||||
-rw-r--r-- | src/time/zoneinfo_unix_test.go | 90 |
2 files changed, 112 insertions, 5 deletions
diff --git a/src/time/zoneinfo_unix.go b/src/time/zoneinfo_unix.go index c311ddc33f..80724eb30a 100644 --- a/src/time/zoneinfo_unix.go +++ b/src/time/zoneinfo_unix.go @@ -29,7 +29,9 @@ func initLocal() { // consult $TZ to find the time zone to use. // no $TZ means use the system default /etc/localtime. // $TZ="" means use UTC. - // $TZ="foo" means use /usr/share/zoneinfo/foo. + // $TZ="foo" or $TZ=":foo" if foo is an absolute path, then the file pointed + // by foo will be used to initialize timezone; otherwise, file + // /usr/share/zoneinfo/foo will be used. tz, ok := syscall.Getenv("TZ") switch { @@ -40,10 +42,25 @@ func initLocal() { localLoc.name = "Local" return } - case tz != "" && tz != "UTC": - if z, err := loadLocation(tz, zoneSources); err == nil { - localLoc = *z - return + case tz != "": + if tz[0] == ':' { + tz = tz[1:] + } + if tz != "" && tz[0] == '/' { + if z, err := loadLocation(tz, []string{""}); err == nil { + localLoc = *z + if tz == "/etc/localtime" { + localLoc.name = "Local" + } else { + localLoc.name = tz + } + return + } + } else if tz != "" && tz != "UTC" { + if z, err := loadLocation(tz, zoneSources); err == nil { + localLoc = *z + return + } } } diff --git a/src/time/zoneinfo_unix_test.go b/src/time/zoneinfo_unix_test.go new file mode 100644 index 0000000000..2d45b83d52 --- /dev/null +++ b/src/time/zoneinfo_unix_test.go @@ -0,0 +1,90 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build aix darwin,amd64 dragonfly freebsd linux,!android netbsd openbsd solaris + +package time_test + +import ( + "os" + "testing" + "time" +) + +func TestEnvTZUsage(t *testing.T) { + const env = "TZ" + tz, ok := os.LookupEnv(env) + if !ok { + defer os.Unsetenv(env) + } else { + defer os.Setenv(env, tz) + } + defer time.ForceUSPacificForTesting() + + localZoneName := "Local" + // The file may not exist. + if _, err := os.Stat("/etc/localtime"); os.IsNotExist(err) { + localZoneName = "UTC" + } + + cases := []struct { + nilFlag bool + tz string + local string + }{ + // no $TZ means use the system default /etc/localtime. + {true, "", localZoneName}, + // $TZ="" means use UTC. + {false, "", "UTC"}, + {false, ":", "UTC"}, + {false, "Asia/Shanghai", "Asia/Shanghai"}, + {false, ":Asia/Shanghai", "Asia/Shanghai"}, + {false, "/etc/localtime", localZoneName}, + {false, ":/etc/localtime", localZoneName}, + } + + for _, c := range cases { + time.ResetLocalOnceForTest() + if c.nilFlag { + os.Unsetenv(env) + } else { + os.Setenv(env, c.tz) + } + if time.Local.String() != c.local { + t.Errorf("invalid Local location name for %q: got %q want %q", c.tz, time.Local, c.local) + } + } + + time.ResetLocalOnceForTest() + // The file may not exist on Solaris 2 and IRIX 6. + path := "/usr/share/zoneinfo/Asia/Shanghai" + os.Setenv(env, path) + if _, err := os.Stat(path); os.IsNotExist(err) { + if time.Local.String() != "UTC" { + t.Errorf(`invalid path should fallback to UTC: got %q want "UTC"`, time.Local) + } + return + } + if time.Local.String() != path { + t.Errorf(`custom path should lead to path itself: got %q want %q`, time.Local, path) + } + + timeInUTC := time.Date(2009, 1, 1, 12, 0, 0, 0, time.UTC) + sameTimeInShanghai := time.Date(2009, 1, 1, 20, 0, 0, 0, time.Local) + if !timeInUTC.Equal(sameTimeInShanghai) { + t.Errorf("invalid timezone: got %q want %q", timeInUTC, sameTimeInShanghai) + } + + time.ResetLocalOnceForTest() + os.Setenv(env, ":"+path) + if time.Local.String() != path { + t.Errorf(`custom path should lead to path itself: got %q want %q`, time.Local, path) + } + + time.ResetLocalOnceForTest() + os.Setenv(env, path[:len(path)-1]) + if time.Local.String() != "UTC" { + t.Errorf(`invalid path should fallback to UTC: got %q want "UTC"`, time.Local) + } +} |