Source file
src/time/format_test.go
1
2
3
4
5 package time_test
6
7 import (
8 "fmt"
9 "strconv"
10 "strings"
11 "testing"
12 "testing/quick"
13 . "time"
14 )
15
16 var 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
25 func TestNextStdChunk(t *testing.T) {
26
27
28
29
30
31
32
33
34
35 markChunks := func(format string) string {
36
37
38
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
60
61
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
70 type TimeFormatTest struct {
71 time Time
72 formattedValue string
73 }
74
75 var 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
81 func 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
91 type FormatTest struct {
92 name string
93 format string
94 result string
95 }
96
97 var 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
112 {"Janet", "Hi Janet, the Month is January", "Hi Janet, the Month is February"},
113
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
121 func TestFormat(t *testing.T) {
122
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 var goStringTests = []struct {
133 in Time
134 want string
135 }{
136 {Date(2009, February, 5, 5, 0, 57, 12345600, UTC),
137 "time.Date(2009, time.February, 5, 5, 0, 57, 12345600, time.UTC)"},
138 {Date(2009, February, 5, 5, 0, 57, 12345600, Local),
139 "time.Date(2009, time.February, 5, 5, 0, 57, 12345600, time.Local)"},
140 {Date(2009, February, 5, 5, 0, 57, 12345600, FixedZone("Europe/Berlin", 3*60*60)),
141 `time.Date(2009, time.February, 5, 5, 0, 57, 12345600, time.Location("Europe/Berlin"))`,
142 },
143 {Date(2009, February, 5, 5, 0, 57, 12345600, FixedZone("Non-ASCII character ⏰", 3*60*60)),
144 `time.Date(2009, time.February, 5, 5, 0, 57, 12345600, time.Location("Non-ASCII character \xe2\x8f\xb0"))`,
145 },
146 }
147
148 func TestGoString(t *testing.T) {
149
150 for _, tt := range goStringTests {
151 if tt.in.GoString() != tt.want {
152 t.Errorf("GoString (%q): got %q want %q", tt.in, tt.in.GoString(), tt.want)
153 }
154 }
155 }
156
157
158 func TestFormatSingleDigits(t *testing.T) {
159 time := Date(2001, 2, 3, 4, 5, 6, 700000000, UTC)
160 test := FormatTest{"single digit format", "3:4:5", "4:5:6"}
161 result := time.Format(test.format)
162 if result != test.result {
163 t.Errorf("%s expected %q got %q", test.name, test.result, result)
164 }
165 }
166
167 func TestFormatShortYear(t *testing.T) {
168 years := []int{
169 -100001, -100000, -99999,
170 -10001, -10000, -9999,
171 -1001, -1000, -999,
172 -101, -100, -99,
173 -11, -10, -9,
174 -1, 0, 1,
175 9, 10, 11,
176 99, 100, 101,
177 999, 1000, 1001,
178 9999, 10000, 10001,
179 99999, 100000, 100001,
180 }
181
182 for _, y := range years {
183 time := Date(y, January, 1, 0, 0, 0, 0, UTC)
184 result := time.Format("2006.01.02")
185 var want string
186 if y < 0 {
187
188
189 want = fmt.Sprintf("-%04d.%02d.%02d", -y, 1, 1)
190 } else {
191 want = fmt.Sprintf("%04d.%02d.%02d", y, 1, 1)
192 }
193 if result != want {
194 t.Errorf("(jan 1 %d).Format(\"2006.01.02\") = %q, want %q", y, result, want)
195 }
196 }
197 }
198
199 type ParseTest struct {
200 name string
201 format string
202 value string
203 hasTZ bool
204 hasWD bool
205 yearSign int
206 fracDigits int
207 }
208
209 var parseTests = []ParseTest{
210 {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
211 {"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010", true, true, 1, 0},
212 {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
213 {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1, 0},
214 {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1, 0},
215 {"RFC1123", RFC1123, "Thu, 04 Feb 2010 22:00:57 PDT", true, true, 1, 0},
216 {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57 -0800", true, true, 1, 0},
217 {"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1, 0},
218 {"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},
219
220 {"ANSIC", ANSIC, "Thu Feb 4 21:00:57.0 2010", false, true, 1, 1},
221 {"UnixDate", UnixDate, "Thu Feb 4 21:00:57.01 PST 2010", true, true, 1, 2},
222 {"RubyDate", RubyDate, "Thu Feb 04 21:00:57.012 -0800 2010", true, true, 1, 3},
223 {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57.0123 PST", true, true, 1, 4},
224 {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57.01234 PST", true, true, 1, 5},
225 {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57.01234 -0800", true, true, 1, 5},
226 {"RFC3339", RFC3339, "2010-02-04T21:00:57.012345678-08:00", true, false, 1, 9},
227 {"custom: \"2006-01-02 15:04:05\"", "2006-01-02 15:04:05", "2010-02-04 21:00:57.0", false, false, 1, 0},
228
229 {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
230 {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
231
232 {"ANSIC", ANSIC, "THU FEB 4 21:00:57 2010", false, true, 1, 0},
233 {"ANSIC", ANSIC, "thu feb 4 21:00:57 2010", false, true, 1, 0},
234
235 {"millisecond:: dot separator", "Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 21:00:57.012 2010", false, true, 1, 3},
236 {"microsecond:: dot separator", "Mon Jan _2 15:04:05.000000 2006", "Thu Feb 4 21:00:57.012345 2010", false, true, 1, 6},
237 {"nanosecond:: dot separator", "Mon Jan _2 15:04:05.000000000 2006", "Thu Feb 4 21:00:57.012345678 2010", false, true, 1, 9},
238 {"millisecond:: comma separator", "Mon Jan _2 15:04:05,000 2006", "Thu Feb 4 21:00:57.012 2010", false, true, 1, 3},
239 {"microsecond:: comma separator", "Mon Jan _2 15:04:05,000000 2006", "Thu Feb 4 21:00:57.012345 2010", false, true, 1, 6},
240 {"nanosecond:: comma separator", "Mon Jan _2 15:04:05,000000000 2006", "Thu Feb 4 21:00:57.012345678 2010", false, true, 1, 9},
241
242
243 {"zero1", "2006.01.02.15.04.05.0", "2010.02.04.21.00.57.0", false, false, 1, 1},
244 {"zero2", "2006.01.02.15.04.05.00", "2010.02.04.21.00.57.01", false, false, 1, 2},
245
246 {"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},
247
248
249 {"GMT-8", UnixDate, "Fri Feb 5 05:00:57 GMT-8 2010", true, true, 1, 0},
250
251
252
253
254
255 {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
256 {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
257 {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
258 {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
259 {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
260 {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
261
262 {"", "2006-01-02 15:04:05,9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
263 {"", "2006-01-02 15:04:05,999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
264 {"", "2006-01-02 15:04:05,9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
265 {"", "2006-01-02 15:04:05,999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
266 {"", "2006-01-02 15:04:05,9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
267 {"", "2006-01-02 15:04:05,999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
268
269
270 {"", StampNano, "Feb 4 21:00:57.012345678", false, false, -1, 9},
271 {"", "Jan _2 15:04:05.999", "Feb 4 21:00:57.012300000", false, false, -1, 4},
272 {"", "Jan _2 15:04:05.999", "Feb 4 21:00:57.012345678", false, false, -1, 9},
273 {"", "Jan _2 15:04:05.999999999", "Feb 4 21:00:57.0123", false, false, -1, 4},
274 {"", "Jan _2 15:04:05.999999999", "Feb 4 21:00:57.012345678", false, false, -1, 9},
275
276
277 {"", "2006-01-02 002 15:04:05", "2010-02-04 035 21:00:57", false, false, 1, 0},
278 {"", "2006-01 002 15:04:05", "2010-02 035 21:00:57", false, false, 1, 0},
279 {"", "2006-002 15:04:05", "2010-035 21:00:57", false, false, 1, 0},
280 {"", "200600201 15:04:05", "201003502 21:00:57", false, false, 1, 0},
281 {"", "200600204 15:04:05", "201003504 21:00:57", false, false, 1, 0},
282 }
283
284 func TestParse(t *testing.T) {
285 for _, test := range parseTests {
286 time, err := Parse(test.format, test.value)
287 if err != nil {
288 t.Errorf("%s error: %v", test.name, err)
289 } else {
290 checkTime(time, &test, t)
291 }
292 }
293 }
294
295
296 var dayOutOfRangeTests = []struct {
297 date string
298 ok bool
299 }{
300 {"Thu Jan 99 21:00:57 2010", false},
301 {"Thu Jan 31 21:00:57 2010", true},
302 {"Thu Jan 32 21:00:57 2010", false},
303 {"Thu Feb 28 21:00:57 2012", true},
304 {"Thu Feb 29 21:00:57 2012", true},
305 {"Thu Feb 29 21:00:57 2010", false},
306 {"Thu Mar 31 21:00:57 2010", true},
307 {"Thu Mar 32 21:00:57 2010", false},
308 {"Thu Apr 30 21:00:57 2010", true},
309 {"Thu Apr 31 21:00:57 2010", false},
310 {"Thu May 31 21:00:57 2010", true},
311 {"Thu May 32 21:00:57 2010", false},
312 {"Thu Jun 30 21:00:57 2010", true},
313 {"Thu Jun 31 21:00:57 2010", false},
314 {"Thu Jul 31 21:00:57 2010", true},
315 {"Thu Jul 32 21:00:57 2010", false},
316 {"Thu Aug 31 21:00:57 2010", true},
317 {"Thu Aug 32 21:00:57 2010", false},
318 {"Thu Sep 30 21:00:57 2010", true},
319 {"Thu Sep 31 21:00:57 2010", false},
320 {"Thu Oct 31 21:00:57 2010", true},
321 {"Thu Oct 32 21:00:57 2010", false},
322 {"Thu Nov 30 21:00:57 2010", true},
323 {"Thu Nov 31 21:00:57 2010", false},
324 {"Thu Dec 31 21:00:57 2010", true},
325 {"Thu Dec 32 21:00:57 2010", false},
326 {"Thu Dec 00 21:00:57 2010", false},
327 }
328
329 func TestParseDayOutOfRange(t *testing.T) {
330 for _, test := range dayOutOfRangeTests {
331 _, err := Parse(ANSIC, test.date)
332 switch {
333 case test.ok && err == nil:
334
335 case !test.ok && err != nil:
336 if !strings.Contains(err.Error(), "day out of range") {
337 t.Errorf("%q: expected 'day' error, got %v", test.date, err)
338 }
339 case test.ok && err != nil:
340 t.Errorf("%q: unexpected error: %v", test.date, err)
341 case !test.ok && err == nil:
342 t.Errorf("%q: expected 'day' error, got none", test.date)
343 }
344 }
345 }
346
347
348
349
350
351
352
353
354
355
356
357 func TestParseInLocation(t *testing.T) {
358
359 baghdad, err := LoadLocation("Asia/Baghdad")
360 if err != nil {
361 t.Fatal(err)
362 }
363
364 var t1, t2 Time
365
366 t1, err = ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", baghdad)
367 if err != nil {
368 t.Fatal(err)
369 }
370
371 _, offset := t1.Zone()
372
373
374
375
376
377
378 if offset != 0 {
379 t2 = Date(2013, February, 1, 00, 00, 00, 0, baghdad)
380 if t1 != t2 {
381 t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad) = %v, want %v", t1, t2)
382 }
383 if offset != 3*60*60 {
384 t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad).Zone = _, %d, want _, %d", offset, 3*60*60)
385 }
386 }
387
388 blancSablon, err := LoadLocation("America/Blanc-Sablon")
389 if err != nil {
390 t.Fatal(err)
391 }
392
393
394
395
396 t1, err = ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", blancSablon)
397 if err != nil {
398 t.Fatal(err)
399 }
400 t2 = Date(2013, February, 1, 00, 00, 00, 0, blancSablon)
401 if t1 != t2 {
402 t.Fatalf("ParseInLocation(Feb 01 2013 AST, Blanc-Sablon) = %v, want %v", t1, t2)
403 }
404 _, offset = t1.Zone()
405 if offset != -4*60*60 {
406 t.Fatalf("ParseInLocation(Feb 01 2013 AST, Blanc-Sablon).Zone = _, %d, want _, %d", offset, -4*60*60)
407 }
408 }
409
410 func TestLoadLocationZipFile(t *testing.T) {
411 ForceZipFileForTesting(true)
412 defer ForceZipFileForTesting(false)
413
414 _, err := LoadLocation("Australia/Sydney")
415 if err != nil {
416 t.Fatal(err)
417 }
418 }
419
420 var rubyTests = []ParseTest{
421 {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
422
423 {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1, 0},
424 {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1, 0},
425 {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1, 0},
426 }
427
428
429 func TestRubyParse(t *testing.T) {
430 for _, test := range rubyTests {
431 time, err := Parse(test.format, test.value)
432 if err != nil {
433 t.Errorf("%s error: %v", test.name, err)
434 } else {
435 checkTime(time, &test, t)
436 }
437 }
438 }
439
440 func checkTime(time Time, test *ParseTest, t *testing.T) {
441
442 if test.yearSign >= 0 && test.yearSign*time.Year() != 2010 {
443 t.Errorf("%s: bad year: %d not %d", test.name, time.Year(), 2010)
444 }
445 if time.Month() != February {
446 t.Errorf("%s: bad month: %s not %s", test.name, time.Month(), February)
447 }
448 if time.Day() != 4 {
449 t.Errorf("%s: bad day: %d not %d", test.name, time.Day(), 4)
450 }
451 if time.Hour() != 21 {
452 t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour(), 21)
453 }
454 if time.Minute() != 0 {
455 t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute(), 0)
456 }
457 if time.Second() != 57 {
458 t.Errorf("%s: bad second: %d not %d", test.name, time.Second(), 57)
459 }
460
461 nanosec, err := strconv.ParseUint("012345678"[:test.fracDigits]+"000000000"[:9-test.fracDigits], 10, 0)
462 if err != nil {
463 panic(err)
464 }
465 if time.Nanosecond() != int(nanosec) {
466 t.Errorf("%s: bad nanosecond: %d not %d", test.name, time.Nanosecond(), nanosec)
467 }
468 name, offset := time.Zone()
469 if test.hasTZ && offset != -28800 {
470 t.Errorf("%s: bad tz offset: %s %d not %d", test.name, name, offset, -28800)
471 }
472 if test.hasWD && time.Weekday() != Thursday {
473 t.Errorf("%s: bad weekday: %s not %s", test.name, time.Weekday(), Thursday)
474 }
475 }
476
477 func TestFormatAndParse(t *testing.T) {
478 const fmt = "Mon MST " + RFC3339
479 f := func(sec int64) bool {
480 t1 := Unix(sec/2, 0)
481 if t1.Year() < 1000 || t1.Year() > 9999 || t1.Unix() != sec {
482
483 return true
484 }
485 t2, err := Parse(fmt, t1.Format(fmt))
486 if err != nil {
487 t.Errorf("error: %s", err)
488 return false
489 }
490 if t1.Unix() != t2.Unix() || t1.Nanosecond() != t2.Nanosecond() {
491 t.Errorf("FormatAndParse %d: %q(%d) %q(%d)", sec, t1, t1.Unix(), t2, t2.Unix())
492 return false
493 }
494 return true
495 }
496 f32 := func(sec int32) bool { return f(int64(sec)) }
497 cfg := &quick.Config{MaxCount: 10000}
498
499
500 if err := quick.Check(f32, cfg); err != nil {
501 t.Fatal(err)
502 }
503 if err := quick.Check(f, cfg); err != nil {
504 t.Fatal(err)
505 }
506 }
507
508 type ParseTimeZoneTest struct {
509 value string
510 length int
511 ok bool
512 }
513
514 var parseTimeZoneTests = []ParseTimeZoneTest{
515 {"gmt hi there", 0, false},
516 {"GMT hi there", 3, true},
517 {"GMT+12 hi there", 6, true},
518 {"GMT+00 hi there", 6, true},
519 {"GMT+", 3, true},
520 {"GMT+3", 5, true},
521 {"GMT+a", 3, true},
522 {"GMT+3a", 5, true},
523 {"GMT-5 hi there", 5, true},
524 {"GMT-51 hi there", 3, true},
525 {"ChST hi there", 4, true},
526 {"MeST hi there", 4, true},
527 {"MSDx", 3, true},
528 {"MSDY", 0, false},
529 {"ESAST hi", 5, true},
530 {"ESASTT hi", 0, false},
531 {"ESATY hi", 0, false},
532 {"WITA hi", 4, true},
533
534 {"+03 hi", 3, true},
535 {"-04 hi", 3, true},
536
537 {"+00", 3, true},
538 {"-11", 3, true},
539 {"-12", 3, true},
540 {"-23", 3, true},
541 {"-24", 0, false},
542 {"+13", 3, true},
543 {"+14", 3, true},
544 {"+23", 3, true},
545 {"+24", 0, false},
546 }
547
548 func TestParseTimeZone(t *testing.T) {
549 for _, test := range parseTimeZoneTests {
550 length, ok := ParseTimeZone(test.value)
551 if ok != test.ok {
552 t.Errorf("expected %t for %q got %t", test.ok, test.value, ok)
553 } else if length != test.length {
554 t.Errorf("expected %d for %q got %d", test.length, test.value, length)
555 }
556 }
557 }
558
559 type ParseErrorTest struct {
560 format string
561 value string
562 expect string
563 }
564
565 var parseErrorTests = []ParseErrorTest{
566 {ANSIC, "Feb 4 21:00:60 2010", "cannot parse"},
567 {ANSIC, "Thu Feb 4 21:00:57 @2010", "cannot parse"},
568 {ANSIC, "Thu Feb 4 21:00:60 2010", "second out of range"},
569 {ANSIC, "Thu Feb 4 21:61:57 2010", "minute out of range"},
570 {ANSIC, "Thu Feb 4 24:00:60 2010", "hour out of range"},
571 {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59x01 2010", "cannot parse"},
572 {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.xxx 2010", "cannot parse"},
573 {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.-123 2010", "fractional second out of range"},
574
575 {StampNano, "Dec 7 11:22:01.000000", `cannot parse ".000000" as ".000000000"`},
576 {StampNano, "Dec 7 11:22:01.0000000000", `extra text: "0"`},
577
578 {RFC3339, "2006-01-02T15:04:05Z07:00", `parsing time "2006-01-02T15:04:05Z07:00": extra text: "07:00"`},
579 {RFC3339, "2006-01-02T15:04_abc", `parsing time "2006-01-02T15:04_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as ":"`},
580 {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"`},
581 {RFC3339, "2006-01-02T15:04:05Z_abc", `parsing time "2006-01-02T15:04:05Z_abc": extra text: "_abc"`},
582
583 {RFC3339, "2010-02-04T21:00:67.012345678-08:00", "second out of range"},
584
585 {"_2 Jan 06 15:04 MST", "4 --- 00 00:00 GMT", "cannot parse"},
586 {"_2 January 06 15:04 MST", "4 --- 00 00:00 GMT", "cannot parse"},
587
588
589 {"Jan _2 002 2006", "Feb 4 034 2006", "day-of-year does not match day"},
590 {"Jan _2 002 2006", "Feb 4 004 2006", "day-of-year does not match month"},
591
592
593 {`"2006-01-02T15:04:05Z07:00"`, "0", `parsing time "0" as "\"2006-01-02T15:04:05Z07:00\"": cannot parse "0" as "\""`},
594 {RFC3339, "\"", `parsing time "\"" as "2006-01-02T15:04:05Z07:00": cannot parse "\"" as "2006"`},
595 }
596
597 func TestParseErrors(t *testing.T) {
598 for _, test := range parseErrorTests {
599 _, err := Parse(test.format, test.value)
600 if err == nil {
601 t.Errorf("expected error for %q %q", test.format, test.value)
602 } else if !strings.Contains(err.Error(), test.expect) {
603 t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err)
604 }
605 }
606 }
607
608 func TestNoonIs12PM(t *testing.T) {
609 noon := Date(0, January, 1, 12, 0, 0, 0, UTC)
610 const expect = "12:00PM"
611 got := noon.Format("3:04PM")
612 if got != expect {
613 t.Errorf("got %q; expect %q", got, expect)
614 }
615 got = noon.Format("03:04PM")
616 if got != expect {
617 t.Errorf("got %q; expect %q", got, expect)
618 }
619 }
620
621 func TestMidnightIs12AM(t *testing.T) {
622 midnight := Date(0, January, 1, 0, 0, 0, 0, UTC)
623 expect := "12:00AM"
624 got := midnight.Format("3:04PM")
625 if got != expect {
626 t.Errorf("got %q; expect %q", got, expect)
627 }
628 got = midnight.Format("03:04PM")
629 if got != expect {
630 t.Errorf("got %q; expect %q", got, expect)
631 }
632 }
633
634 func Test12PMIsNoon(t *testing.T) {
635 noon, err := Parse("3:04PM", "12:00PM")
636 if err != nil {
637 t.Fatal("error parsing date:", err)
638 }
639 if noon.Hour() != 12 {
640 t.Errorf("got %d; expect 12", noon.Hour())
641 }
642 noon, err = Parse("03:04PM", "12:00PM")
643 if err != nil {
644 t.Fatal("error parsing date:", err)
645 }
646 if noon.Hour() != 12 {
647 t.Errorf("got %d; expect 12", noon.Hour())
648 }
649 }
650
651 func Test12AMIsMidnight(t *testing.T) {
652 midnight, err := Parse("3:04PM", "12:00AM")
653 if err != nil {
654 t.Fatal("error parsing date:", err)
655 }
656 if midnight.Hour() != 0 {
657 t.Errorf("got %d; expect 0", midnight.Hour())
658 }
659 midnight, err = Parse("03:04PM", "12:00AM")
660 if err != nil {
661 t.Fatal("error parsing date:", err)
662 }
663 if midnight.Hour() != 0 {
664 t.Errorf("got %d; expect 0", midnight.Hour())
665 }
666 }
667
668
669
670 func TestMissingZone(t *testing.T) {
671 time, err := Parse(RubyDate, "Thu Feb 02 16:10:03 -0500 2006")
672 if err != nil {
673 t.Fatal("error parsing date:", err)
674 }
675 expect := "Thu Feb 2 16:10:03 -0500 2006"
676 str := time.Format(UnixDate)
677 if str != expect {
678 t.Errorf("got %s; expect %s", str, expect)
679 }
680 }
681
682 func TestMinutesInTimeZone(t *testing.T) {
683 time, err := Parse(RubyDate, "Mon Jan 02 15:04:05 +0123 2006")
684 if err != nil {
685 t.Fatal("error parsing date:", err)
686 }
687 expected := (1*60 + 23) * 60
688 _, offset := time.Zone()
689 if offset != expected {
690 t.Errorf("ZoneOffset = %d, want %d", offset, expected)
691 }
692 }
693
694 type SecondsTimeZoneOffsetTest struct {
695 format string
696 value string
697 expectedoffset int
698 }
699
700 var secondsTimeZoneOffsetTests = []SecondsTimeZoneOffsetTest{
701 {"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
702 {"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02-00:34:08", -(34*60 + 8)},
703 {"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02+003408", 34*60 + 8},
704 {"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
705 {"2006-01-02T15:04:05Z070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
706 {"2006-01-02T15:04:05Z07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
707 {"2006-01-02T15:04:05-07", "1871-01-01T05:33:02+01", 1 * 60 * 60},
708 {"2006-01-02T15:04:05-07", "1871-01-01T05:33:02-02", -2 * 60 * 60},
709 {"2006-01-02T15:04:05Z07", "1871-01-01T05:33:02-02", -2 * 60 * 60},
710 }
711
712 func TestParseSecondsInTimeZone(t *testing.T) {
713
714 for _, test := range secondsTimeZoneOffsetTests {
715 time, err := Parse(test.format, test.value)
716 if err != nil {
717 t.Fatal("error parsing date:", err)
718 }
719 _, offset := time.Zone()
720 if offset != test.expectedoffset {
721 t.Errorf("ZoneOffset = %d, want %d", offset, test.expectedoffset)
722 }
723 }
724 }
725
726 func TestFormatSecondsInTimeZone(t *testing.T) {
727 for _, test := range secondsTimeZoneOffsetTests {
728 d := Date(1871, 1, 1, 5, 33, 2, 0, FixedZone("LMT", test.expectedoffset))
729 timestr := d.Format(test.format)
730 if timestr != test.value {
731 t.Errorf("Format = %s, want %s", timestr, test.value)
732 }
733 }
734 }
735
736
737 func TestUnderscoreTwoThousand(t *testing.T) {
738 format := "15:04_20060102"
739 input := "14:38_20150618"
740 time, err := Parse(format, input)
741 if err != nil {
742 t.Error(err)
743 }
744 if y, m, d := time.Date(); y != 2015 || m != 6 || d != 18 {
745 t.Errorf("Incorrect y/m/d, got %d/%d/%d", y, m, d)
746 }
747 if h := time.Hour(); h != 14 {
748 t.Errorf("Incorrect hour, got %d", h)
749 }
750 if m := time.Minute(); m != 38 {
751 t.Errorf("Incorrect minute, got %d", m)
752 }
753 }
754
755
756 func TestStd0xParseError(t *testing.T) {
757 tests := []struct {
758 format, value, valueElemPrefix string
759 }{
760 {"01 MST", "0 MST", "0"},
761 {"01 MST", "1 MST", "1"},
762 {RFC850, "Thursday, 04-Feb-1 21:00:57 PST", "1"},
763 }
764 for _, tt := range tests {
765 _, err := Parse(tt.format, tt.value)
766 if err == nil {
767 t.Errorf("Parse(%q, %q) did not fail as expected", tt.format, tt.value)
768 } else if perr, ok := err.(*ParseError); !ok {
769 t.Errorf("Parse(%q, %q) returned error type %T, expected ParseError", tt.format, tt.value, perr)
770 } else if !strings.Contains(perr.Error(), "cannot parse") || !strings.HasPrefix(perr.ValueElem, tt.valueElemPrefix) {
771 t.Errorf("Parse(%q, %q) returned wrong parsing error message: %v", tt.format, tt.value, perr)
772 }
773 }
774 }
775
776 var monthOutOfRangeTests = []struct {
777 value string
778 ok bool
779 }{
780 {"00-01", false},
781 {"13-01", false},
782 {"01-01", true},
783 }
784
785 func TestParseMonthOutOfRange(t *testing.T) {
786 for _, test := range monthOutOfRangeTests {
787 _, err := Parse("01-02", test.value)
788 switch {
789 case !test.ok && err != nil:
790 if !strings.Contains(err.Error(), "month out of range") {
791 t.Errorf("%q: expected 'month' error, got %v", test.value, err)
792 }
793 case test.ok && err != nil:
794 t.Errorf("%q: unexpected error: %v", test.value, err)
795 case !test.ok && err == nil:
796 t.Errorf("%q: expected 'month' error, got none", test.value)
797 }
798 }
799 }
800
801
802 func TestParseYday(t *testing.T) {
803 t.Parallel()
804 for i := 1; i <= 365; i++ {
805 d := fmt.Sprintf("2020-%03d", i)
806 tm, err := Parse("2006-002", d)
807 if err != nil {
808 t.Errorf("unexpected error for %s: %v", d, err)
809 } else if tm.Year() != 2020 || tm.YearDay() != i {
810 t.Errorf("got year %d yearday %d, want %d %d", tm.Year(), tm.YearDay(), 2020, i)
811 }
812 }
813 }
814
815
816 func TestQuote(t *testing.T) {
817 tests := []struct {
818 s, want string
819 }{
820 {`"`, `"\""`},
821 {`abc"xyz"`, `"abc\"xyz\""`},
822 {"", `""`},
823 {"abc", `"abc"`},
824 {`☺`, `"\xe2\x98\xba"`},
825 {`☺ hello ☺ hello`, `"\xe2\x98\xba hello \xe2\x98\xba hello"`},
826 {"\x04", `"\x04"`},
827 }
828 for _, tt := range tests {
829 if q := Quote(tt.s); q != tt.want {
830 t.Errorf("Quote(%q) = got %q, want %q", tt.s, q, tt.want)
831 }
832 }
833
834 }
835
836
837 func TestFormatFractionalSecondSeparators(t *testing.T) {
838 tests := []struct {
839 s, want string
840 }{
841 {`15:04:05.000`, `21:00:57.012`},
842 {`15:04:05.999`, `21:00:57.012`},
843 {`15:04:05,000`, `21:00:57,012`},
844 {`15:04:05,999`, `21:00:57,012`},
845 }
846
847
848 time := Unix(0, 1233810057012345600)
849 for _, tt := range tests {
850 if q := time.Format(tt.s); q != tt.want {
851 t.Errorf("Format(%q) = got %q, want %q", tt.s, q, tt.want)
852 }
853 }
854 }
855
856
857 func TestParseFractionalSecondsLongerThanNineDigits(t *testing.T) {
858 tests := []struct {
859 s string
860 want int
861 }{
862
863 {"2021-09-29T16:04:33.000000000Z", 0},
864 {"2021-09-29T16:04:33.000000001Z", 1},
865 {"2021-09-29T16:04:33.100000000Z", 100_000_000},
866 {"2021-09-29T16:04:33.100000001Z", 100_000_001},
867 {"2021-09-29T16:04:33.999999999Z", 999_999_999},
868 {"2021-09-29T16:04:33.012345678Z", 12_345_678},
869
870 {"2021-09-29T16:04:33.0000000000Z", 0},
871 {"2021-09-29T16:04:33.0000000001Z", 0},
872 {"2021-09-29T16:04:33.1000000000Z", 100_000_000},
873 {"2021-09-29T16:04:33.1000000009Z", 100_000_000},
874 {"2021-09-29T16:04:33.9999999999Z", 999_999_999},
875 {"2021-09-29T16:04:33.0123456789Z", 12_345_678},
876
877 {"2021-09-29T16:04:33.10000000000Z", 100_000_000},
878 {"2021-09-29T16:04:33.00123456789Z", 1_234_567},
879
880 {"2021-09-29T16:04:33.000123456789Z", 123_456},
881
882 {"2021-09-29T16:04:33.9999999999999999Z", 999_999_999},
883 }
884
885 for _, tt := range tests {
886 tm, err := Parse(RFC3339, tt.s)
887 if err != nil {
888 t.Errorf("Unexpected error: %v", err)
889 continue
890 }
891 if got := tm.Nanosecond(); got != tt.want {
892 t.Errorf("Parse(%q) = got %d, want %d", tt.s, got, tt.want)
893 }
894 }
895 }
896
View as plain text