Source file src/time/zoneinfo_test.go

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package time_test
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"internal/testenv"
    11  	"os"
    12  	"reflect"
    13  	"testing"
    14  	"time"
    15  )
    16  
    17  func init() {
    18  	if time.ZoneinfoForTesting() != nil {
    19  		panic(fmt.Errorf("zoneinfo initialized before first LoadLocation"))
    20  	}
    21  }
    22  
    23  func TestEnvVarUsage(t *testing.T) {
    24  	time.ResetZoneinfoForTesting()
    25  
    26  	const testZoneinfo = "foo.zip"
    27  	const env = "ZONEINFO"
    28  
    29  	t.Setenv(env, testZoneinfo)
    30  
    31  	// Result isn't important, we're testing the side effect of this command
    32  	time.LoadLocation("Asia/Jerusalem")
    33  	defer time.ResetZoneinfoForTesting()
    34  
    35  	if zoneinfo := time.ZoneinfoForTesting(); testZoneinfo != *zoneinfo {
    36  		t.Errorf("zoneinfo does not match env variable: got %q want %q", *zoneinfo, testZoneinfo)
    37  	}
    38  }
    39  
    40  func TestBadLocationErrMsg(t *testing.T) {
    41  	time.ResetZoneinfoForTesting()
    42  	loc := "Asia/SomethingNotExist"
    43  	want := errors.New("unknown time zone " + loc)
    44  	_, err := time.LoadLocation(loc)
    45  	if err.Error() != want.Error() {
    46  		t.Errorf("LoadLocation(%q) error = %v; want %v", loc, err, want)
    47  	}
    48  }
    49  
    50  func TestLoadLocationValidatesNames(t *testing.T) {
    51  	time.ResetZoneinfoForTesting()
    52  	const env = "ZONEINFO"
    53  	t.Setenv(env, "")
    54  
    55  	bad := []string{
    56  		"/usr/foo/Foo",
    57  		"\\UNC\foo",
    58  		"..",
    59  		"a..",
    60  	}
    61  	for _, v := range bad {
    62  		_, err := time.LoadLocation(v)
    63  		if err != time.ErrLocation {
    64  			t.Errorf("LoadLocation(%q) error = %v; want ErrLocation", v, err)
    65  		}
    66  	}
    67  }
    68  
    69  func TestVersion3(t *testing.T) {
    70  	undo := time.DisablePlatformSources()
    71  	defer undo()
    72  	_, err := time.LoadLocation("Asia/Jerusalem")
    73  	if err != nil {
    74  		t.Fatal(err)
    75  	}
    76  }
    77  
    78  // Test that we get the correct results for times before the first
    79  // transition time. To do this we explicitly check early dates in a
    80  // couple of specific timezones.
    81  func TestFirstZone(t *testing.T) {
    82  	undo := time.DisablePlatformSources()
    83  	defer undo()
    84  
    85  	const format = "Mon, 02 Jan 2006 15:04:05 -0700 (MST)"
    86  	var tests = []struct {
    87  		zone  string
    88  		unix  int64
    89  		want1 string
    90  		want2 string
    91  	}{
    92  		{
    93  			"PST8PDT",
    94  			-1633269601,
    95  			"Sun, 31 Mar 1918 01:59:59 -0800 (PST)",
    96  			"Sun, 31 Mar 1918 03:00:00 -0700 (PDT)",
    97  		},
    98  		{
    99  			"Pacific/Fakaofo",
   100  			1325242799,
   101  			"Thu, 29 Dec 2011 23:59:59 -1100 (-11)",
   102  			"Sat, 31 Dec 2011 00:00:00 +1300 (+13)",
   103  		},
   104  	}
   105  
   106  	for _, test := range tests {
   107  		z, err := time.LoadLocation(test.zone)
   108  		if err != nil {
   109  			t.Fatal(err)
   110  		}
   111  		s := time.Unix(test.unix, 0).In(z).Format(format)
   112  		if s != test.want1 {
   113  			t.Errorf("for %s %d got %q want %q", test.zone, test.unix, s, test.want1)
   114  		}
   115  		s = time.Unix(test.unix+1, 0).In(z).Format(format)
   116  		if s != test.want2 {
   117  			t.Errorf("for %s %d got %q want %q", test.zone, test.unix, s, test.want2)
   118  		}
   119  	}
   120  }
   121  
   122  func TestLocationNames(t *testing.T) {
   123  	if time.Local.String() != "Local" {
   124  		t.Errorf(`invalid Local location name: got %q want "Local"`, time.Local)
   125  	}
   126  	if time.UTC.String() != "UTC" {
   127  		t.Errorf(`invalid UTC location name: got %q want "UTC"`, time.UTC)
   128  	}
   129  }
   130  
   131  func TestLoadLocationFromTZData(t *testing.T) {
   132  	undo := time.DisablePlatformSources()
   133  	defer undo()
   134  
   135  	const locationName = "Asia/Jerusalem"
   136  	reference, err := time.LoadLocation(locationName)
   137  	if err != nil {
   138  		t.Fatal(err)
   139  	}
   140  
   141  	gorootSource, ok := time.GorootZoneSource(testenv.GOROOT(t))
   142  	if !ok {
   143  		t.Fatal("Failed to locate tzinfo source in GOROOT.")
   144  	}
   145  	tzinfo, err := time.LoadTzinfo(locationName, gorootSource)
   146  	if err != nil {
   147  		t.Fatal(err)
   148  	}
   149  	sample, err := time.LoadLocationFromTZData(locationName, tzinfo)
   150  	if err != nil {
   151  		t.Fatal(err)
   152  	}
   153  
   154  	if !reflect.DeepEqual(reference, sample) {
   155  		t.Errorf("return values of LoadLocationFromTZData and LoadLocation don't match")
   156  	}
   157  }
   158  
   159  // Issue 30099.
   160  func TestEarlyLocation(t *testing.T) {
   161  	undo := time.DisablePlatformSources()
   162  	defer undo()
   163  
   164  	const locName = "America/New_York"
   165  	loc, err := time.LoadLocation(locName)
   166  	if err != nil {
   167  		t.Fatal(err)
   168  	}
   169  
   170  	d := time.Date(1900, time.January, 1, 0, 0, 0, 0, loc)
   171  	tzName, tzOffset := d.Zone()
   172  	if want := "EST"; tzName != want {
   173  		t.Errorf("Zone name == %s, want %s", tzName, want)
   174  	}
   175  	if want := -18000; tzOffset != want {
   176  		t.Errorf("Zone offset == %d, want %d", tzOffset, want)
   177  	}
   178  }
   179  
   180  func TestMalformedTZData(t *testing.T) {
   181  	// The goal here is just that malformed tzdata results in an error, not a panic.
   182  	issue29437 := "TZif\x00000000000000000\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0000"
   183  	_, err := time.LoadLocationFromTZData("abc", []byte(issue29437))
   184  	if err == nil {
   185  		t.Error("expected error, got none")
   186  	}
   187  }
   188  
   189  var slimTests = []struct {
   190  	zoneName   string
   191  	fileName   string
   192  	date       func(*time.Location) time.Time
   193  	wantName   string
   194  	wantOffset int
   195  }{
   196  	{
   197  		// 2020b slim tzdata for Europe/Berlin.
   198  		zoneName:   "Europe/Berlin",
   199  		fileName:   "2020b_Europe_Berlin",
   200  		date:       func(loc *time.Location) time.Time { return time.Date(2020, time.October, 29, 15, 30, 0, 0, loc) },
   201  		wantName:   "CET",
   202  		wantOffset: 3600,
   203  	},
   204  	{
   205  		// 2021a slim tzdata for America/Nuuk.
   206  		zoneName:   "America/Nuuk",
   207  		fileName:   "2021a_America_Nuuk",
   208  		date:       func(loc *time.Location) time.Time { return time.Date(2020, time.October, 29, 15, 30, 0, 0, loc) },
   209  		wantName:   "-03",
   210  		wantOffset: -10800,
   211  	},
   212  	{
   213  		// 2021a slim tzdata for Asia/Gaza.
   214  		zoneName:   "Asia/Gaza",
   215  		fileName:   "2021a_Asia_Gaza",
   216  		date:       func(loc *time.Location) time.Time { return time.Date(2020, time.October, 29, 15, 30, 0, 0, loc) },
   217  		wantName:   "EET",
   218  		wantOffset: 7200,
   219  	},
   220  	{
   221  		// 2021a slim tzdata for Europe/Dublin.
   222  		zoneName:   "Europe/Dublin",
   223  		fileName:   "2021a_Europe_Dublin",
   224  		date:       func(loc *time.Location) time.Time { return time.Date(2021, time.April, 2, 11, 12, 13, 0, loc) },
   225  		wantName:   "IST",
   226  		wantOffset: 3600,
   227  	},
   228  }
   229  
   230  func TestLoadLocationFromTZDataSlim(t *testing.T) {
   231  	for _, test := range slimTests {
   232  		tzData, err := os.ReadFile("testdata/" + test.fileName)
   233  		if err != nil {
   234  			t.Error(err)
   235  			continue
   236  		}
   237  		reference, err := time.LoadLocationFromTZData(test.zoneName, tzData)
   238  		if err != nil {
   239  			t.Error(err)
   240  			continue
   241  		}
   242  
   243  		d := test.date(reference)
   244  		tzName, tzOffset := d.Zone()
   245  		if tzName != test.wantName {
   246  			t.Errorf("Zone name == %s, want %s", tzName, test.wantName)
   247  		}
   248  		if tzOffset != test.wantOffset {
   249  			t.Errorf("Zone offset == %d, want %d", tzOffset, test.wantOffset)
   250  		}
   251  	}
   252  }
   253  
   254  func TestTzset(t *testing.T) {
   255  	for _, test := range []struct {
   256  		inStr string
   257  		inEnd int64
   258  		inSec int64
   259  		name  string
   260  		off   int
   261  		start int64
   262  		end   int64
   263  		isDST bool
   264  		ok    bool
   265  	}{
   266  		{"", 0, 0, "", 0, 0, 0, false, false},
   267  		{"PST8PDT,M3.2.0,M11.1.0", 0, 2159200800, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true, true},
   268  		{"PST8PDT,M3.2.0,M11.1.0", 0, 2152173599, "PST", -8 * 60 * 60, 2145916800, 2152173600, false, true},
   269  		{"PST8PDT,M3.2.0,M11.1.0", 0, 2152173600, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true, true},
   270  		{"PST8PDT,M3.2.0,M11.1.0", 0, 2152173601, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true, true},
   271  		{"PST8PDT,M3.2.0,M11.1.0", 0, 2172733199, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true, true},
   272  		{"PST8PDT,M3.2.0,M11.1.0", 0, 2172733200, "PST", -8 * 60 * 60, 2172733200, 2177452800, false, true},
   273  		{"PST8PDT,M3.2.0,M11.1.0", 0, 2172733201, "PST", -8 * 60 * 60, 2172733200, 2177452800, false, true},
   274  		{"KST-9", 592333200, 1677246697, "KST", 9 * 60 * 60, 592333200, 1<<63 - 1, false, true},
   275  	} {
   276  		name, off, start, end, isDST, ok := time.Tzset(test.inStr, test.inEnd, test.inSec)
   277  		if name != test.name || off != test.off || start != test.start || end != test.end || isDST != test.isDST || ok != test.ok {
   278  			t.Errorf("tzset(%q, %d, %d) = %q, %d, %d, %d, %t, %t, want %q, %d, %d, %d, %t, %t", test.inStr, test.inEnd, test.inSec, name, off, start, end, isDST, ok, test.name, test.off, test.start, test.end, test.isDST, test.ok)
   279  		}
   280  	}
   281  }
   282  
   283  func TestTzsetName(t *testing.T) {
   284  	for _, test := range []struct {
   285  		in   string
   286  		name string
   287  		out  string
   288  		ok   bool
   289  	}{
   290  		{"", "", "", false},
   291  		{"X", "", "", false},
   292  		{"PST", "PST", "", true},
   293  		{"PST8PDT", "PST", "8PDT", true},
   294  		{"PST-08", "PST", "-08", true},
   295  		{"<A+B>+08", "A+B", "+08", true},
   296  	} {
   297  		name, out, ok := time.TzsetName(test.in)
   298  		if name != test.name || out != test.out || ok != test.ok {
   299  			t.Errorf("tzsetName(%q) = %q, %q, %t, want %q, %q, %t", test.in, name, out, ok, test.name, test.out, test.ok)
   300  		}
   301  	}
   302  }
   303  
   304  func TestTzsetOffset(t *testing.T) {
   305  	for _, test := range []struct {
   306  		in  string
   307  		off int
   308  		out string
   309  		ok  bool
   310  	}{
   311  		{"", 0, "", false},
   312  		{"X", 0, "", false},
   313  		{"+", 0, "", false},
   314  		{"+08", 8 * 60 * 60, "", true},
   315  		{"-01:02:03", -1*60*60 - 2*60 - 3, "", true},
   316  		{"01", 1 * 60 * 60, "", true},
   317  		{"100", 100 * 60 * 60, "", true},
   318  		{"1000", 0, "", false},
   319  		{"8PDT", 8 * 60 * 60, "PDT", true},
   320  	} {
   321  		off, out, ok := time.TzsetOffset(test.in)
   322  		if off != test.off || out != test.out || ok != test.ok {
   323  			t.Errorf("tzsetName(%q) = %d, %q, %t, want %d, %q, %t", test.in, off, out, ok, test.off, test.out, test.ok)
   324  		}
   325  	}
   326  }
   327  
   328  func TestTzsetRule(t *testing.T) {
   329  	for _, test := range []struct {
   330  		in  string
   331  		r   time.Rule
   332  		out string
   333  		ok  bool
   334  	}{
   335  		{"", time.Rule{}, "", false},
   336  		{"X", time.Rule{}, "", false},
   337  		{"J10", time.Rule{Kind: time.RuleJulian, Day: 10, Time: 2 * 60 * 60}, "", true},
   338  		{"20", time.Rule{Kind: time.RuleDOY, Day: 20, Time: 2 * 60 * 60}, "", true},
   339  		{"M1.2.3", time.Rule{Kind: time.RuleMonthWeekDay, Mon: 1, Week: 2, Day: 3, Time: 2 * 60 * 60}, "", true},
   340  		{"30/03:00:00", time.Rule{Kind: time.RuleDOY, Day: 30, Time: 3 * 60 * 60}, "", true},
   341  		{"M4.5.6/03:00:00", time.Rule{Kind: time.RuleMonthWeekDay, Mon: 4, Week: 5, Day: 6, Time: 3 * 60 * 60}, "", true},
   342  		{"M4.5.7/03:00:00", time.Rule{}, "", false},
   343  		{"M4.5.6/-04", time.Rule{Kind: time.RuleMonthWeekDay, Mon: 4, Week: 5, Day: 6, Time: -4 * 60 * 60}, "", true},
   344  	} {
   345  		r, out, ok := time.TzsetRule(test.in)
   346  		if r != test.r || out != test.out || ok != test.ok {
   347  			t.Errorf("tzsetName(%q) = %#v, %q, %t, want %#v, %q, %t", test.in, r, out, ok, test.r, test.out, test.ok)
   348  		}
   349  	}
   350  }
   351  

View as plain text