1// Copyright 2009 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
5package time_test
6
7import (
8	"fmt"
9	"strconv"
10	"strings"
11	"testing"
12	"testing/quick"
13	. "time"
14)
15
16var nextStdChunkTests = []string{
17	"(2006)-(01)-(02)T(15):(04):(05)(Z07:00)",
18	"(2006)-(01)-(02) (002) (15):(04):(05)",
19	"(2006)-(01) (002) (15):(04):(05)",
20	"(2006)-(002) (15):(04):(05)",
21	"(2006)(002)(01) (15):(04):(05)",
22	"(2006)(002)(04) (15):(04):(05)",
23}
24
25func TestNextStdChunk(t *testing.T) {
26	// Most bugs in Parse or Format boil down to problems with
27	// the exact detection of format chunk boundaries in the
28	// helper function nextStdChunk (here called as NextStdChunk).
29	// This test checks nextStdChunk's behavior directly,
30	// instead of needing to test it only indirectly through Parse/Format.
31
32	// markChunks returns format with each detected
33	// 'format chunk' parenthesized.
34	// For example showChunks("2006-01-02") == "(2006)-(01)-(02)".
35	markChunks := func(format string) string {
36		// Note that NextStdChunk and StdChunkNames
37		// are not part of time's public API.
38		// They are exported in export_test for this test.
39		out := ""
40		for s := format; s != ""; {
41			prefix, std, suffix := NextStdChunk(s)
42			out += prefix
43			if std > 0 {
44				out += "(" + StdChunkNames[std] + ")"
45			}
46			s = suffix
47		}
48		return out
49	}
50
51	noParens := func(r rune) rune {
52		if r == '(' || r == ')' {
53			return -1
54		}
55		return r
56	}
57
58	for _, marked := range nextStdChunkTests {
59		// marked is an expected output from markChunks.
60		// If we delete the parens and pass it through markChunks,
61		// we should get the original back.
62		format := strings.Map(noParens, marked)
63		out := markChunks(format)
64		if out != marked {
65			t.Errorf("nextStdChunk parses %q as %q, want %q", format, out, marked)
66		}
67	}
68}
69
70type TimeFormatTest struct {
71	time           Time
72	formattedValue string
73}
74
75var rfc3339Formats = []TimeFormatTest{
76	{Date(2008, 9, 17, 20, 4, 26, 0, UTC), "2008-09-17T20:04:26Z"},
77	{Date(1994, 9, 17, 20, 4, 26, 0, FixedZone("EST", -18000)), "1994-09-17T20:04:26-05:00"},
78	{Date(2000, 12, 26, 1, 15, 6, 0, FixedZone("OTO", 15600)), "2000-12-26T01:15:06+04:20"},
79}
80
81func TestRFC3339Conversion(t *testing.T) {
82	for _, f := range rfc3339Formats {
83		if f.time.Format(RFC3339) != f.formattedValue {
84			t.Error("RFC3339:")
85			t.Errorf("  want=%+v", f.formattedValue)
86			t.Errorf("  have=%+v", f.time.Format(RFC3339))
87		}
88	}
89}
90
91type FormatTest struct {
92	name   string
93	format string
94	result string
95}
96
97var formatTests = []FormatTest{
98	{"ANSIC", ANSIC, "Wed Feb  4 21:00:57 2009"},
99	{"UnixDate", UnixDate, "Wed Feb  4 21:00:57 PST 2009"},
100	{"RubyDate", RubyDate, "Wed Feb 04 21:00:57 -0800 2009"},
101	{"RFC822", RFC822, "04 Feb 09 21:00 PST"},
102	{"RFC850", RFC850, "Wednesday, 04-Feb-09 21:00:57 PST"},
103	{"RFC1123", RFC1123, "Wed, 04 Feb 2009 21:00:57 PST"},
104	{"RFC1123Z", RFC1123Z, "Wed, 04 Feb 2009 21:00:57 -0800"},
105	{"RFC3339", RFC3339, "2009-02-04T21:00:57-08:00"},
106	{"RFC3339Nano", RFC3339Nano, "2009-02-04T21:00:57.0123456-08:00"},
107	{"Kitchen", Kitchen, "9:00PM"},
108	{"am/pm", "3pm", "9pm"},
109	{"AM/PM", "3PM", "9PM"},
110	{"two-digit year", "06 01 02", "09 02 04"},
111	// Three-letter months and days must not be followed by lower-case letter.
112	{"Janet", "Hi Janet, the Month is January", "Hi Janet, the Month is February"},
113	// Time stamps, Fractional seconds.
114	{"Stamp", Stamp, "Feb  4 21:00:57"},
115	{"StampMilli", StampMilli, "Feb  4 21:00:57.012"},
116	{"StampMicro", StampMicro, "Feb  4 21:00:57.012345"},
117	{"StampNano", StampNano, "Feb  4 21:00:57.012345600"},
118	{"YearDay", "Jan  2 002 __2 2", "Feb  4 035  35 4"},
119}
120
121func TestFormat(t *testing.T) {
122	// The numeric time represents Thu Feb  4 21:00:57.012345600 PST 2009
123	time := Unix(0, 1233810057012345600)
124	for _, test := range formatTests {
125		result := time.Format(test.format)
126		if result != test.result {
127			t.Errorf("%s expected %q got %q", test.name, test.result, result)
128		}
129	}
130}
131
132// issue 12440.
133func TestFormatSingleDigits(t *testing.T) {
134	time := Date(2001, 2, 3, 4, 5, 6, 700000000, UTC)
135	test := FormatTest{"single digit format", "3:4:5", "4:5:6"}
136	result := time.Format(test.format)
137	if result != test.result {
138		t.Errorf("%s expected %q got %q", test.name, test.result, result)
139	}
140}
141
142func TestFormatShortYear(t *testing.T) {
143	years := []int{
144		-100001, -100000, -99999,
145		-10001, -10000, -9999,
146		-1001, -1000, -999,
147		-101, -100, -99,
148		-11, -10, -9,
149		-1, 0, 1,
150		9, 10, 11,
151		99, 100, 101,
152		999, 1000, 1001,
153		9999, 10000, 10001,
154		99999, 100000, 100001,
155	}
156
157	for _, y := range years {
158		time := Date(y, January, 1, 0, 0, 0, 0, UTC)
159		result := time.Format("2006.01.02")
160		var want string
161		if y < 0 {
162			// The 4 in %04d counts the - sign, so print -y instead
163			// and introduce our own - sign.
164			want = fmt.Sprintf("-%04d.%02d.%02d", -y, 1, 1)
165		} else {
166			want = fmt.Sprintf("%04d.%02d.%02d", y, 1, 1)
167		}
168		if result != want {
169			t.Errorf("(jan 1 %d).Format(\"2006.01.02\") = %q, want %q", y, result, want)
170		}
171	}
172}
173
174type ParseTest struct {
175	name       string
176	format     string
177	value      string
178	hasTZ      bool // contains a time zone
179	hasWD      bool // contains a weekday
180	yearSign   int  // sign of year, -1 indicates the year is not present in the format
181	fracDigits int  // number of digits of fractional second
182}
183
184var parseTests = []ParseTest{
185	{"ANSIC", ANSIC, "Thu Feb  4 21:00:57 2010", false, true, 1, 0},
186	{"UnixDate", UnixDate, "Thu Feb  4 21:00:57 PST 2010", true, true, 1, 0},
187	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
188	{"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1, 0},
189	{"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1, 0},
190	{"RFC1123", RFC1123, "Thu, 04 Feb 2010 22:00:57 PDT", true, true, 1, 0},
191	{"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57 -0800", true, true, 1, 0},
192	{"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1, 0},
193	{"custom: \"2006-01-02 15:04:05-07\"", "2006-01-02 15:04:05-07", "2010-02-04 21:00:57-08", true, false, 1, 0},
194	// Optional fractional seconds.
195	{"ANSIC", ANSIC, "Thu Feb  4 21:00:57.0 2010", false, true, 1, 1},
196	{"UnixDate", UnixDate, "Thu Feb  4 21:00:57.01 PST 2010", true, true, 1, 2},
197	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57.012 -0800 2010", true, true, 1, 3},
198	{"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57.0123 PST", true, true, 1, 4},
199	{"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57.01234 PST", true, true, 1, 5},
200	{"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57.01234 -0800", true, true, 1, 5},
201	{"RFC3339", RFC3339, "2010-02-04T21:00:57.012345678-08:00", true, false, 1, 9},
202	{"custom: \"2006-01-02 15:04:05\"", "2006-01-02 15:04:05", "2010-02-04 21:00:57.0", false, false, 1, 0},
203	// Amount of white space should not matter.
204	{"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
205	{"ANSIC", ANSIC, "Thu      Feb     4     21:00:57     2010", false, true, 1, 0},
206	// Case should not matter
207	{"ANSIC", ANSIC, "THU FEB 4 21:00:57 2010", false, true, 1, 0},
208	{"ANSIC", ANSIC, "thu feb 4 21:00:57 2010", false, true, 1, 0},
209	// Fractional seconds.
210	{"millisecond", "Mon Jan _2 15:04:05.000 2006", "Thu Feb  4 21:00:57.012 2010", false, true, 1, 3},
211	{"microsecond", "Mon Jan _2 15:04:05.000000 2006", "Thu Feb  4 21:00:57.012345 2010", false, true, 1, 6},
212	{"nanosecond", "Mon Jan _2 15:04:05.000000000 2006", "Thu Feb  4 21:00:57.012345678 2010", false, true, 1, 9},
213	// Leading zeros in other places should not be taken as fractional seconds.
214	{"zero1", "2006.01.02.15.04.05.0", "2010.02.04.21.00.57.0", false, false, 1, 1},
215	{"zero2", "2006.01.02.15.04.05.00", "2010.02.04.21.00.57.01", false, false, 1, 2},
216	// Month and day names only match when not followed by a lower-case letter.
217	{"Janet", "Hi Janet, the Month is January: Jan _2 15:04:05 2006", "Hi Janet, the Month is February: Feb  4 21:00:57 2010", false, true, 1, 0},
218
219	// GMT with offset.
220	{"GMT-8", UnixDate, "Fri Feb  5 05:00:57 GMT-8 2010", true, true, 1, 0},
221
222	// Accept any number of fractional second digits (including none) for .999...
223	// In Go 1, .999... was completely ignored in the format, meaning the first two
224	// cases would succeed, but the next four would not. Go 1.1 accepts all six.
225	{"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
226	{"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
227	{"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
228	{"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
229	{"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
230	{"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
231
232	// issue 4502.
233	{"", StampNano, "Feb  4 21:00:57.012345678", false, false, -1, 9},
234	{"", "Jan _2 15:04:05.999", "Feb  4 21:00:57.012300000", false, false, -1, 4},
235	{"", "Jan _2 15:04:05.999", "Feb  4 21:00:57.012345678", false, false, -1, 9},
236	{"", "Jan _2 15:04:05.999999999", "Feb  4 21:00:57.0123", false, false, -1, 4},
237	{"", "Jan _2 15:04:05.999999999", "Feb  4 21:00:57.012345678", false, false, -1, 9},
238
239	// Day of year.
240	{"", "2006-01-02 002 15:04:05", "2010-02-04 035 21:00:57", false, false, 1, 0},
241	{"", "2006-01 002 15:04:05", "2010-02 035 21:00:57", false, false, 1, 0},
242	{"", "2006-002 15:04:05", "2010-035 21:00:57", false, false, 1, 0},
243	{"", "200600201 15:04:05", "201003502 21:00:57", false, false, 1, 0},
244	{"", "200600204 15:04:05", "201003504 21:00:57", false, false, 1, 0},
245}
246
247func TestParse(t *testing.T) {
248	for _, test := range parseTests {
249		time, err := Parse(test.format, test.value)
250		if err != nil {
251			t.Errorf("%s error: %v", test.name, err)
252		} else {
253			checkTime(time, &test, t)
254		}
255	}
256}
257
258// All parsed with ANSIC.
259var dayOutOfRangeTests = []struct {
260	date string
261	ok   bool
262}{
263	{"Thu Jan 99 21:00:57 2010", false},
264	{"Thu Jan 31 21:00:57 2010", true},
265	{"Thu Jan 32 21:00:57 2010", false},
266	{"Thu Feb 28 21:00:57 2012", true},
267	{"Thu Feb 29 21:00:57 2012", true},
268	{"Thu Feb 29 21:00:57 2010", false},
269	{"Thu Mar 31 21:00:57 2010", true},
270	{"Thu Mar 32 21:00:57 2010", false},
271	{"Thu Apr 30 21:00:57 2010", true},
272	{"Thu Apr 31 21:00:57 2010", false},
273	{"Thu May 31 21:00:57 2010", true},
274	{"Thu May 32 21:00:57 2010", false},
275	{"Thu Jun 30 21:00:57 2010", true},
276	{"Thu Jun 31 21:00:57 2010", false},
277	{"Thu Jul 31 21:00:57 2010", true},
278	{"Thu Jul 32 21:00:57 2010", false},
279	{"Thu Aug 31 21:00:57 2010", true},
280	{"Thu Aug 32 21:00:57 2010", false},
281	{"Thu Sep 30 21:00:57 2010", true},
282	{"Thu Sep 31 21:00:57 2010", false},
283	{"Thu Oct 31 21:00:57 2010", true},
284	{"Thu Oct 32 21:00:57 2010", false},
285	{"Thu Nov 30 21:00:57 2010", true},
286	{"Thu Nov 31 21:00:57 2010", false},
287	{"Thu Dec 31 21:00:57 2010", true},
288	{"Thu Dec 32 21:00:57 2010", false},
289	{"Thu Dec 00 21:00:57 2010", false},
290}
291
292func TestParseDayOutOfRange(t *testing.T) {
293	for _, test := range dayOutOfRangeTests {
294		_, err := Parse(ANSIC, test.date)
295		switch {
296		case test.ok && err == nil:
297			// OK
298		case !test.ok && err != nil:
299			if !strings.Contains(err.Error(), "day out of range") {
300				t.Errorf("%q: expected 'day' error, got %v", test.date, err)
301			}
302		case test.ok && err != nil:
303			t.Errorf("%q: unexpected error: %v", test.date, err)
304		case !test.ok && err == nil:
305			t.Errorf("%q: expected 'day' error, got none", test.date)
306		}
307	}
308}
309
310// TestParseInLocation checks that the Parse and ParseInLocation
311// functions do not get confused by the fact that AST (Arabia Standard
312// Time) and AST (Atlantic Standard Time) are different time zones,
313// even though they have the same abbreviation.
314//
315// ICANN has been slowly phasing out invented abbreviation in favor of
316// numeric time zones (for example, the Asia/Baghdad time zone
317// abbreviation got changed from AST to +03 in the 2017a tzdata
318// release); but we still want to make sure that the time package does
319// not get confused on systems with slightly older tzdata packages.
320func TestParseInLocation(t *testing.T) {
321
322	baghdad, err := LoadLocation("Asia/Baghdad")
323	if err != nil {
324		t.Fatal(err)
325	}
326
327	var t1, t2 Time
328
329	t1, err = ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", baghdad)
330	if err != nil {
331		t.Fatal(err)
332	}
333
334	_, offset := t1.Zone()
335
336	// A zero offset means that ParseInLocation did not recognize the
337	// 'AST' abbreviation as matching the current location (Baghdad,
338	// where we'd expect a +03 hrs offset); likely because we're using
339	// a recent tzdata release (2017a or newer).
340	// If it happens, skip the Baghdad test.
341	if offset != 0 {
342		t2 = Date(2013, February, 1, 00, 00, 00, 0, baghdad)
343		if t1 != t2 {
344			t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad) = %v, want %v", t1, t2)
345		}
346		if offset != 3*60*60 {
347			t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad).Zone = _, %d, want _, %d", offset, 3*60*60)
348		}
349	}
350
351	blancSablon, err := LoadLocation("America/Blanc-Sablon")
352	if err != nil {
353		t.Fatal(err)
354	}
355
356	// In this case 'AST' means 'Atlantic Standard Time', and we
357	// expect the abbreviation to correctly match the american
358	// location.
359	t1, err = ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", blancSablon)
360	if err != nil {
361		t.Fatal(err)
362	}
363	t2 = Date(2013, February, 1, 00, 00, 00, 0, blancSablon)
364	if t1 != t2 {
365		t.Fatalf("ParseInLocation(Feb 01 2013 AST, Blanc-Sablon) = %v, want %v", t1, t2)
366	}
367	_, offset = t1.Zone()
368	if offset != -4*60*60 {
369		t.Fatalf("ParseInLocation(Feb 01 2013 AST, Blanc-Sablon).Zone = _, %d, want _, %d", offset, -4*60*60)
370	}
371}
372
373func TestLoadLocationZipFile(t *testing.T) {
374	t.Skip("gccgo does not use the zip file")
375
376	ForceZipFileForTesting(true)
377	defer ForceZipFileForTesting(false)
378
379	_, err := LoadLocation("Australia/Sydney")
380	if err != nil {
381		t.Fatal(err)
382	}
383}
384
385var rubyTests = []ParseTest{
386	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
387	// Ignore the time zone in the test. If it parses, it'll be OK.
388	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1, 0},
389	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1, 0},
390	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1, 0},
391}
392
393// Problematic time zone format needs special tests.
394func TestRubyParse(t *testing.T) {
395	for _, test := range rubyTests {
396		time, err := Parse(test.format, test.value)
397		if err != nil {
398			t.Errorf("%s error: %v", test.name, err)
399		} else {
400			checkTime(time, &test, t)
401		}
402	}
403}
404
405func checkTime(time Time, test *ParseTest, t *testing.T) {
406	// The time should be Thu Feb  4 21:00:57 PST 2010
407	if test.yearSign >= 0 && test.yearSign*time.Year() != 2010 {
408		t.Errorf("%s: bad year: %d not %d", test.name, time.Year(), 2010)
409	}
410	if time.Month() != February {
411		t.Errorf("%s: bad month: %s not %s", test.name, time.Month(), February)
412	}
413	if time.Day() != 4 {
414		t.Errorf("%s: bad day: %d not %d", test.name, time.Day(), 4)
415	}
416	if time.Hour() != 21 {
417		t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour(), 21)
418	}
419	if time.Minute() != 0 {
420		t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute(), 0)
421	}
422	if time.Second() != 57 {
423		t.Errorf("%s: bad second: %d not %d", test.name, time.Second(), 57)
424	}
425	// Nanoseconds must be checked against the precision of the input.
426	nanosec, err := strconv.ParseUint("012345678"[:test.fracDigits]+"000000000"[:9-test.fracDigits], 10, 0)
427	if err != nil {
428		panic(err)
429	}
430	if time.Nanosecond() != int(nanosec) {
431		t.Errorf("%s: bad nanosecond: %d not %d", test.name, time.Nanosecond(), nanosec)
432	}
433	name, offset := time.Zone()
434	if test.hasTZ && offset != -28800 {
435		t.Errorf("%s: bad tz offset: %s %d not %d", test.name, name, offset, -28800)
436	}
437	if test.hasWD && time.Weekday() != Thursday {
438		t.Errorf("%s: bad weekday: %s not %s", test.name, time.Weekday(), Thursday)
439	}
440}
441
442func TestFormatAndParse(t *testing.T) {
443	const fmt = "Mon MST " + RFC3339 // all fields
444	f := func(sec int64) bool {
445		t1 := Unix(sec/2, 0)
446		if t1.Year() < 1000 || t1.Year() > 9999 || t1.Unix() != sec {
447			// not required to work
448			return true
449		}
450		t2, err := Parse(fmt, t1.Format(fmt))
451		if err != nil {
452			t.Errorf("error: %s", err)
453			return false
454		}
455		if t1.Unix() != t2.Unix() || t1.Nanosecond() != t2.Nanosecond() {
456			t.Errorf("FormatAndParse %d: %q(%d) %q(%d)", sec, t1, t1.Unix(), t2, t2.Unix())
457			return false
458		}
459		return true
460	}
461	f32 := func(sec int32) bool { return f(int64(sec)) }
462	cfg := &quick.Config{MaxCount: 10000}
463
464	// Try a reasonable date first, then the huge ones.
465	if err := quick.Check(f32, cfg); err != nil {
466		t.Fatal(err)
467	}
468	if err := quick.Check(f, cfg); err != nil {
469		t.Fatal(err)
470	}
471}
472
473type ParseTimeZoneTest struct {
474	value  string
475	length int
476	ok     bool
477}
478
479var parseTimeZoneTests = []ParseTimeZoneTest{
480	{"gmt hi there", 0, false},
481	{"GMT hi there", 3, true},
482	{"GMT+12 hi there", 6, true},
483	{"GMT+00 hi there", 6, true},
484	{"GMT+", 3, true},
485	{"GMT+3", 5, true},
486	{"GMT+a", 3, true},
487	{"GMT+3a", 5, true},
488	{"GMT-5 hi there", 5, true},
489	{"GMT-51 hi there", 3, true},
490	{"ChST hi there", 4, true},
491	{"MeST hi there", 4, true},
492	{"MSDx", 3, true},
493	{"MSDY", 0, false}, // four letters must end in T.
494	{"ESAST hi", 5, true},
495	{"ESASTT hi", 0, false}, // run of upper-case letters too long.
496	{"ESATY hi", 0, false},  // five letters must end in T.
497	{"WITA hi", 4, true},    // Issue #18251
498	// Issue #24071
499	{"+03 hi", 3, true},
500	{"-04 hi", 3, true},
501	// Issue #26032
502	{"+00", 3, true},
503	{"-11", 3, true},
504	{"-12", 3, true},
505	{"-23", 3, true},
506	{"-24", 0, false},
507	{"+13", 3, true},
508	{"+14", 3, true},
509	{"+23", 3, true},
510	{"+24", 0, false},
511}
512
513func TestParseTimeZone(t *testing.T) {
514	for _, test := range parseTimeZoneTests {
515		length, ok := ParseTimeZone(test.value)
516		if ok != test.ok {
517			t.Errorf("expected %t for %q got %t", test.ok, test.value, ok)
518		} else if length != test.length {
519			t.Errorf("expected %d for %q got %d", test.length, test.value, length)
520		}
521	}
522}
523
524type ParseErrorTest struct {
525	format string
526	value  string
527	expect string // must appear within the error
528}
529
530var parseErrorTests = []ParseErrorTest{
531	{ANSIC, "Feb  4 21:00:60 2010", "cannot parse"}, // cannot parse Feb as Mon
532	{ANSIC, "Thu Feb  4 21:00:57 @2010", "cannot parse"},
533	{ANSIC, "Thu Feb  4 21:00:60 2010", "second out of range"},
534	{ANSIC, "Thu Feb  4 21:61:57 2010", "minute out of range"},
535	{ANSIC, "Thu Feb  4 24:00:60 2010", "hour out of range"},
536	{"Mon Jan _2 15:04:05.000 2006", "Thu Feb  4 23:00:59x01 2010", "cannot parse"},
537	{"Mon Jan _2 15:04:05.000 2006", "Thu Feb  4 23:00:59.xxx 2010", "cannot parse"},
538	{"Mon Jan _2 15:04:05.000 2006", "Thu Feb  4 23:00:59.-123 2010", "fractional second out of range"},
539	// issue 4502. StampNano requires exactly 9 digits of precision.
540	{StampNano, "Dec  7 11:22:01.000000", `cannot parse ".000000" as ".000000000"`},
541	{StampNano, "Dec  7 11:22:01.0000000000", `extra text: "0"`},
542	// issue 4493. Helpful errors.
543	{RFC3339, "2006-01-02T15:04:05Z07:00", `parsing time "2006-01-02T15:04:05Z07:00": extra text: "07:00"`},
544	{RFC3339, "2006-01-02T15:04_abc", `parsing time "2006-01-02T15:04_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as ":"`},
545	{RFC3339, "2006-01-02T15:04:05_abc", `parsing time "2006-01-02T15:04:05_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as "Z07:00"`},
546	{RFC3339, "2006-01-02T15:04:05Z_abc", `parsing time "2006-01-02T15:04:05Z_abc": extra text: "_abc"`},
547	// invalid second followed by optional fractional seconds
548	{RFC3339, "2010-02-04T21:00:67.012345678-08:00", "second out of range"},
549	// issue 21113
550	{"_2 Jan 06 15:04 MST", "4 --- 00 00:00 GMT", "cannot parse"},
551	{"_2 January 06 15:04 MST", "4 --- 00 00:00 GMT", "cannot parse"},
552
553	// invalid or mismatched day-of-year
554	{"Jan _2 002 2006", "Feb  4 034 2006", "day-of-year does not match day"},
555	{"Jan _2 002 2006", "Feb  4 004 2006", "day-of-year does not match month"},
556}
557
558func TestParseErrors(t *testing.T) {
559	for _, test := range parseErrorTests {
560		_, err := Parse(test.format, test.value)
561		if err == nil {
562			t.Errorf("expected error for %q %q", test.format, test.value)
563		} else if !strings.Contains(err.Error(), test.expect) {
564			t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err)
565		}
566	}
567}
568
569func TestNoonIs12PM(t *testing.T) {
570	noon := Date(0, January, 1, 12, 0, 0, 0, UTC)
571	const expect = "12:00PM"
572	got := noon.Format("3:04PM")
573	if got != expect {
574		t.Errorf("got %q; expect %q", got, expect)
575	}
576	got = noon.Format("03:04PM")
577	if got != expect {
578		t.Errorf("got %q; expect %q", got, expect)
579	}
580}
581
582func TestMidnightIs12AM(t *testing.T) {
583	midnight := Date(0, January, 1, 0, 0, 0, 0, UTC)
584	expect := "12:00AM"
585	got := midnight.Format("3:04PM")
586	if got != expect {
587		t.Errorf("got %q; expect %q", got, expect)
588	}
589	got = midnight.Format("03:04PM")
590	if got != expect {
591		t.Errorf("got %q; expect %q", got, expect)
592	}
593}
594
595func Test12PMIsNoon(t *testing.T) {
596	noon, err := Parse("3:04PM", "12:00PM")
597	if err != nil {
598		t.Fatal("error parsing date:", err)
599	}
600	if noon.Hour() != 12 {
601		t.Errorf("got %d; expect 12", noon.Hour())
602	}
603	noon, err = Parse("03:04PM", "12:00PM")
604	if err != nil {
605		t.Fatal("error parsing date:", err)
606	}
607	if noon.Hour() != 12 {
608		t.Errorf("got %d; expect 12", noon.Hour())
609	}
610}
611
612func Test12AMIsMidnight(t *testing.T) {
613	midnight, err := Parse("3:04PM", "12:00AM")
614	if err != nil {
615		t.Fatal("error parsing date:", err)
616	}
617	if midnight.Hour() != 0 {
618		t.Errorf("got %d; expect 0", midnight.Hour())
619	}
620	midnight, err = Parse("03:04PM", "12:00AM")
621	if err != nil {
622		t.Fatal("error parsing date:", err)
623	}
624	if midnight.Hour() != 0 {
625		t.Errorf("got %d; expect 0", midnight.Hour())
626	}
627}
628
629// Check that a time without a Zone still produces a (numeric) time zone
630// when formatted with MST as a requested zone.
631func TestMissingZone(t *testing.T) {
632	time, err := Parse(RubyDate, "Thu Feb 02 16:10:03 -0500 2006")
633	if err != nil {
634		t.Fatal("error parsing date:", err)
635	}
636	expect := "Thu Feb  2 16:10:03 -0500 2006" // -0500 not EST
637	str := time.Format(UnixDate)               // uses MST as its time zone
638	if str != expect {
639		t.Errorf("got %s; expect %s", str, expect)
640	}
641}
642
643func TestMinutesInTimeZone(t *testing.T) {
644	time, err := Parse(RubyDate, "Mon Jan 02 15:04:05 +0123 2006")
645	if err != nil {
646		t.Fatal("error parsing date:", err)
647	}
648	expected := (1*60 + 23) * 60
649	_, offset := time.Zone()
650	if offset != expected {
651		t.Errorf("ZoneOffset = %d, want %d", offset, expected)
652	}
653}
654
655type SecondsTimeZoneOffsetTest struct {
656	format         string
657	value          string
658	expectedoffset int
659}
660
661var secondsTimeZoneOffsetTests = []SecondsTimeZoneOffsetTest{
662	{"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
663	{"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02-00:34:08", -(34*60 + 8)},
664	{"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02+003408", 34*60 + 8},
665	{"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
666	{"2006-01-02T15:04:05Z070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
667	{"2006-01-02T15:04:05Z07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
668	{"2006-01-02T15:04:05-07", "1871-01-01T05:33:02+01", 1 * 60 * 60},
669	{"2006-01-02T15:04:05-07", "1871-01-01T05:33:02-02", -2 * 60 * 60},
670	{"2006-01-02T15:04:05Z07", "1871-01-01T05:33:02-02", -2 * 60 * 60},
671}
672
673func TestParseSecondsInTimeZone(t *testing.T) {
674	// should accept timezone offsets with seconds like: Zone America/New_York   -4:56:02 -      LMT     1883 Nov 18 12:03:58
675	for _, test := range secondsTimeZoneOffsetTests {
676		time, err := Parse(test.format, test.value)
677		if err != nil {
678			t.Fatal("error parsing date:", err)
679		}
680		_, offset := time.Zone()
681		if offset != test.expectedoffset {
682			t.Errorf("ZoneOffset = %d, want %d", offset, test.expectedoffset)
683		}
684	}
685}
686
687func TestFormatSecondsInTimeZone(t *testing.T) {
688	for _, test := range secondsTimeZoneOffsetTests {
689		d := Date(1871, 1, 1, 5, 33, 2, 0, FixedZone("LMT", test.expectedoffset))
690		timestr := d.Format(test.format)
691		if timestr != test.value {
692			t.Errorf("Format = %s, want %s", timestr, test.value)
693		}
694	}
695}
696
697// Issue 11334.
698func TestUnderscoreTwoThousand(t *testing.T) {
699	format := "15:04_20060102"
700	input := "14:38_20150618"
701	time, err := Parse(format, input)
702	if err != nil {
703		t.Error(err)
704	}
705	if y, m, d := time.Date(); y != 2015 || m != 6 || d != 18 {
706		t.Errorf("Incorrect y/m/d, got %d/%d/%d", y, m, d)
707	}
708	if h := time.Hour(); h != 14 {
709		t.Errorf("Incorrect hour, got %d", h)
710	}
711	if m := time.Minute(); m != 38 {
712		t.Errorf("Incorrect minute, got %d", m)
713	}
714}
715
716// Issue 29918, 29916
717func TestStd0xParseError(t *testing.T) {
718	tests := []struct {
719		format, value, valueElemPrefix string
720	}{
721		{"01 MST", "0 MST", "0"},
722		{"01 MST", "1 MST", "1"},
723		{RFC850, "Thursday, 04-Feb-1 21:00:57 PST", "1"},
724	}
725	for _, tt := range tests {
726		_, err := Parse(tt.format, tt.value)
727		if err == nil {
728			t.Errorf("Parse(%q, %q) did not fail as expected", tt.format, tt.value)
729		} else if perr, ok := err.(*ParseError); !ok {
730			t.Errorf("Parse(%q, %q) returned error type %T, expected ParseError", tt.format, tt.value, perr)
731		} else if !strings.Contains(perr.Error(), "cannot parse") || !strings.HasPrefix(perr.ValueElem, tt.valueElemPrefix) {
732			t.Errorf("Parse(%q, %q) returned wrong parsing error message: %v", tt.format, tt.value, perr)
733		}
734	}
735}
736
737var monthOutOfRangeTests = []struct {
738	value string
739	ok    bool
740}{
741	{"00-01", false},
742	{"13-01", false},
743	{"01-01", true},
744}
745
746func TestParseMonthOutOfRange(t *testing.T) {
747	for _, test := range monthOutOfRangeTests {
748		_, err := Parse("01-02", test.value)
749		switch {
750		case !test.ok && err != nil:
751			if !strings.Contains(err.Error(), "month out of range") {
752				t.Errorf("%q: expected 'month' error, got %v", test.value, err)
753			}
754		case test.ok && err != nil:
755			t.Errorf("%q: unexpected error: %v", test.value, err)
756		case !test.ok && err == nil:
757			t.Errorf("%q: expected 'month' error, got none", test.value)
758		}
759	}
760}
761
762// Issue 37387.
763func TestParseYday(t *testing.T) {
764	t.Parallel()
765	for i := 1; i <= 365; i++ {
766		d := fmt.Sprintf("2020-%03d", i)
767		tm, err := Parse("2006-002", d)
768		if err != nil {
769			t.Errorf("unexpected error for %s: %v", d, err)
770		} else if tm.Year() != 2020 || tm.YearDay() != i {
771			t.Errorf("got year %d yearday %d, want %d %d", tm.Year(), tm.YearDay(), 2020, i)
772		}
773	}
774}
775