package time
-func ForceAndroidTzdataForTest(tzdata bool) {
- forceZipFileForTesting(false)
- if tzdata {
- zoneSources = zoneSources[:len(zoneSources)-1]
+func ForceAndroidTzdataForTest() (undo func()) {
+ allowGorootSource = false
+ origLoadFromEmbeddedTZData := loadFromEmbeddedTZData
+ loadFromEmbeddedTZData = nil
+
+ return func() {
+ allowGorootSource = true
+ loadFromEmbeddedTZData = origLoadFromEmbeddedTZData
}
}
}
var (
- ForceZipFileForTesting = forceZipFileForTesting
+ DisablePlatformSources = disablePlatformSources
+ GorootZoneSource = gorootZoneSource
ParseTimeZone = parseTimeZone
SetMono = (*Time).setMono
GetMono = (*Time).mono
}
func TestLoadLocationZipFile(t *testing.T) {
- ForceZipFileForTesting(true)
- defer ForceZipFileForTesting(false)
+ undo := DisablePlatformSources()
+ defer undo()
_, err := LoadLocation("Australia/Sydney")
if err != nil {
package time
func init() {
- // force US/Pacific for time zone tests
+ // Force US/Pacific for time zone tests.
ForceUSPacificForTesting()
}
func initTestingZone() {
- z, err := loadLocation("America/Los_Angeles", zoneSources[len(zoneSources)-1:])
+ // For hermeticity, use only tzinfo source from the test's GOROOT,
+ // not the system sources and not whatever GOROOT may happen to be
+ // set in the process's environment (if any).
+ // This test runs in GOROOT/src/time, so GOROOT is "../..",
+ // but it is theoretically possible
+ sources := []string{"../../lib/time/zoneinfo.zip"}
+ z, err := loadLocation("America/Los_Angeles", sources)
if err != nil {
panic("cannot load America/Los_Angeles for testing: " + err.Error() + "; you may want to use -tags=timetzdata")
}
localLoc = *z
}
-var OrigZoneSources = zoneSources
+var origPlatformZoneSources []string = platformZoneSources
-func forceZipFileForTesting(zipOnly bool) {
- zoneSources = make([]string, len(OrigZoneSources))
- copy(zoneSources, OrigZoneSources)
- if zipOnly {
- zoneSources = zoneSources[len(zoneSources)-1:]
+func disablePlatformSources() (undo func()) {
+ platformZoneSources = nil
+ return func() {
+ platformZoneSources = origPlatformZoneSources
}
}
}
func TestTimeIsDST(t *testing.T) {
- ForceZipFileForTesting(true)
- defer ForceZipFileForTesting(false)
+ undo := DisablePlatformSources()
+ defer undo()
tzWithDST, err := LoadLocation("Australia/Sydney")
if err != nil {
// Issue 49284: time: ParseInLocation incorrectly because of Daylight Saving Time
func TestTimeWithZoneTransition(t *testing.T) {
- ForceZipFileForTesting(true)
- defer ForceZipFileForTesting(false)
+ undo := DisablePlatformSources()
+ defer undo()
loc, err := LoadLocation("Asia/Shanghai")
if err != nil {
}
func TestEmbeddedTZData(t *testing.T) {
- time.ForceZipFileForTesting(true)
- defer time.ForceZipFileForTesting(false)
+ undo := time.DisablePlatformSources()
+ defer undo()
for _, zone := range zones {
ref, err := time.LoadLocation(zone)
firstErr = err
}
}
- if z, err := loadLocation(name, zoneSources); err == nil {
+ if z, err := loadLocation(name, platformZoneSources); err == nil {
return z, nil
} else if firstErr == nil {
firstErr = err
import (
"errors"
- "runtime"
"syscall"
)
-var zoneSources = []string{
+var platformZoneSources = []string{
"/system/usr/share/zoneinfo/tzdata",
"/data/misc/zoneinfo/current/tzdata",
- runtime.GOROOT() + "/lib/time/zoneinfo.zip",
}
func initLocal() {
loadTzinfoFromTzdata = androidLoadTzinfoFromTzdata
}
+var allowGorootSource = true
+
+func gorootZoneSource(goroot string) (string, bool) {
+ if goroot == "" || !allowGorootSource {
+ return "", false
+ }
+ return goroot + "/lib/time/zoneinfo.zip", true
+}
+
func androidLoadTzinfoFromTzdata(file, name string) ([]byte, error) {
const (
headersize = 12 + 3*4
)
func TestAndroidTzdata(t *testing.T) {
- ForceAndroidTzdataForTest(true)
- defer ForceAndroidTzdataForTest(false)
+ undo := ForceAndroidTzdataForTest()
+ defer undo()
if _, err := LoadLocation("America/Los_Angeles"); err != nil {
t.Error(err)
}
--- /dev/null
+// Copyright 2022 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.
+
+//go:build !ios && !android
+
+package time
+
+func gorootZoneSource(goroot string) (string, bool) {
+ if goroot == "" {
+ return "", false
+ }
+ return goroot + "/lib/time/zoneinfo.zip", true
+}
package time
import (
- "runtime"
"syscall"
)
-var zoneSources = []string{
- getZoneRoot() + "/zoneinfo.zip",
-}
+var platformZoneSources []string // none on iOS
-func getZoneRoot() string {
+func gorootZoneSource(goroot string) (string, bool) {
// The working directory at initialization is the root of the
// app bundle: "/private/.../bundlename.app". That's where we
// keep zoneinfo.zip for tethered iOS builds.
// For self-hosted iOS builds, the zoneinfo.zip is in GOROOT.
- roots := []string{runtime.GOROOT() + "/lib/time"}
+ var roots []string
+ if goroot != "" {
+ roots = append(roots, goroot+"/lib/time")
+ }
wd, err := syscall.Getwd()
if err == nil {
roots = append(roots, wd)
}
defer syscall.Close(fd)
if err := syscall.Fstat(fd, &st); err == nil {
- return r
+ return r + "/zoneinfo.zip", true
}
}
- return "/XXXNOEXIST"
+ return "", false
}
func initLocal() {
package time
import (
- "runtime"
"syscall/js"
)
-var zoneSources = []string{
+var platformZoneSources = []string{
"/usr/share/zoneinfo/",
"/usr/share/lib/zoneinfo/",
"/usr/lib/locale/TZ/",
- runtime.GOROOT() + "/lib/time/zoneinfo.zip",
}
func initLocal() {
package time
import (
- "runtime"
"syscall"
)
-var zoneSources = []string{
- runtime.GOROOT() + "/lib/time/zoneinfo.zip",
-}
+var platformZoneSources []string // none on Plan 9
func isSpace(r rune) bool {
return r == ' ' || r == '\t' || r == '\n'
// and parsed is returned as a Location.
func loadLocation(name string, sources []string) (z *Location, firstErr error) {
for _, source := range sources {
- var zoneData, err = loadTzinfo(name, source)
+ zoneData, err := loadTzinfo(name, source)
if err == nil {
if z, err = LoadLocationFromTZData(name, zoneData); err == nil {
return z, nil
}
}
if loadFromEmbeddedTZData != nil {
- zonedata, err := loadFromEmbeddedTZData(name)
+ zoneData, err := loadFromEmbeddedTZData(name)
if err == nil {
- if z, err = LoadLocationFromTZData(name, []byte(zonedata)); err == nil {
+ if z, err = LoadLocationFromTZData(name, []byte(zoneData)); err == nil {
+ return z, nil
+ }
+ }
+ if firstErr == nil && err != syscall.ENOENT {
+ firstErr = err
+ }
+ }
+ if source, ok := gorootZoneSource(runtime.GOROOT()); ok {
+ zoneData, err := loadTzinfo(name, source)
+ if err == nil {
+ if z, err = LoadLocationFromTZData(name, zoneData); err == nil {
return z, nil
}
}
}
func TestVersion3(t *testing.T) {
- time.ForceZipFileForTesting(true)
- defer time.ForceZipFileForTesting(false)
+ undo := time.DisablePlatformSources()
+ defer undo()
_, err := time.LoadLocation("Asia/Jerusalem")
if err != nil {
t.Fatal(err)
// transition time. To do this we explicitly check early dates in a
// couple of specific timezones.
func TestFirstZone(t *testing.T) {
- time.ForceZipFileForTesting(true)
- defer time.ForceZipFileForTesting(false)
+ undo := time.DisablePlatformSources()
+ defer undo()
const format = "Mon, 02 Jan 2006 15:04:05 -0700 (MST)"
var tests = []struct {
}
func TestLoadLocationFromTZData(t *testing.T) {
- time.ForceZipFileForTesting(true)
- defer time.ForceZipFileForTesting(false)
+ undo := time.DisablePlatformSources()
+ defer undo()
const locationName = "Asia/Jerusalem"
reference, err := time.LoadLocation(locationName)
t.Fatal(err)
}
- tzinfo, err := time.LoadTzinfo(locationName, time.OrigZoneSources[len(time.OrigZoneSources)-1])
+ gorootSource, ok := time.GorootZoneSource("../..")
+ if !ok {
+ t.Fatal("Failed to locate tzinfo source in GOROOT.")
+ }
+ tzinfo, err := time.LoadTzinfo(locationName, gorootSource)
if err != nil {
t.Fatal(err)
}
// Issue 30099.
func TestEarlyLocation(t *testing.T) {
- time.ForceZipFileForTesting(true)
- defer time.ForceZipFileForTesting(false)
+ undo := time.DisablePlatformSources()
+ defer undo()
const locName = "America/New_York"
loc, err := time.LoadLocation(locName)
package time
import (
- "runtime"
"syscall"
)
// Many systems use /usr/share/zoneinfo, Solaris 2 has
// /usr/share/lib/zoneinfo, IRIX 6 has /usr/lib/locale/TZ.
-var zoneSources = []string{
+var platformZoneSources = []string{
"/usr/share/zoneinfo/",
"/usr/share/lib/zoneinfo/",
"/usr/lib/locale/TZ/",
- runtime.GOROOT() + "/lib/time/zoneinfo.zip",
}
func initLocal() {
return
}
} else if tz != "" && tz != "UTC" {
- if z, err := loadLocation(tz, zoneSources); err == nil {
+ if z, err := loadLocation(tz, platformZoneSources); err == nil {
localLoc = *z
return
}
import (
"errors"
"internal/syscall/windows/registry"
- "runtime"
"syscall"
)
-var zoneSources = []string{
- runtime.GOROOT() + "/lib/time/zoneinfo.zip",
-}
+var platformZoneSources []string // none: Windows uses system calls instead
// TODO(rsc): Fall back to copy of zoneinfo files.