github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/time/format_test.go (about) 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 5 package time_test 6 7 import ( 8 "bytes" 9 "fmt" 10 "math" 11 "strconv" 12 "strings" 13 "testing" 14 "testing/quick" 15 . "time" 16 ) 17 18 var nextStdChunkTests = []string{ 19 "(2006)-(01)-(02)T(15):(04):(05)(Z07:00)", 20 "(2006)-(01)-(02) (002) (15):(04):(05)", 21 "(2006)-(01) (002) (15):(04):(05)", 22 "(2006)-(002) (15):(04):(05)", 23 "(2006)(002)(01) (15):(04):(05)", 24 "(2006)(002)(04) (15):(04):(05)", 25 } 26 27 func TestNextStdChunk(t *testing.T) { 28 // Most bugs in Parse or Format boil down to problems with 29 // the exact detection of format chunk boundaries in the 30 // helper function nextStdChunk (here called as NextStdChunk). 31 // This test checks nextStdChunk's behavior directly, 32 // instead of needing to test it only indirectly through Parse/Format. 33 34 // markChunks returns format with each detected 35 // 'format chunk' parenthesized. 36 // For example showChunks("2006-01-02") == "(2006)-(01)-(02)". 37 markChunks := func(format string) string { 38 // Note that NextStdChunk and StdChunkNames 39 // are not part of time's public API. 40 // They are exported in export_test for this test. 41 out := "" 42 for s := format; s != ""; { 43 prefix, std, suffix := NextStdChunk(s) 44 out += prefix 45 if std > 0 { 46 out += "(" + StdChunkNames[std] + ")" 47 } 48 s = suffix 49 } 50 return out 51 } 52 53 noParens := func(r rune) rune { 54 if r == '(' || r == ')' { 55 return -1 56 } 57 return r 58 } 59 60 for _, marked := range nextStdChunkTests { 61 // marked is an expected output from markChunks. 62 // If we delete the parens and pass it through markChunks, 63 // we should get the original back. 64 format := strings.Map(noParens, marked) 65 out := markChunks(format) 66 if out != marked { 67 t.Errorf("nextStdChunk parses %q as %q, want %q", format, out, marked) 68 } 69 } 70 } 71 72 type TimeFormatTest struct { 73 time Time 74 formattedValue string 75 } 76 77 var rfc3339Formats = []TimeFormatTest{ 78 {Date(2008, 9, 17, 20, 4, 26, 0, UTC), "2008-09-17T20:04:26Z"}, 79 {Date(1994, 9, 17, 20, 4, 26, 0, FixedZone("EST", -18000)), "1994-09-17T20:04:26-05:00"}, 80 {Date(2000, 12, 26, 1, 15, 6, 0, FixedZone("OTO", 15600)), "2000-12-26T01:15:06+04:20"}, 81 } 82 83 func TestRFC3339Conversion(t *testing.T) { 84 for _, f := range rfc3339Formats { 85 if f.time.Format(RFC3339) != f.formattedValue { 86 t.Error("RFC3339:") 87 t.Errorf(" want=%+v", f.formattedValue) 88 t.Errorf(" have=%+v", f.time.Format(RFC3339)) 89 } 90 } 91 } 92 93 type FormatTest struct { 94 name string 95 format string 96 result string 97 } 98 99 var formatTests = []FormatTest{ 100 {"ANSIC", ANSIC, "Wed Feb 4 21:00:57 2009"}, 101 {"UnixDate", UnixDate, "Wed Feb 4 21:00:57 PST 2009"}, 102 {"RubyDate", RubyDate, "Wed Feb 04 21:00:57 -0800 2009"}, 103 {"RFC822", RFC822, "04 Feb 09 21:00 PST"}, 104 {"RFC850", RFC850, "Wednesday, 04-Feb-09 21:00:57 PST"}, 105 {"RFC1123", RFC1123, "Wed, 04 Feb 2009 21:00:57 PST"}, 106 {"RFC1123Z", RFC1123Z, "Wed, 04 Feb 2009 21:00:57 -0800"}, 107 {"RFC3339", RFC3339, "2009-02-04T21:00:57-08:00"}, 108 {"RFC3339Nano", RFC3339Nano, "2009-02-04T21:00:57.0123456-08:00"}, 109 {"Kitchen", Kitchen, "9:00PM"}, 110 {"am/pm", "3pm", "9pm"}, 111 {"AM/PM", "3PM", "9PM"}, 112 {"two-digit year", "06 01 02", "09 02 04"}, 113 // Three-letter months and days must not be followed by lower-case letter. 114 {"Janet", "Hi Janet, the Month is January", "Hi Janet, the Month is February"}, 115 // Time stamps, Fractional seconds. 116 {"Stamp", Stamp, "Feb 4 21:00:57"}, 117 {"StampMilli", StampMilli, "Feb 4 21:00:57.012"}, 118 {"StampMicro", StampMicro, "Feb 4 21:00:57.012345"}, 119 {"StampNano", StampNano, "Feb 4 21:00:57.012345600"}, 120 {"DateTime", DateTime, "2009-02-04 21:00:57"}, 121 {"DateOnly", DateOnly, "2009-02-04"}, 122 {"TimeOnly", TimeOnly, "21:00:57"}, 123 {"YearDay", "Jan 2 002 __2 2", "Feb 4 035 35 4"}, 124 {"Year", "2006 6 06 _6 __6 ___6", "2009 6 09 _6 __6 ___6"}, 125 {"Month", "Jan January 1 01 _1", "Feb February 2 02 _2"}, 126 {"DayOfMonth", "2 02 _2 __2", "4 04 4 35"}, 127 {"DayOfWeek", "Mon Monday", "Wed Wednesday"}, 128 {"Hour", "15 3 03 _3", "21 9 09 _9"}, 129 {"Minute", "4 04 _4", "0 00 _0"}, 130 {"Second", "5 05 _5", "57 57 _57"}, 131 } 132 133 func TestFormat(t *testing.T) { 134 // The numeric time represents Thu Feb 4 21:00:57.012345600 PST 2009 135 time := Unix(0, 1233810057012345600) 136 for _, test := range formatTests { 137 result := time.Format(test.format) 138 if result != test.result { 139 t.Errorf("%s expected %q got %q", test.name, test.result, result) 140 } 141 } 142 } 143 144 var goStringTests = []struct { 145 in Time 146 want string 147 }{ 148 {Date(2009, February, 5, 5, 0, 57, 12345600, UTC), 149 "time.Date(2009, time.February, 5, 5, 0, 57, 12345600, time.UTC)"}, 150 {Date(2009, February, 5, 5, 0, 57, 12345600, Local), 151 "time.Date(2009, time.February, 5, 5, 0, 57, 12345600, time.Local)"}, 152 {Date(2009, February, 5, 5, 0, 57, 12345600, FixedZone("Europe/Berlin", 3*60*60)), 153 `time.Date(2009, time.February, 5, 5, 0, 57, 12345600, time.Location("Europe/Berlin"))`, 154 }, 155 {Date(2009, February, 5, 5, 0, 57, 12345600, FixedZone("Non-ASCII character ⏰", 3*60*60)), 156 `time.Date(2009, time.February, 5, 5, 0, 57, 12345600, time.Location("Non-ASCII character \xe2\x8f\xb0"))`, 157 }, 158 } 159 160 func TestGoString(t *testing.T) { 161 // The numeric time represents Thu Feb 4 21:00:57.012345600 PST 2009 162 for _, tt := range goStringTests { 163 if tt.in.GoString() != tt.want { 164 t.Errorf("GoString (%q): got %q want %q", tt.in, tt.in.GoString(), tt.want) 165 } 166 } 167 } 168 169 // issue 12440. 170 func TestFormatSingleDigits(t *testing.T) { 171 time := Date(2001, 2, 3, 4, 5, 6, 700000000, UTC) 172 test := FormatTest{"single digit format", "3:4:5", "4:5:6"} 173 result := time.Format(test.format) 174 if result != test.result { 175 t.Errorf("%s expected %q got %q", test.name, test.result, result) 176 } 177 } 178 179 func TestFormatShortYear(t *testing.T) { 180 years := []int{ 181 -100001, -100000, -99999, 182 -10001, -10000, -9999, 183 -1001, -1000, -999, 184 -101, -100, -99, 185 -11, -10, -9, 186 -1, 0, 1, 187 9, 10, 11, 188 99, 100, 101, 189 999, 1000, 1001, 190 9999, 10000, 10001, 191 99999, 100000, 100001, 192 } 193 194 for _, y := range years { 195 time := Date(y, January, 1, 0, 0, 0, 0, UTC) 196 result := time.Format("2006.01.02") 197 var want string 198 if y < 0 { 199 // The 4 in %04d counts the - sign, so print -y instead 200 // and introduce our own - sign. 201 want = fmt.Sprintf("-%04d.%02d.%02d", -y, 1, 1) 202 } else { 203 want = fmt.Sprintf("%04d.%02d.%02d", y, 1, 1) 204 } 205 if result != want { 206 t.Errorf("(jan 1 %d).Format(\"2006.01.02\") = %q, want %q", y, result, want) 207 } 208 } 209 } 210 211 type ParseTest struct { 212 name string 213 format string 214 value string 215 hasTZ bool // contains a time zone 216 hasWD bool // contains a weekday 217 yearSign int // sign of year, -1 indicates the year is not present in the format 218 fracDigits int // number of digits of fractional second 219 } 220 221 var parseTests = []ParseTest{ 222 {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0}, 223 {"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010", true, true, 1, 0}, 224 {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0}, 225 {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1, 0}, 226 {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1, 0}, 227 {"RFC1123", RFC1123, "Thu, 04 Feb 2010 22:00:57 PDT", true, true, 1, 0}, 228 {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57 -0800", true, true, 1, 0}, 229 {"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1, 0}, 230 {"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}, 231 // Optional fractional seconds. 232 {"ANSIC", ANSIC, "Thu Feb 4 21:00:57.0 2010", false, true, 1, 1}, 233 {"UnixDate", UnixDate, "Thu Feb 4 21:00:57.01 PST 2010", true, true, 1, 2}, 234 {"RubyDate", RubyDate, "Thu Feb 04 21:00:57.012 -0800 2010", true, true, 1, 3}, 235 {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57.0123 PST", true, true, 1, 4}, 236 {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57.01234 PST", true, true, 1, 5}, 237 {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57.01234 -0800", true, true, 1, 5}, 238 {"RFC3339", RFC3339, "2010-02-04T21:00:57.012345678-08:00", true, false, 1, 9}, 239 {"custom: \"2006-01-02 15:04:05\"", "2006-01-02 15:04:05", "2010-02-04 21:00:57.0", false, false, 1, 0}, 240 // Amount of white space should not matter. 241 {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0}, 242 {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0}, 243 // Case should not matter 244 {"ANSIC", ANSIC, "THU FEB 4 21:00:57 2010", false, true, 1, 0}, 245 {"ANSIC", ANSIC, "thu feb 4 21:00:57 2010", false, true, 1, 0}, 246 // Fractional seconds. 247 {"millisecond:: dot separator", "Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 21:00:57.012 2010", false, true, 1, 3}, 248 {"microsecond:: dot separator", "Mon Jan _2 15:04:05.000000 2006", "Thu Feb 4 21:00:57.012345 2010", false, true, 1, 6}, 249 {"nanosecond:: dot separator", "Mon Jan _2 15:04:05.000000000 2006", "Thu Feb 4 21:00:57.012345678 2010", false, true, 1, 9}, 250 {"millisecond:: comma separator", "Mon Jan _2 15:04:05,000 2006", "Thu Feb 4 21:00:57.012 2010", false, true, 1, 3}, 251 {"microsecond:: comma separator", "Mon Jan _2 15:04:05,000000 2006", "Thu Feb 4 21:00:57.012345 2010", false, true, 1, 6}, 252 {"nanosecond:: comma separator", "Mon Jan _2 15:04:05,000000000 2006", "Thu Feb 4 21:00:57.012345678 2010", false, true, 1, 9}, 253 254 // Leading zeros in other places should not be taken as fractional seconds. 255 {"zero1", "2006.01.02.15.04.05.0", "2010.02.04.21.00.57.0", false, false, 1, 1}, 256 {"zero2", "2006.01.02.15.04.05.00", "2010.02.04.21.00.57.01", false, false, 1, 2}, 257 // Month and day names only match when not followed by a lower-case letter. 258 {"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}, 259 260 // GMT with offset. 261 {"GMT-8", UnixDate, "Fri Feb 5 05:00:57 GMT-8 2010", true, true, 1, 0}, 262 263 // Accept any number of fractional second digits (including none) for .999... 264 // In Go 1, .999... was completely ignored in the format, meaning the first two 265 // cases would succeed, but the next four would not. Go 1.1 accepts all six. 266 // decimal "." separator. 267 {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0}, 268 {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0}, 269 {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4}, 270 {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4}, 271 {"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9}, 272 {"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9}, 273 // comma "," separator. 274 {"", "2006-01-02 15:04:05,9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0}, 275 {"", "2006-01-02 15:04:05,999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0}, 276 {"", "2006-01-02 15:04:05,9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4}, 277 {"", "2006-01-02 15:04:05,999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4}, 278 {"", "2006-01-02 15:04:05,9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9}, 279 {"", "2006-01-02 15:04:05,999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9}, 280 281 // issue 4502. 282 {"", StampNano, "Feb 4 21:00:57.012345678", false, false, -1, 9}, 283 {"", "Jan _2 15:04:05.999", "Feb 4 21:00:57.012300000", false, false, -1, 4}, 284 {"", "Jan _2 15:04:05.999", "Feb 4 21:00:57.012345678", false, false, -1, 9}, 285 {"", "Jan _2 15:04:05.999999999", "Feb 4 21:00:57.0123", false, false, -1, 4}, 286 {"", "Jan _2 15:04:05.999999999", "Feb 4 21:00:57.012345678", false, false, -1, 9}, 287 288 // Day of year. 289 {"", "2006-01-02 002 15:04:05", "2010-02-04 035 21:00:57", false, false, 1, 0}, 290 {"", "2006-01 002 15:04:05", "2010-02 035 21:00:57", false, false, 1, 0}, 291 {"", "2006-002 15:04:05", "2010-035 21:00:57", false, false, 1, 0}, 292 {"", "200600201 15:04:05", "201003502 21:00:57", false, false, 1, 0}, 293 {"", "200600204 15:04:05", "201003504 21:00:57", false, false, 1, 0}, 294 } 295 296 func TestParse(t *testing.T) { 297 for _, test := range parseTests { 298 time, err := Parse(test.format, test.value) 299 if err != nil { 300 t.Errorf("%s error: %v", test.name, err) 301 } else { 302 checkTime(time, &test, t) 303 } 304 } 305 } 306 307 // All parsed with ANSIC. 308 var dayOutOfRangeTests = []struct { 309 date string 310 ok bool 311 }{ 312 {"Thu Jan 99 21:00:57 2010", false}, 313 {"Thu Jan 31 21:00:57 2010", true}, 314 {"Thu Jan 32 21:00:57 2010", false}, 315 {"Thu Feb 28 21:00:57 2012", true}, 316 {"Thu Feb 29 21:00:57 2012", true}, 317 {"Thu Feb 29 21:00:57 2010", false}, 318 {"Thu Mar 31 21:00:57 2010", true}, 319 {"Thu Mar 32 21:00:57 2010", false}, 320 {"Thu Apr 30 21:00:57 2010", true}, 321 {"Thu Apr 31 21:00:57 2010", false}, 322 {"Thu May 31 21:00:57 2010", true}, 323 {"Thu May 32 21:00:57 2010", false}, 324 {"Thu Jun 30 21:00:57 2010", true}, 325 {"Thu Jun 31 21:00:57 2010", false}, 326 {"Thu Jul 31 21:00:57 2010", true}, 327 {"Thu Jul 32 21:00:57 2010", false}, 328 {"Thu Aug 31 21:00:57 2010", true}, 329 {"Thu Aug 32 21:00:57 2010", false}, 330 {"Thu Sep 30 21:00:57 2010", true}, 331 {"Thu Sep 31 21:00:57 2010", false}, 332 {"Thu Oct 31 21:00:57 2010", true}, 333 {"Thu Oct 32 21:00:57 2010", false}, 334 {"Thu Nov 30 21:00:57 2010", true}, 335 {"Thu Nov 31 21:00:57 2010", false}, 336 {"Thu Dec 31 21:00:57 2010", true}, 337 {"Thu Dec 32 21:00:57 2010", false}, 338 {"Thu Dec 00 21:00:57 2010", false}, 339 } 340 341 func TestParseDayOutOfRange(t *testing.T) { 342 for _, test := range dayOutOfRangeTests { 343 _, err := Parse(ANSIC, test.date) 344 switch { 345 case test.ok && err == nil: 346 // OK 347 case !test.ok && err != nil: 348 if !strings.Contains(err.Error(), "day out of range") { 349 t.Errorf("%q: expected 'day' error, got %v", test.date, err) 350 } 351 case test.ok && err != nil: 352 t.Errorf("%q: unexpected error: %v", test.date, err) 353 case !test.ok && err == nil: 354 t.Errorf("%q: expected 'day' error, got none", test.date) 355 } 356 } 357 } 358 359 // TestParseInLocation checks that the Parse and ParseInLocation 360 // functions do not get confused by the fact that AST (Arabia Standard 361 // Time) and AST (Atlantic Standard Time) are different time zones, 362 // even though they have the same abbreviation. 363 // 364 // ICANN has been slowly phasing out invented abbreviation in favor of 365 // numeric time zones (for example, the Asia/Baghdad time zone 366 // abbreviation got changed from AST to +03 in the 2017a tzdata 367 // release); but we still want to make sure that the time package does 368 // not get confused on systems with slightly older tzdata packages. 369 func TestParseInLocation(t *testing.T) { 370 371 baghdad, err := LoadLocation("Asia/Baghdad") 372 if err != nil { 373 t.Fatal(err) 374 } 375 376 var t1, t2 Time 377 378 t1, err = ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", baghdad) 379 if err != nil { 380 t.Fatal(err) 381 } 382 383 _, offset := t1.Zone() 384 385 // A zero offset means that ParseInLocation did not recognize the 386 // 'AST' abbreviation as matching the current location (Baghdad, 387 // where we'd expect a +03 hrs offset); likely because we're using 388 // a recent tzdata release (2017a or newer). 389 // If it happens, skip the Baghdad test. 390 if offset != 0 { 391 t2 = Date(2013, February, 1, 00, 00, 00, 0, baghdad) 392 if t1 != t2 { 393 t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad) = %v, want %v", t1, t2) 394 } 395 if offset != 3*60*60 { 396 t.Fatalf("ParseInLocation(Feb 01 2013 AST, Baghdad).Zone = _, %d, want _, %d", offset, 3*60*60) 397 } 398 } 399 400 blancSablon, err := LoadLocation("America/Blanc-Sablon") 401 if err != nil { 402 t.Fatal(err) 403 } 404 405 // In this case 'AST' means 'Atlantic Standard Time', and we 406 // expect the abbreviation to correctly match the american 407 // location. 408 t1, err = ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 AST", blancSablon) 409 if err != nil { 410 t.Fatal(err) 411 } 412 t2 = Date(2013, February, 1, 00, 00, 00, 0, blancSablon) 413 if t1 != t2 { 414 t.Fatalf("ParseInLocation(Feb 01 2013 AST, Blanc-Sablon) = %v, want %v", t1, t2) 415 } 416 _, offset = t1.Zone() 417 if offset != -4*60*60 { 418 t.Fatalf("ParseInLocation(Feb 01 2013 AST, Blanc-Sablon).Zone = _, %d, want _, %d", offset, -4*60*60) 419 } 420 } 421 422 func TestLoadLocationZipFile(t *testing.T) { 423 undo := DisablePlatformSources() 424 defer undo() 425 426 _, err := LoadLocation("Australia/Sydney") 427 if err != nil { 428 t.Fatal(err) 429 } 430 } 431 432 var rubyTests = []ParseTest{ 433 {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0}, 434 // Ignore the time zone in the test. If it parses, it'll be OK. 435 {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1, 0}, 436 {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1, 0}, 437 {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1, 0}, 438 } 439 440 // Problematic time zone format needs special tests. 441 func TestRubyParse(t *testing.T) { 442 for _, test := range rubyTests { 443 time, err := Parse(test.format, test.value) 444 if err != nil { 445 t.Errorf("%s error: %v", test.name, err) 446 } else { 447 checkTime(time, &test, t) 448 } 449 } 450 } 451 452 func checkTime(time Time, test *ParseTest, t *testing.T) { 453 // The time should be Thu Feb 4 21:00:57 PST 2010 454 if test.yearSign >= 0 && test.yearSign*time.Year() != 2010 { 455 t.Errorf("%s: bad year: %d not %d", test.name, time.Year(), 2010) 456 } 457 if time.Month() != February { 458 t.Errorf("%s: bad month: %s not %s", test.name, time.Month(), February) 459 } 460 if time.Day() != 4 { 461 t.Errorf("%s: bad day: %d not %d", test.name, time.Day(), 4) 462 } 463 if time.Hour() != 21 { 464 t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour(), 21) 465 } 466 if time.Minute() != 0 { 467 t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute(), 0) 468 } 469 if time.Second() != 57 { 470 t.Errorf("%s: bad second: %d not %d", test.name, time.Second(), 57) 471 } 472 // Nanoseconds must be checked against the precision of the input. 473 nanosec, err := strconv.ParseUint("012345678"[:test.fracDigits]+"000000000"[:9-test.fracDigits], 10, 0) 474 if err != nil { 475 panic(err) 476 } 477 if time.Nanosecond() != int(nanosec) { 478 t.Errorf("%s: bad nanosecond: %d not %d", test.name, time.Nanosecond(), nanosec) 479 } 480 name, offset := time.Zone() 481 if test.hasTZ && offset != -28800 { 482 t.Errorf("%s: bad tz offset: %s %d not %d", test.name, name, offset, -28800) 483 } 484 if test.hasWD && time.Weekday() != Thursday { 485 t.Errorf("%s: bad weekday: %s not %s", test.name, time.Weekday(), Thursday) 486 } 487 } 488 489 func TestFormatAndParse(t *testing.T) { 490 const fmt = "Mon MST " + RFC3339 // all fields 491 f := func(sec int64) bool { 492 t1 := Unix(sec/2, 0) 493 if t1.Year() < 1000 || t1.Year() > 9999 || t1.Unix() != sec { 494 // not required to work 495 return true 496 } 497 t2, err := Parse(fmt, t1.Format(fmt)) 498 if err != nil { 499 t.Errorf("error: %s", err) 500 return false 501 } 502 if t1.Unix() != t2.Unix() || t1.Nanosecond() != t2.Nanosecond() { 503 t.Errorf("FormatAndParse %d: %q(%d) %q(%d)", sec, t1, t1.Unix(), t2, t2.Unix()) 504 return false 505 } 506 return true 507 } 508 f32 := func(sec int32) bool { return f(int64(sec)) } 509 cfg := &quick.Config{MaxCount: 10000} 510 511 // Try a reasonable date first, then the huge ones. 512 if err := quick.Check(f32, cfg); err != nil { 513 t.Fatal(err) 514 } 515 if err := quick.Check(f, cfg); err != nil { 516 t.Fatal(err) 517 } 518 } 519 520 type ParseTimeZoneTest struct { 521 value string 522 length int 523 ok bool 524 } 525 526 var parseTimeZoneTests = []ParseTimeZoneTest{ 527 {"gmt hi there", 0, false}, 528 {"GMT hi there", 3, true}, 529 {"GMT+12 hi there", 6, true}, 530 {"GMT+00 hi there", 6, true}, 531 {"GMT+", 3, true}, 532 {"GMT+3", 5, true}, 533 {"GMT+a", 3, true}, 534 {"GMT+3a", 5, true}, 535 {"GMT-5 hi there", 5, true}, 536 {"GMT-51 hi there", 3, true}, 537 {"ChST hi there", 4, true}, 538 {"MeST hi there", 4, true}, 539 {"MSDx", 3, true}, 540 {"MSDY", 0, false}, // four letters must end in T. 541 {"ESAST hi", 5, true}, 542 {"ESASTT hi", 0, false}, // run of upper-case letters too long. 543 {"ESATY hi", 0, false}, // five letters must end in T. 544 {"WITA hi", 4, true}, // Issue #18251 545 // Issue #24071 546 {"+03 hi", 3, true}, 547 {"-04 hi", 3, true}, 548 // Issue #26032 549 {"+00", 3, true}, 550 {"-11", 3, true}, 551 {"-12", 3, true}, 552 {"-23", 3, true}, 553 {"-24", 0, false}, 554 {"+13", 3, true}, 555 {"+14", 3, true}, 556 {"+23", 3, true}, 557 {"+24", 0, false}, 558 } 559 560 func TestParseTimeZone(t *testing.T) { 561 for _, test := range parseTimeZoneTests { 562 length, ok := ParseTimeZone(test.value) 563 if ok != test.ok { 564 t.Errorf("expected %t for %q got %t", test.ok, test.value, ok) 565 } else if length != test.length { 566 t.Errorf("expected %d for %q got %d", test.length, test.value, length) 567 } 568 } 569 } 570 571 type ParseErrorTest struct { 572 format string 573 value string 574 expect string // must appear within the error 575 } 576 577 var parseErrorTests = []ParseErrorTest{ 578 {ANSIC, "Feb 4 21:00:60 2010", "cannot parse"}, // cannot parse Feb as Mon 579 {ANSIC, "Thu Feb 4 21:00:57 @2010", "cannot parse"}, 580 {ANSIC, "Thu Feb 4 21:00:60 2010", "second out of range"}, 581 {ANSIC, "Thu Feb 4 21:61:57 2010", "minute out of range"}, 582 {ANSIC, "Thu Feb 4 24:00:60 2010", "hour out of range"}, 583 {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59x01 2010", "cannot parse"}, 584 {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.xxx 2010", "cannot parse"}, 585 {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.-123 2010", "fractional second out of range"}, 586 // issue 4502. StampNano requires exactly 9 digits of precision. 587 {StampNano, "Dec 7 11:22:01.000000", `cannot parse ".000000" as ".000000000"`}, 588 {StampNano, "Dec 7 11:22:01.0000000000", `extra text: "0"`}, 589 // issue 4493. Helpful errors. 590 {RFC3339, "2006-01-02T15:04:05Z07:00", `parsing time "2006-01-02T15:04:05Z07:00": extra text: "07:00"`}, 591 {RFC3339, "2006-01-02T15:04_abc", `parsing time "2006-01-02T15:04_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as ":"`}, 592 {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"`}, 593 {RFC3339, "2006-01-02T15:04:05Z_abc", `parsing time "2006-01-02T15:04:05Z_abc": extra text: "_abc"`}, 594 // invalid second followed by optional fractional seconds 595 {RFC3339, "2010-02-04T21:00:67.012345678-08:00", "second out of range"}, 596 // issue 54569 597 {RFC3339, "0000-01-01T00:00:.0+00:00", `parsing time "0000-01-01T00:00:.0+00:00" as "2006-01-02T15:04:05Z07:00": cannot parse ".0+00:00" as "05"`}, 598 // issue 21113 599 {"_2 Jan 06 15:04 MST", "4 --- 00 00:00 GMT", "cannot parse"}, 600 {"_2 January 06 15:04 MST", "4 --- 00 00:00 GMT", "cannot parse"}, 601 602 // invalid or mismatched day-of-year 603 {"Jan _2 002 2006", "Feb 4 034 2006", "day-of-year does not match day"}, 604 {"Jan _2 002 2006", "Feb 4 004 2006", "day-of-year does not match month"}, 605 606 // issue 45391. 607 {`"2006-01-02T15:04:05Z07:00"`, "0", `parsing time "0" as "\"2006-01-02T15:04:05Z07:00\"": cannot parse "0" as "\""`}, 608 {RFC3339, "\"", `parsing time "\"" as "2006-01-02T15:04:05Z07:00": cannot parse "\"" as "2006"`}, 609 610 // issue 54570 611 {RFC3339, "0000-01-01T00:00:00+00:+0", `parsing time "0000-01-01T00:00:00+00:+0" as "2006-01-02T15:04:05Z07:00": cannot parse "" as "Z07:00"`}, 612 {RFC3339, "0000-01-01T00:00:00+-0:00", `parsing time "0000-01-01T00:00:00+-0:00" as "2006-01-02T15:04:05Z07:00": cannot parse "" as "Z07:00"`}, 613 } 614 615 func TestParseErrors(t *testing.T) { 616 for _, test := range parseErrorTests { 617 _, err := Parse(test.format, test.value) 618 if err == nil { 619 t.Errorf("expected error for %q %q", test.format, test.value) 620 } else if !strings.Contains(err.Error(), test.expect) { 621 t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err) 622 } 623 } 624 } 625 626 func TestNoonIs12PM(t *testing.T) { 627 noon := Date(0, January, 1, 12, 0, 0, 0, UTC) 628 const expect = "12:00PM" 629 got := noon.Format("3:04PM") 630 if got != expect { 631 t.Errorf("got %q; expect %q", got, expect) 632 } 633 got = noon.Format("03:04PM") 634 if got != expect { 635 t.Errorf("got %q; expect %q", got, expect) 636 } 637 } 638 639 func TestMidnightIs12AM(t *testing.T) { 640 midnight := Date(0, January, 1, 0, 0, 0, 0, UTC) 641 expect := "12:00AM" 642 got := midnight.Format("3:04PM") 643 if got != expect { 644 t.Errorf("got %q; expect %q", got, expect) 645 } 646 got = midnight.Format("03:04PM") 647 if got != expect { 648 t.Errorf("got %q; expect %q", got, expect) 649 } 650 } 651 652 func Test12PMIsNoon(t *testing.T) { 653 noon, err := Parse("3:04PM", "12:00PM") 654 if err != nil { 655 t.Fatal("error parsing date:", err) 656 } 657 if noon.Hour() != 12 { 658 t.Errorf("got %d; expect 12", noon.Hour()) 659 } 660 noon, err = Parse("03:04PM", "12:00PM") 661 if err != nil { 662 t.Fatal("error parsing date:", err) 663 } 664 if noon.Hour() != 12 { 665 t.Errorf("got %d; expect 12", noon.Hour()) 666 } 667 } 668 669 func Test12AMIsMidnight(t *testing.T) { 670 midnight, err := Parse("3:04PM", "12:00AM") 671 if err != nil { 672 t.Fatal("error parsing date:", err) 673 } 674 if midnight.Hour() != 0 { 675 t.Errorf("got %d; expect 0", midnight.Hour()) 676 } 677 midnight, err = Parse("03:04PM", "12:00AM") 678 if err != nil { 679 t.Fatal("error parsing date:", err) 680 } 681 if midnight.Hour() != 0 { 682 t.Errorf("got %d; expect 0", midnight.Hour()) 683 } 684 } 685 686 // Check that a time without a Zone still produces a (numeric) time zone 687 // when formatted with MST as a requested zone. 688 func TestMissingZone(t *testing.T) { 689 time, err := Parse(RubyDate, "Thu Feb 02 16:10:03 -0500 2006") 690 if err != nil { 691 t.Fatal("error parsing date:", err) 692 } 693 expect := "Thu Feb 2 16:10:03 -0500 2006" // -0500 not EST 694 str := time.Format(UnixDate) // uses MST as its time zone 695 if str != expect { 696 t.Errorf("got %s; expect %s", str, expect) 697 } 698 } 699 700 func TestMinutesInTimeZone(t *testing.T) { 701 time, err := Parse(RubyDate, "Mon Jan 02 15:04:05 +0123 2006") 702 if err != nil { 703 t.Fatal("error parsing date:", err) 704 } 705 expected := (1*60 + 23) * 60 706 _, offset := time.Zone() 707 if offset != expected { 708 t.Errorf("ZoneOffset = %d, want %d", offset, expected) 709 } 710 } 711 712 type SecondsTimeZoneOffsetTest struct { 713 format string 714 value string 715 expectedoffset int 716 } 717 718 var secondsTimeZoneOffsetTests = []SecondsTimeZoneOffsetTest{ 719 {"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)}, 720 {"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02-00:34:08", -(34*60 + 8)}, 721 {"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02+003408", 34*60 + 8}, 722 {"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8}, 723 {"2006-01-02T15:04:05Z070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)}, 724 {"2006-01-02T15:04:05Z07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8}, 725 {"2006-01-02T15:04:05-07", "1871-01-01T05:33:02+01", 1 * 60 * 60}, 726 {"2006-01-02T15:04:05-07", "1871-01-01T05:33:02-02", -2 * 60 * 60}, 727 {"2006-01-02T15:04:05Z07", "1871-01-01T05:33:02-02", -2 * 60 * 60}, 728 } 729 730 func TestParseSecondsInTimeZone(t *testing.T) { 731 // should accept timezone offsets with seconds like: Zone America/New_York -4:56:02 - LMT 1883 Nov 18 12:03:58 732 for _, test := range secondsTimeZoneOffsetTests { 733 time, err := Parse(test.format, test.value) 734 if err != nil { 735 t.Fatal("error parsing date:", err) 736 } 737 _, offset := time.Zone() 738 if offset != test.expectedoffset { 739 t.Errorf("ZoneOffset = %d, want %d", offset, test.expectedoffset) 740 } 741 } 742 } 743 744 func TestFormatSecondsInTimeZone(t *testing.T) { 745 for _, test := range secondsTimeZoneOffsetTests { 746 d := Date(1871, 1, 1, 5, 33, 2, 0, FixedZone("LMT", test.expectedoffset)) 747 timestr := d.Format(test.format) 748 if timestr != test.value { 749 t.Errorf("Format = %s, want %s", timestr, test.value) 750 } 751 } 752 } 753 754 // Issue 11334. 755 func TestUnderscoreTwoThousand(t *testing.T) { 756 format := "15:04_20060102" 757 input := "14:38_20150618" 758 time, err := Parse(format, input) 759 if err != nil { 760 t.Error(err) 761 } 762 if y, m, d := time.Date(); y != 2015 || m != 6 || d != 18 { 763 t.Errorf("Incorrect y/m/d, got %d/%d/%d", y, m, d) 764 } 765 if h := time.Hour(); h != 14 { 766 t.Errorf("Incorrect hour, got %d", h) 767 } 768 if m := time.Minute(); m != 38 { 769 t.Errorf("Incorrect minute, got %d", m) 770 } 771 } 772 773 // Issue 29918, 29916 774 func TestStd0xParseError(t *testing.T) { 775 tests := []struct { 776 format, value, valueElemPrefix string 777 }{ 778 {"01 MST", "0 MST", "0"}, 779 {"01 MST", "1 MST", "1"}, 780 {RFC850, "Thursday, 04-Feb-1 21:00:57 PST", "1"}, 781 } 782 for _, tt := range tests { 783 _, err := Parse(tt.format, tt.value) 784 if err == nil { 785 t.Errorf("Parse(%q, %q) did not fail as expected", tt.format, tt.value) 786 } else if perr, ok := err.(*ParseError); !ok { 787 t.Errorf("Parse(%q, %q) returned error type %T, expected ParseError", tt.format, tt.value, perr) 788 } else if !strings.Contains(perr.Error(), "cannot parse") || !strings.HasPrefix(perr.ValueElem, tt.valueElemPrefix) { 789 t.Errorf("Parse(%q, %q) returned wrong parsing error message: %v", tt.format, tt.value, perr) 790 } 791 } 792 } 793 794 var monthOutOfRangeTests = []struct { 795 value string 796 ok bool 797 }{ 798 {"00-01", false}, 799 {"13-01", false}, 800 {"01-01", true}, 801 } 802 803 func TestParseMonthOutOfRange(t *testing.T) { 804 for _, test := range monthOutOfRangeTests { 805 _, err := Parse("01-02", test.value) 806 switch { 807 case !test.ok && err != nil: 808 if !strings.Contains(err.Error(), "month out of range") { 809 t.Errorf("%q: expected 'month' error, got %v", test.value, err) 810 } 811 case test.ok && err != nil: 812 t.Errorf("%q: unexpected error: %v", test.value, err) 813 case !test.ok && err == nil: 814 t.Errorf("%q: expected 'month' error, got none", test.value) 815 } 816 } 817 } 818 819 // Issue 37387. 820 func TestParseYday(t *testing.T) { 821 t.Parallel() 822 for i := 1; i <= 365; i++ { 823 d := fmt.Sprintf("2020-%03d", i) 824 tm, err := Parse("2006-002", d) 825 if err != nil { 826 t.Errorf("unexpected error for %s: %v", d, err) 827 } else if tm.Year() != 2020 || tm.YearDay() != i { 828 t.Errorf("got year %d yearday %d, want %d %d", tm.Year(), tm.YearDay(), 2020, i) 829 } 830 } 831 } 832 833 // Issue 45391. 834 func TestQuote(t *testing.T) { 835 tests := []struct { 836 s, want string 837 }{ 838 {`"`, `"\""`}, 839 {`abc"xyz"`, `"abc\"xyz\""`}, 840 {"", `""`}, 841 {"abc", `"abc"`}, 842 {`☺`, `"\xe2\x98\xba"`}, 843 {`☺ hello ☺ hello`, `"\xe2\x98\xba hello \xe2\x98\xba hello"`}, 844 {"\x04", `"\x04"`}, 845 } 846 for _, tt := range tests { 847 if q := Quote(tt.s); q != tt.want { 848 t.Errorf("Quote(%q) = got %q, want %q", tt.s, q, tt.want) 849 } 850 } 851 852 } 853 854 // Issue 48037 855 func TestFormatFractionalSecondSeparators(t *testing.T) { 856 tests := []struct { 857 s, want string 858 }{ 859 {`15:04:05.000`, `21:00:57.012`}, 860 {`15:04:05.999`, `21:00:57.012`}, 861 {`15:04:05,000`, `21:00:57,012`}, 862 {`15:04:05,999`, `21:00:57,012`}, 863 } 864 865 // The numeric time represents Thu Feb 4 21:00:57.012345600 PST 2009 866 time := Unix(0, 1233810057012345600) 867 for _, tt := range tests { 868 if q := time.Format(tt.s); q != tt.want { 869 t.Errorf("Format(%q) = got %q, want %q", tt.s, q, tt.want) 870 } 871 } 872 } 873 874 var longFractionalDigitsTests = []struct { 875 value string 876 want int 877 }{ 878 // 9 digits 879 {"2021-09-29T16:04:33.000000000Z", 0}, 880 {"2021-09-29T16:04:33.000000001Z", 1}, 881 {"2021-09-29T16:04:33.100000000Z", 100_000_000}, 882 {"2021-09-29T16:04:33.100000001Z", 100_000_001}, 883 {"2021-09-29T16:04:33.999999999Z", 999_999_999}, 884 {"2021-09-29T16:04:33.012345678Z", 12_345_678}, 885 // 10 digits, truncates 886 {"2021-09-29T16:04:33.0000000000Z", 0}, 887 {"2021-09-29T16:04:33.0000000001Z", 0}, 888 {"2021-09-29T16:04:33.1000000000Z", 100_000_000}, 889 {"2021-09-29T16:04:33.1000000009Z", 100_000_000}, 890 {"2021-09-29T16:04:33.9999999999Z", 999_999_999}, 891 {"2021-09-29T16:04:33.0123456789Z", 12_345_678}, 892 // 11 digits, truncates 893 {"2021-09-29T16:04:33.10000000000Z", 100_000_000}, 894 {"2021-09-29T16:04:33.00123456789Z", 1_234_567}, 895 // 12 digits, truncates 896 {"2021-09-29T16:04:33.000123456789Z", 123_456}, 897 // 15 digits, truncates 898 {"2021-09-29T16:04:33.9999999999999999Z", 999_999_999}, 899 } 900 901 // Issue 48685 and 54567. 902 func TestParseFractionalSecondsLongerThanNineDigits(t *testing.T) { 903 for _, tt := range longFractionalDigitsTests { 904 for _, format := range []string{RFC3339, RFC3339Nano} { 905 tm, err := Parse(format, tt.value) 906 if err != nil { 907 t.Errorf("Parse(%q, %q) error: %v", format, tt.value, err) 908 continue 909 } 910 if got := tm.Nanosecond(); got != tt.want { 911 t.Errorf("Parse(%q, %q) = got %d, want %d", format, tt.value, got, tt.want) 912 } 913 } 914 } 915 } 916 917 func FuzzFormatRFC3339(f *testing.F) { 918 for _, ts := range [][2]int64{ 919 {math.MinInt64, math.MinInt64}, // 292277026304-08-26T15:42:51Z 920 {-62167219200, 0}, // 0000-01-01T00:00:00Z 921 {1661201140, 676836973}, // 2022-08-22T20:45:40.676836973Z 922 {253402300799, 999999999}, // 9999-12-31T23:59:59.999999999Z 923 {math.MaxInt64, math.MaxInt64}, // -292277022365-05-08T08:17:07Z 924 } { 925 f.Add(ts[0], ts[1], true, false, 0) 926 f.Add(ts[0], ts[1], false, true, 0) 927 for _, offset := range []int{0, 60, 60 * 60, 99*60*60 + 99*60, 123456789} { 928 f.Add(ts[0], ts[1], false, false, -offset) 929 f.Add(ts[0], ts[1], false, false, +offset) 930 } 931 } 932 933 f.Fuzz(func(t *testing.T, sec, nsec int64, useUTC, useLocal bool, tzOffset int) { 934 var loc *Location 935 switch { 936 case useUTC: 937 loc = UTC 938 case useLocal: 939 loc = Local 940 default: 941 loc = FixedZone("", tzOffset) 942 } 943 ts := Unix(sec, nsec).In(loc) 944 945 got := AppendFormatRFC3339(ts, nil, false) 946 want := AppendFormatAny(ts, nil, RFC3339) 947 if !bytes.Equal(got, want) { 948 t.Errorf("Format(%s, RFC3339) mismatch:\n\tgot: %s\n\twant: %s", ts, got, want) 949 } 950 951 gotNanos := AppendFormatRFC3339(ts, nil, true) 952 wantNanos := AppendFormatAny(ts, nil, RFC3339Nano) 953 if !bytes.Equal(got, want) { 954 t.Errorf("Format(%s, RFC3339Nano) mismatch:\n\tgot: %s\n\twant: %s", ts, gotNanos, wantNanos) 955 } 956 }) 957 } 958 959 func FuzzParseRFC3339(f *testing.F) { 960 for _, tt := range formatTests { 961 f.Add(tt.result) 962 } 963 for _, tt := range parseTests { 964 f.Add(tt.value) 965 } 966 for _, tt := range parseErrorTests { 967 f.Add(tt.value) 968 } 969 for _, tt := range longFractionalDigitsTests { 970 f.Add(tt.value) 971 } 972 973 f.Fuzz(func(t *testing.T, s string) { 974 // equalTime is like time.Time.Equal, but also compares the time zone. 975 equalTime := func(t1, t2 Time) bool { 976 name1, offset1 := t1.Zone() 977 name2, offset2 := t2.Zone() 978 return t1.Equal(t2) && name1 == name2 && offset1 == offset2 979 } 980 981 for _, tz := range []*Location{UTC, Local} { 982 // Parsing as RFC3339 or RFC3339Nano should be identical. 983 t1, err1 := ParseAny(RFC3339, s, UTC, tz) 984 t2, err2 := ParseAny(RFC3339Nano, s, UTC, tz) 985 switch { 986 case (err1 == nil) != (err2 == nil): 987 t.Fatalf("ParseAny(%q) error mismatch:\n\tgot: %v\n\twant: %v", s, err1, err2) 988 case !equalTime(t1, t2): 989 t.Fatalf("ParseAny(%q) value mismatch:\n\tgot: %v\n\twant: %v", s, t1, t2) 990 } 991 992 // TODO(https://go.dev/issue/54580): 993 // Remove these checks after ParseAny rejects all invalid RFC 3339. 994 if err1 == nil { 995 num2 := func(s string) byte { return 10*(s[0]-'0') + (s[1] - '0') } 996 switch { 997 case len(s) > 12 && s[12] == ':': 998 t.Skipf("ParseAny(%q) incorrectly allows single-digit hour fields", s) 999 case len(s) > 19 && s[19] == ',': 1000 t.Skipf("ParseAny(%q) incorrectly allows comma as sub-second separator", s) 1001 case !strings.HasSuffix(s, "Z") && len(s) > 4 && (num2(s[len(s)-5:]) >= 24 || num2(s[len(s)-2:]) >= 60): 1002 t.Skipf("ParseAny(%q) incorrectly allows out-of-range zone offset", s) 1003 } 1004 } 1005 1006 // Customized parser should be identical to general parser. 1007 switch got, ok := ParseRFC3339(s, tz); { 1008 case ok != (err1 == nil): 1009 t.Fatalf("ParseRFC3339(%q) error mismatch:\n\tgot: %v\n\twant: %v", s, ok, err1 == nil) 1010 case !equalTime(got, t1): 1011 t.Fatalf("ParseRFC3339(%q) value mismatch:\n\tgot: %v\n\twant: %v", s, got, t2) 1012 } 1013 } 1014 }) 1015 }