github.com/embeddedgo/x@v0.0.6-0.20191217015414-d79a36f562e7/time/format.go (about) 1 // Copyright 2010 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 6 7 import ( 8 "errors" 9 ) 10 11 // These are predefined layouts for use in Time.Format and time.Parse. 12 // The reference time used in the layouts is the specific time: 13 // Mon Jan 2 15:04:05 MST 2006 14 // which is Unix time 1136239445. Since MST is GMT-0700, 15 // the reference time can be thought of as 16 // 01/02 03:04:05PM '06 -0700 17 // To define your own format, write down what the reference time would look 18 // like formatted your way; see the values of constants like ANSIC, 19 // StampMicro or Kitchen for examples. The model is to demonstrate what the 20 // reference time looks like so that the Format and Parse methods can apply 21 // the same transformation to a general time value. 22 // 23 // Some valid layouts are invalid time values for time.Parse, due to formats 24 // such as _ for space padding and Z for zone information. 25 // 26 // Within the format string, an underscore _ represents a space that may be 27 // replaced by a digit if the following number (a day) has two digits; for 28 // compatibility with fixed-width Unix time formats. 29 // 30 // A decimal point followed by one or more zeros represents a fractional 31 // second, printed to the given number of decimal places. A decimal point 32 // followed by one or more nines represents a fractional second, printed to 33 // the given number of decimal places, with trailing zeros removed. 34 // When parsing (only), the input may contain a fractional second 35 // field immediately after the seconds field, even if the layout does not 36 // signify its presence. In that case a decimal point followed by a maximal 37 // series of digits is parsed as a fractional second. 38 // 39 // Numeric time zone offsets format as follows: 40 // -0700 ±hhmm 41 // -07:00 ±hh:mm 42 // -07 ±hh 43 // Replacing the sign in the format with a Z triggers 44 // the ISO 8601 behavior of printing Z instead of an 45 // offset for the UTC zone. Thus: 46 // Z0700 Z or ±hhmm 47 // Z07:00 Z or ±hh:mm 48 // Z07 Z or ±hh 49 // 50 // The recognized day of week formats are "Mon" and "Monday". 51 // The recognized month formats are "Jan" and "January". 52 // 53 // The formats 2, _2, and 02 are unpadded, space-padded, and zero-padded 54 // day of month. The formats __2 and 002 are space-padded and zero-padded 55 // three-character day of year; there is no unpadded day of year format. 56 // 57 // Text in the format string that is not recognized as part of the reference 58 // time is echoed verbatim during Format and expected to appear verbatim 59 // in the input to Parse. 60 // 61 // The executable example for Time.Format demonstrates the working 62 // of the layout string in detail and is a good reference. 63 // 64 // Note that the RFC822, RFC850, and RFC1123 formats should be applied 65 // only to local times. Applying them to UTC times will use "UTC" as the 66 // time zone abbreviation, while strictly speaking those RFCs require the 67 // use of "GMT" in that case. 68 // In general RFC1123Z should be used instead of RFC1123 for servers 69 // that insist on that format, and RFC3339 should be preferred for new protocols. 70 // RFC3339, RFC822, RFC822Z, RFC1123, and RFC1123Z are useful for formatting; 71 // when used with time.Parse they do not accept all the time formats 72 // permitted by the RFCs. 73 // The RFC3339Nano format removes trailing zeros from the seconds field 74 // and thus may not sort correctly once formatted. 75 const ( 76 ANSIC = "Mon Jan _2 15:04:05 2006" 77 UnixDate = "Mon Jan _2 15:04:05 MST 2006" 78 RubyDate = "Mon Jan 02 15:04:05 -0700 2006" 79 RFC822 = "02 Jan 06 15:04 MST" 80 RFC822Z = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone 81 RFC850 = "Monday, 02-Jan-06 15:04:05 MST" 82 RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST" 83 RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone 84 RFC3339 = "2006-01-02T15:04:05Z07:00" 85 RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00" 86 Kitchen = "3:04PM" 87 // Handy time stamps. 88 Stamp = "Jan _2 15:04:05" 89 StampMilli = "Jan _2 15:04:05.000" 90 StampMicro = "Jan _2 15:04:05.000000" 91 StampNano = "Jan _2 15:04:05.000000000" 92 ) 93 94 const ( 95 _ = iota 96 stdLongMonth = iota + stdNeedDate // "January" 97 stdMonth // "Jan" 98 stdNumMonth // "1" 99 stdZeroMonth // "01" 100 stdLongWeekDay // "Monday" 101 stdWeekDay // "Mon" 102 stdDay // "2" 103 stdUnderDay // "_2" 104 stdZeroDay // "02" 105 stdUnderYearDay // "__2" 106 stdZeroYearDay // "002" 107 stdHour = iota + stdNeedClock // "15" 108 stdHour12 // "3" 109 stdZeroHour12 // "03" 110 stdMinute // "4" 111 stdZeroMinute // "04" 112 stdSecond // "5" 113 stdZeroSecond // "05" 114 stdLongYear = iota + stdNeedDate // "2006" 115 stdYear // "06" 116 stdPM = iota + stdNeedClock // "PM" 117 stdpm // "pm" 118 stdTZ = iota // "MST" 119 stdISO8601TZ // "Z0700" // prints Z for UTC 120 stdISO8601SecondsTZ // "Z070000" 121 stdISO8601ShortTZ // "Z07" 122 stdISO8601ColonTZ // "Z07:00" // prints Z for UTC 123 stdISO8601ColonSecondsTZ // "Z07:00:00" 124 stdNumTZ // "-0700" // always numeric 125 stdNumSecondsTz // "-070000" 126 stdNumShortTZ // "-07" // always numeric 127 stdNumColonTZ // "-07:00" // always numeric 128 stdNumColonSecondsTZ // "-07:00:00" 129 stdFracSecond0 // ".0", ".00", ... , trailing zeros included 130 stdFracSecond9 // ".9", ".99", ..., trailing zeros omitted 131 132 stdNeedDate = 1 << 8 // need month, day, year 133 stdNeedClock = 2 << 8 // need hour, minute, second 134 stdArgShift = 16 // extra argument in high bits, above low stdArgShift 135 stdMask = 1<<stdArgShift - 1 // mask out argument 136 ) 137 138 // std0x records the std values for "01", "02", ..., "06". 139 var std0x = [...]int{stdZeroMonth, stdZeroDay, stdZeroHour12, stdZeroMinute, stdZeroSecond, stdYear} 140 141 // startsWithLowerCase reports whether the string has a lower-case letter at the beginning. 142 // Its purpose is to prevent matching strings like "Month" when looking for "Mon". 143 func startsWithLowerCase(str string) bool { 144 if len(str) == 0 { 145 return false 146 } 147 c := str[0] 148 return 'a' <= c && c <= 'z' 149 } 150 151 // nextStdChunk finds the first occurrence of a std string in 152 // layout and returns the text before, the std string, and the text after. 153 func nextStdChunk(layout string) (prefix string, std int, suffix string) { 154 for i := 0; i < len(layout); i++ { 155 switch c := int(layout[i]); c { 156 case 'J': // January, Jan 157 if len(layout) >= i+3 && layout[i:i+3] == "Jan" { 158 if len(layout) >= i+7 && layout[i:i+7] == "January" { 159 return layout[0:i], stdLongMonth, layout[i+7:] 160 } 161 if !startsWithLowerCase(layout[i+3:]) { 162 return layout[0:i], stdMonth, layout[i+3:] 163 } 164 } 165 166 case 'M': // Monday, Mon, MST 167 if len(layout) >= i+3 { 168 if layout[i:i+3] == "Mon" { 169 if len(layout) >= i+6 && layout[i:i+6] == "Monday" { 170 return layout[0:i], stdLongWeekDay, layout[i+6:] 171 } 172 if !startsWithLowerCase(layout[i+3:]) { 173 return layout[0:i], stdWeekDay, layout[i+3:] 174 } 175 } 176 if layout[i:i+3] == "MST" { 177 return layout[0:i], stdTZ, layout[i+3:] 178 } 179 } 180 181 case '0': // 01, 02, 03, 04, 05, 06, 002 182 if len(layout) >= i+2 && '1' <= layout[i+1] && layout[i+1] <= '6' { 183 return layout[0:i], std0x[layout[i+1]-'1'], layout[i+2:] 184 } 185 if len(layout) >= i+3 && layout[i+1] == '0' && layout[i+2] == '2' { 186 return layout[0:i], stdZeroYearDay, layout[i+3:] 187 } 188 189 case '1': // 15, 1 190 if len(layout) >= i+2 && layout[i+1] == '5' { 191 return layout[0:i], stdHour, layout[i+2:] 192 } 193 return layout[0:i], stdNumMonth, layout[i+1:] 194 195 case '2': // 2006, 2 196 if len(layout) >= i+4 && layout[i:i+4] == "2006" { 197 return layout[0:i], stdLongYear, layout[i+4:] 198 } 199 return layout[0:i], stdDay, layout[i+1:] 200 201 case '_': // _2, _2006, __2 202 if len(layout) >= i+2 && layout[i+1] == '2' { 203 //_2006 is really a literal _, followed by stdLongYear 204 if len(layout) >= i+5 && layout[i+1:i+5] == "2006" { 205 return layout[0 : i+1], stdLongYear, layout[i+5:] 206 } 207 return layout[0:i], stdUnderDay, layout[i+2:] 208 } 209 if len(layout) >= i+3 && layout[i+1] == '_' && layout[i+2] == '2' { 210 return layout[0:i], stdUnderYearDay, layout[i+3:] 211 } 212 213 case '3': 214 return layout[0:i], stdHour12, layout[i+1:] 215 216 case '4': 217 return layout[0:i], stdMinute, layout[i+1:] 218 219 case '5': 220 return layout[0:i], stdSecond, layout[i+1:] 221 222 case 'P': // PM 223 if len(layout) >= i+2 && layout[i+1] == 'M' { 224 return layout[0:i], stdPM, layout[i+2:] 225 } 226 227 case 'p': // pm 228 if len(layout) >= i+2 && layout[i+1] == 'm' { 229 return layout[0:i], stdpm, layout[i+2:] 230 } 231 232 case '-': // -070000, -07:00:00, -0700, -07:00, -07 233 if len(layout) >= i+7 && layout[i:i+7] == "-070000" { 234 return layout[0:i], stdNumSecondsTz, layout[i+7:] 235 } 236 if len(layout) >= i+9 && layout[i:i+9] == "-07:00:00" { 237 return layout[0:i], stdNumColonSecondsTZ, layout[i+9:] 238 } 239 if len(layout) >= i+5 && layout[i:i+5] == "-0700" { 240 return layout[0:i], stdNumTZ, layout[i+5:] 241 } 242 if len(layout) >= i+6 && layout[i:i+6] == "-07:00" { 243 return layout[0:i], stdNumColonTZ, layout[i+6:] 244 } 245 if len(layout) >= i+3 && layout[i:i+3] == "-07" { 246 return layout[0:i], stdNumShortTZ, layout[i+3:] 247 } 248 249 case 'Z': // Z070000, Z07:00:00, Z0700, Z07:00, 250 if len(layout) >= i+7 && layout[i:i+7] == "Z070000" { 251 return layout[0:i], stdISO8601SecondsTZ, layout[i+7:] 252 } 253 if len(layout) >= i+9 && layout[i:i+9] == "Z07:00:00" { 254 return layout[0:i], stdISO8601ColonSecondsTZ, layout[i+9:] 255 } 256 if len(layout) >= i+5 && layout[i:i+5] == "Z0700" { 257 return layout[0:i], stdISO8601TZ, layout[i+5:] 258 } 259 if len(layout) >= i+6 && layout[i:i+6] == "Z07:00" { 260 return layout[0:i], stdISO8601ColonTZ, layout[i+6:] 261 } 262 if len(layout) >= i+3 && layout[i:i+3] == "Z07" { 263 return layout[0:i], stdISO8601ShortTZ, layout[i+3:] 264 } 265 266 case '.': // .000 or .999 - repeated digits for fractional seconds. 267 if i+1 < len(layout) && (layout[i+1] == '0' || layout[i+1] == '9') { 268 ch := layout[i+1] 269 j := i + 1 270 for j < len(layout) && layout[j] == ch { 271 j++ 272 } 273 // String of digits must end here - only fractional second is all digits. 274 if !isDigit(layout, j) { 275 std := stdFracSecond0 276 if layout[i+1] == '9' { 277 std = stdFracSecond9 278 } 279 std |= (j - (i + 1)) << stdArgShift 280 return layout[0:i], std, layout[j:] 281 } 282 } 283 } 284 } 285 return layout, 0, "" 286 } 287 288 var longDayNames = []string{ 289 "Sunday", 290 "Monday", 291 "Tuesday", 292 "Wednesday", 293 "Thursday", 294 "Friday", 295 "Saturday", 296 } 297 298 var shortDayNames = []string{ 299 "Sun", 300 "Mon", 301 "Tue", 302 "Wed", 303 "Thu", 304 "Fri", 305 "Sat", 306 } 307 308 var shortMonthNames = []string{ 309 "Jan", 310 "Feb", 311 "Mar", 312 "Apr", 313 "May", 314 "Jun", 315 "Jul", 316 "Aug", 317 "Sep", 318 "Oct", 319 "Nov", 320 "Dec", 321 } 322 323 var longMonthNames = []string{ 324 "January", 325 "February", 326 "March", 327 "April", 328 "May", 329 "June", 330 "July", 331 "August", 332 "September", 333 "October", 334 "November", 335 "December", 336 } 337 338 // match reports whether s1 and s2 match ignoring case. 339 // It is assumed s1 and s2 are the same length. 340 func match(s1, s2 string) bool { 341 for i := 0; i < len(s1); i++ { 342 c1 := s1[i] 343 c2 := s2[i] 344 if c1 != c2 { 345 // Switch to lower-case; 'a'-'A' is known to be a single bit. 346 c1 |= 'a' - 'A' 347 c2 |= 'a' - 'A' 348 if c1 != c2 || c1 < 'a' || c1 > 'z' { 349 return false 350 } 351 } 352 } 353 return true 354 } 355 356 func lookup(tab []string, val string) (int, string, error) { 357 for i, v := range tab { 358 if len(val) >= len(v) && match(val[0:len(v)], v) { 359 return i, val[len(v):], nil 360 } 361 } 362 return -1, val, errBad 363 } 364 365 // appendInt appends the decimal form of x to b and returns the result. 366 // If the decimal form (excluding sign) is shorter than width, the result is padded with leading 0's. 367 // Duplicates functionality in strconv, but avoids dependency. 368 func appendInt(b []byte, x int, width int) []byte { 369 u := uint(x) 370 if x < 0 { 371 b = append(b, '-') 372 u = uint(-x) 373 } 374 375 // Assemble decimal in reverse order. 376 var buf [20]byte 377 i := len(buf) 378 for u >= 10 { 379 i-- 380 q := u / 10 381 buf[i] = byte('0' + u - q*10) 382 u = q 383 } 384 i-- 385 buf[i] = byte('0' + u) 386 387 // Add 0-padding. 388 for w := len(buf) - i; w < width; w++ { 389 b = append(b, '0') 390 } 391 392 return append(b, buf[i:]...) 393 } 394 395 // Never printed, just needs to be non-nil for return by atoi. 396 var atoiError = errors.New("time: invalid number") 397 398 // Duplicates functionality in strconv, but avoids dependency. 399 func atoi(s string) (x int, err error) { 400 neg := false 401 if s != "" && (s[0] == '-' || s[0] == '+') { 402 neg = s[0] == '-' 403 s = s[1:] 404 } 405 q, rem, err := leadingInt(s) 406 x = int(q) 407 if err != nil || rem != "" { 408 return 0, atoiError 409 } 410 if neg { 411 x = -x 412 } 413 return x, nil 414 } 415 416 // formatNano appends a fractional second, as nanoseconds, to b 417 // and returns the result. 418 func formatNano(b []byte, nanosec uint, n int, trim bool) []byte { 419 u := nanosec 420 var buf [9]byte 421 for start := len(buf); start > 0; { 422 start-- 423 buf[start] = byte(u%10 + '0') 424 u /= 10 425 } 426 427 if n > 9 { 428 n = 9 429 } 430 if trim { 431 for n > 0 && buf[n-1] == '0' { 432 n-- 433 } 434 if n == 0 { 435 return b 436 } 437 } 438 b = append(b, '.') 439 return append(b, buf[:n]...) 440 } 441 442 // String returns the time formatted using the format string 443 // "2006-01-02 15:04:05.999999999 -0700 MST" 444 // 445 // If the time has a monotonic clock reading, the returned string 446 // includes a final field "m=±<value>", where value is the monotonic 447 // clock reading formatted as a decimal number of seconds. 448 // 449 // The returned string is meant for debugging; for a stable serialized 450 // representation, use t.MarshalText, t.MarshalBinary, or t.Format 451 // with an explicit format string. 452 func (t Time) String() string { 453 s := t.Format("2006-01-02 15:04:05.999999999 -0700 MST") 454 455 // Format monotonic clock reading as m=±ddd.nnnnnnnnn. 456 if t.wall&hasMonotonic != 0 { 457 m2 := uint64(t.ext) 458 sign := byte('+') 459 if t.ext < 0 { 460 sign = '-' 461 m2 = -m2 462 } 463 m1, m2 := m2/1e9, m2%1e9 464 m0, m1 := m1/1e9, m1%1e9 465 var buf []byte 466 buf = append(buf, " m="...) 467 buf = append(buf, sign) 468 wid := 0 469 if m0 != 0 { 470 buf = appendInt(buf, int(m0), 0) 471 wid = 9 472 } 473 buf = appendInt(buf, int(m1), wid) 474 buf = append(buf, '.') 475 buf = appendInt(buf, int(m2), 9) 476 s += string(buf) 477 } 478 return s 479 } 480 481 // Format returns a textual representation of the time value formatted 482 // according to layout, which defines the format by showing how the reference 483 // time, defined to be 484 // Mon Jan 2 15:04:05 -0700 MST 2006 485 // would be displayed if it were the value; it serves as an example of the 486 // desired output. The same display rules will then be applied to the time 487 // value. 488 // 489 // A fractional second is represented by adding a period and zeros 490 // to the end of the seconds section of layout string, as in "15:04:05.000" 491 // to format a time stamp with millisecond precision. 492 // 493 // Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard 494 // and convenient representations of the reference time. For more information 495 // about the formats and the definition of the reference time, see the 496 // documentation for ANSIC and the other constants defined by this package. 497 func (t Time) Format(layout string) string { 498 const bufSize = 64 499 var b []byte 500 max := len(layout) + 10 501 if max < bufSize { 502 var buf [bufSize]byte 503 b = buf[:0] 504 } else { 505 b = make([]byte, 0, max) 506 } 507 b = t.AppendFormat(b, layout) 508 return string(b) 509 } 510 511 // AppendFormat is like Format but appends the textual 512 // representation to b and returns the extended buffer. 513 func (t Time) AppendFormat(b []byte, layout string) []byte { 514 var ( 515 name, offset, abs = t.locabs() 516 517 year int = -1 518 month Month 519 day int 520 yday int 521 hour int = -1 522 min int 523 sec int 524 ) 525 // Each iteration generates one std value. 526 for layout != "" { 527 prefix, std, suffix := nextStdChunk(layout) 528 if prefix != "" { 529 b = append(b, prefix...) 530 } 531 if std == 0 { 532 break 533 } 534 layout = suffix 535 536 // Compute year, month, day if needed. 537 if year < 0 && std&stdNeedDate != 0 { 538 year, month, day, yday = absDate(abs, true) 539 yday++ 540 } 541 542 // Compute hour, minute, second if needed. 543 if hour < 0 && std&stdNeedClock != 0 { 544 hour, min, sec = absClock(abs) 545 } 546 547 switch std & stdMask { 548 case stdYear: 549 y := year 550 if y < 0 { 551 y = -y 552 } 553 b = appendInt(b, y%100, 2) 554 case stdLongYear: 555 b = appendInt(b, year, 4) 556 case stdMonth: 557 b = append(b, month.String()[:3]...) 558 case stdLongMonth: 559 m := month.String() 560 b = append(b, m...) 561 case stdNumMonth: 562 b = appendInt(b, int(month), 0) 563 case stdZeroMonth: 564 b = appendInt(b, int(month), 2) 565 case stdWeekDay: 566 b = append(b, absWeekday(abs).String()[:3]...) 567 case stdLongWeekDay: 568 s := absWeekday(abs).String() 569 b = append(b, s...) 570 case stdDay: 571 b = appendInt(b, day, 0) 572 case stdUnderDay: 573 if day < 10 { 574 b = append(b, ' ') 575 } 576 b = appendInt(b, day, 0) 577 case stdZeroDay: 578 b = appendInt(b, day, 2) 579 case stdUnderYearDay: 580 if yday < 100 { 581 b = append(b, ' ') 582 if yday < 10 { 583 b = append(b, ' ') 584 } 585 } 586 b = appendInt(b, yday, 0) 587 case stdZeroYearDay: 588 b = appendInt(b, yday, 3) 589 case stdHour: 590 b = appendInt(b, hour, 2) 591 case stdHour12: 592 // Noon is 12PM, midnight is 12AM. 593 hr := hour % 12 594 if hr == 0 { 595 hr = 12 596 } 597 b = appendInt(b, hr, 0) 598 case stdZeroHour12: 599 // Noon is 12PM, midnight is 12AM. 600 hr := hour % 12 601 if hr == 0 { 602 hr = 12 603 } 604 b = appendInt(b, hr, 2) 605 case stdMinute: 606 b = appendInt(b, min, 0) 607 case stdZeroMinute: 608 b = appendInt(b, min, 2) 609 case stdSecond: 610 b = appendInt(b, sec, 0) 611 case stdZeroSecond: 612 b = appendInt(b, sec, 2) 613 case stdPM: 614 if hour >= 12 { 615 b = append(b, "PM"...) 616 } else { 617 b = append(b, "AM"...) 618 } 619 case stdpm: 620 if hour >= 12 { 621 b = append(b, "pm"...) 622 } else { 623 b = append(b, "am"...) 624 } 625 case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumColonTZ, stdNumSecondsTz, stdNumShortTZ, stdNumColonSecondsTZ: 626 // Ugly special case. We cheat and take the "Z" variants 627 // to mean "the time zone as formatted for ISO 8601". 628 if offset == 0 && (std == stdISO8601TZ || std == stdISO8601ColonTZ || std == stdISO8601SecondsTZ || std == stdISO8601ShortTZ || std == stdISO8601ColonSecondsTZ) { 629 b = append(b, 'Z') 630 break 631 } 632 zone := offset / 60 // convert to minutes 633 absoffset := offset 634 if zone < 0 { 635 b = append(b, '-') 636 zone = -zone 637 absoffset = -absoffset 638 } else { 639 b = append(b, '+') 640 } 641 b = appendInt(b, zone/60, 2) 642 if std == stdISO8601ColonTZ || std == stdNumColonTZ || std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ { 643 b = append(b, ':') 644 } 645 if std != stdNumShortTZ && std != stdISO8601ShortTZ { 646 b = appendInt(b, zone%60, 2) 647 } 648 649 // append seconds if appropriate 650 if std == stdISO8601SecondsTZ || std == stdNumSecondsTz || std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ { 651 if std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ { 652 b = append(b, ':') 653 } 654 b = appendInt(b, absoffset%60, 2) 655 } 656 657 case stdTZ: 658 if name != "" { 659 b = append(b, name...) 660 break 661 } 662 // No time zone known for this time, but we must print one. 663 // Use the -0700 format. 664 zone := offset / 60 // convert to minutes 665 if zone < 0 { 666 b = append(b, '-') 667 zone = -zone 668 } else { 669 b = append(b, '+') 670 } 671 b = appendInt(b, zone/60, 2) 672 b = appendInt(b, zone%60, 2) 673 case stdFracSecond0, stdFracSecond9: 674 b = formatNano(b, uint(t.Nanosecond()), std>>stdArgShift, std&stdMask == stdFracSecond9) 675 } 676 } 677 return b 678 } 679 680 var errBad = errors.New("bad value for field") // placeholder not passed to user 681 682 // ParseError describes a problem parsing a time string. 683 type ParseError struct { 684 Layout string 685 Value string 686 LayoutElem string 687 ValueElem string 688 Message string 689 } 690 691 func quote(s string) string { 692 return "\"" + s + "\"" 693 } 694 695 // Error returns the string representation of a ParseError. 696 func (e *ParseError) Error() string { 697 if e.Message == "" { 698 return "parsing time " + 699 quote(e.Value) + " as " + 700 quote(e.Layout) + ": cannot parse " + 701 quote(e.ValueElem) + " as " + 702 quote(e.LayoutElem) 703 } 704 return "parsing time " + 705 quote(e.Value) + e.Message 706 } 707 708 // isDigit reports whether s[i] is in range and is a decimal digit. 709 func isDigit(s string, i int) bool { 710 if len(s) <= i { 711 return false 712 } 713 c := s[i] 714 return '0' <= c && c <= '9' 715 } 716 717 // getnum parses s[0:1] or s[0:2] (fixed forces s[0:2]) 718 // as a decimal integer and returns the integer and the 719 // remainder of the string. 720 func getnum(s string, fixed bool) (int, string, error) { 721 if !isDigit(s, 0) { 722 return 0, s, errBad 723 } 724 if !isDigit(s, 1) { 725 if fixed { 726 return 0, s, errBad 727 } 728 return int(s[0] - '0'), s[1:], nil 729 } 730 return int(s[0]-'0')*10 + int(s[1]-'0'), s[2:], nil 731 } 732 733 // getnum3 parses s[0:1], s[0:2], or s[0:3] (fixed forces s[0:3]) 734 // as a decimal integer and returns the integer and the remainder 735 // of the string. 736 func getnum3(s string, fixed bool) (int, string, error) { 737 var n, i int 738 for i = 0; i < 3 && isDigit(s, i); i++ { 739 n = n*10 + int(s[i]-'0') 740 } 741 if i == 0 || fixed && i != 3 { 742 return 0, s, errBad 743 } 744 return n, s[i:], nil 745 } 746 747 func cutspace(s string) string { 748 for len(s) > 0 && s[0] == ' ' { 749 s = s[1:] 750 } 751 return s 752 } 753 754 // skip removes the given prefix from value, 755 // treating runs of space characters as equivalent. 756 func skip(value, prefix string) (string, error) { 757 for len(prefix) > 0 { 758 if prefix[0] == ' ' { 759 if len(value) > 0 && value[0] != ' ' { 760 return value, errBad 761 } 762 prefix = cutspace(prefix) 763 value = cutspace(value) 764 continue 765 } 766 if len(value) == 0 || value[0] != prefix[0] { 767 return value, errBad 768 } 769 prefix = prefix[1:] 770 value = value[1:] 771 } 772 return value, nil 773 } 774 775 // Parse parses a formatted string and returns the time value it represents. 776 // The layout defines the format by showing how the reference time, 777 // defined to be 778 // Mon Jan 2 15:04:05 -0700 MST 2006 779 // would be interpreted if it were the value; it serves as an example of 780 // the input format. The same interpretation will then be made to the 781 // input string. 782 // 783 // Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard 784 // and convenient representations of the reference time. For more information 785 // about the formats and the definition of the reference time, see the 786 // documentation for ANSIC and the other constants defined by this package. 787 // Also, the executable example for Time.Format demonstrates the working 788 // of the layout string in detail and is a good reference. 789 // 790 // Elements omitted from the value are assumed to be zero or, when 791 // zero is impossible, one, so parsing "3:04pm" returns the time 792 // corresponding to Jan 1, year 0, 15:04:00 UTC (note that because the year is 793 // 0, this time is before the zero Time). 794 // Years must be in the range 0000..9999. The day of the week is checked 795 // for syntax but it is otherwise ignored. 796 // 797 // In the absence of a time zone indicator, Parse returns a time in UTC. 798 // 799 // When parsing a time with a zone offset like -0700, if the offset corresponds 800 // to a time zone used by the current location (Local), then Parse uses that 801 // location and zone in the returned time. Otherwise it records the time as 802 // being in a fabricated location with time fixed at the given zone offset. 803 // 804 // When parsing a time with a zone abbreviation like MST, if the zone abbreviation 805 // has a defined offset in the current location, then that offset is used. 806 // The zone abbreviation "UTC" is recognized as UTC regardless of location. 807 // If the zone abbreviation is unknown, Parse records the time as being 808 // in a fabricated location with the given zone abbreviation and a zero offset. 809 // This choice means that such a time can be parsed and reformatted with the 810 // same layout losslessly, but the exact instant used in the representation will 811 // differ by the actual zone offset. To avoid such problems, prefer time layouts 812 // that use a numeric zone offset, or use ParseInLocation. 813 func Parse(layout, value string) (Time, error) { 814 return parse(layout, value, UTC, Local) 815 } 816 817 // ParseInLocation is like Parse but differs in two important ways. 818 // First, in the absence of time zone information, Parse interprets a time as UTC; 819 // ParseInLocation interprets the time as in the given location. 820 // Second, when given a zone offset or abbreviation, Parse tries to match it 821 // against the Local location; ParseInLocation uses the given location. 822 func ParseInLocation(layout, value string, loc *Location) (Time, error) { 823 return parse(layout, value, loc, loc) 824 } 825 826 func parse(layout, value string, defaultLocation, local *Location) (Time, error) { 827 alayout, avalue := layout, value 828 rangeErrString := "" // set if a value is out of range 829 amSet := false // do we need to subtract 12 from the hour for midnight? 830 pmSet := false // do we need to add 12 to the hour? 831 832 // Time being constructed. 833 var ( 834 year int 835 month int = -1 836 day int = -1 837 yday int = -1 838 hour int 839 min int 840 sec int 841 nsec int 842 z *Location 843 zoneOffset int = -1 844 zoneName string 845 ) 846 847 // Each iteration processes one std value. 848 for { 849 var err error 850 prefix, std, suffix := nextStdChunk(layout) 851 stdstr := layout[len(prefix) : len(layout)-len(suffix)] 852 value, err = skip(value, prefix) 853 if err != nil { 854 return Time{}, &ParseError{alayout, avalue, prefix, value, ""} 855 } 856 if std == 0 { 857 if len(value) != 0 { 858 return Time{}, &ParseError{alayout, avalue, "", value, ": extra text: " + value} 859 } 860 break 861 } 862 layout = suffix 863 var p string 864 switch std & stdMask { 865 case stdYear: 866 if len(value) < 2 { 867 err = errBad 868 break 869 } 870 hold := value 871 p, value = value[0:2], value[2:] 872 year, err = atoi(p) 873 if err != nil { 874 value = hold 875 } else if year >= 69 { // Unix time starts Dec 31 1969 in some time zones 876 year += 1900 877 } else { 878 year += 2000 879 } 880 case stdLongYear: 881 if len(value) < 4 || !isDigit(value, 0) { 882 err = errBad 883 break 884 } 885 p, value = value[0:4], value[4:] 886 year, err = atoi(p) 887 case stdMonth: 888 month, value, err = lookup(shortMonthNames, value) 889 month++ 890 case stdLongMonth: 891 month, value, err = lookup(longMonthNames, value) 892 month++ 893 case stdNumMonth, stdZeroMonth: 894 month, value, err = getnum(value, std == stdZeroMonth) 895 if err == nil && (month <= 0 || 12 < month) { 896 rangeErrString = "month" 897 } 898 case stdWeekDay: 899 // Ignore weekday except for error checking. 900 _, value, err = lookup(shortDayNames, value) 901 case stdLongWeekDay: 902 _, value, err = lookup(longDayNames, value) 903 case stdDay, stdUnderDay, stdZeroDay: 904 if std == stdUnderDay && len(value) > 0 && value[0] == ' ' { 905 value = value[1:] 906 } 907 day, value, err = getnum(value, std == stdZeroDay) 908 // Note that we allow any one- or two-digit day here. 909 // The month, day, year combination is validated after we've completed parsing. 910 case stdUnderYearDay, stdZeroYearDay: 911 for i := 0; i < 2; i++ { 912 if std == stdUnderYearDay && len(value) > 0 && value[0] == ' ' { 913 value = value[1:] 914 } 915 } 916 yday, value, err = getnum3(value, std == stdZeroYearDay) 917 // Note that we allow any one-, two-, or three-digit year-day here. 918 // The year-day, year combination is validated after we've completed parsing. 919 case stdHour: 920 hour, value, err = getnum(value, false) 921 if hour < 0 || 24 <= hour { 922 rangeErrString = "hour" 923 } 924 case stdHour12, stdZeroHour12: 925 hour, value, err = getnum(value, std == stdZeroHour12) 926 if hour < 0 || 12 < hour { 927 rangeErrString = "hour" 928 } 929 case stdMinute, stdZeroMinute: 930 min, value, err = getnum(value, std == stdZeroMinute) 931 if min < 0 || 60 <= min { 932 rangeErrString = "minute" 933 } 934 case stdSecond, stdZeroSecond: 935 sec, value, err = getnum(value, std == stdZeroSecond) 936 if sec < 0 || 60 <= sec { 937 rangeErrString = "second" 938 break 939 } 940 // Special case: do we have a fractional second but no 941 // fractional second in the format? 942 if len(value) >= 2 && value[0] == '.' && isDigit(value, 1) { 943 _, std, _ = nextStdChunk(layout) 944 std &= stdMask 945 if std == stdFracSecond0 || std == stdFracSecond9 { 946 // Fractional second in the layout; proceed normally 947 break 948 } 949 // No fractional second in the layout but we have one in the input. 950 n := 2 951 for ; n < len(value) && isDigit(value, n); n++ { 952 } 953 nsec, rangeErrString, err = parseNanoseconds(value, n) 954 value = value[n:] 955 } 956 case stdPM: 957 if len(value) < 2 { 958 err = errBad 959 break 960 } 961 p, value = value[0:2], value[2:] 962 switch p { 963 case "PM": 964 pmSet = true 965 case "AM": 966 amSet = true 967 default: 968 err = errBad 969 } 970 case stdpm: 971 if len(value) < 2 { 972 err = errBad 973 break 974 } 975 p, value = value[0:2], value[2:] 976 switch p { 977 case "pm": 978 pmSet = true 979 case "am": 980 amSet = true 981 default: 982 err = errBad 983 } 984 case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ: 985 if (std == stdISO8601TZ || std == stdISO8601ShortTZ || std == stdISO8601ColonTZ) && len(value) >= 1 && value[0] == 'Z' { 986 value = value[1:] 987 z = UTC 988 break 989 } 990 var sign, hour, min, seconds string 991 if std == stdISO8601ColonTZ || std == stdNumColonTZ { 992 if len(value) < 6 { 993 err = errBad 994 break 995 } 996 if value[3] != ':' { 997 err = errBad 998 break 999 } 1000 sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], "00", value[6:] 1001 } else if std == stdNumShortTZ || std == stdISO8601ShortTZ { 1002 if len(value) < 3 { 1003 err = errBad 1004 break 1005 } 1006 sign, hour, min, seconds, value = value[0:1], value[1:3], "00", "00", value[3:] 1007 } else if std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ { 1008 if len(value) < 9 { 1009 err = errBad 1010 break 1011 } 1012 if value[3] != ':' || value[6] != ':' { 1013 err = errBad 1014 break 1015 } 1016 sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], value[7:9], value[9:] 1017 } else if std == stdISO8601SecondsTZ || std == stdNumSecondsTz { 1018 if len(value) < 7 { 1019 err = errBad 1020 break 1021 } 1022 sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], value[5:7], value[7:] 1023 } else { 1024 if len(value) < 5 { 1025 err = errBad 1026 break 1027 } 1028 sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], "00", value[5:] 1029 } 1030 var hr, mm, ss int 1031 hr, err = atoi(hour) 1032 if err == nil { 1033 mm, err = atoi(min) 1034 } 1035 if err == nil { 1036 ss, err = atoi(seconds) 1037 } 1038 zoneOffset = (hr*60+mm)*60 + ss // offset is in seconds 1039 switch sign[0] { 1040 case '+': 1041 case '-': 1042 zoneOffset = -zoneOffset 1043 default: 1044 err = errBad 1045 } 1046 case stdTZ: 1047 // Does it look like a time zone? 1048 if len(value) >= 3 && value[0:3] == "UTC" { 1049 z = UTC 1050 value = value[3:] 1051 break 1052 } 1053 n, ok := parseTimeZone(value) 1054 if !ok { 1055 err = errBad 1056 break 1057 } 1058 zoneName, value = value[:n], value[n:] 1059 1060 case stdFracSecond0: 1061 // stdFracSecond0 requires the exact number of digits as specified in 1062 // the layout. 1063 ndigit := 1 + (std >> stdArgShift) 1064 if len(value) < ndigit { 1065 err = errBad 1066 break 1067 } 1068 nsec, rangeErrString, err = parseNanoseconds(value, ndigit) 1069 value = value[ndigit:] 1070 1071 case stdFracSecond9: 1072 if len(value) < 2 || value[0] != '.' || value[1] < '0' || '9' < value[1] { 1073 // Fractional second omitted. 1074 break 1075 } 1076 // Take any number of digits, even more than asked for, 1077 // because it is what the stdSecond case would do. 1078 i := 0 1079 for i < 9 && i+1 < len(value) && '0' <= value[i+1] && value[i+1] <= '9' { 1080 i++ 1081 } 1082 nsec, rangeErrString, err = parseNanoseconds(value, 1+i) 1083 value = value[1+i:] 1084 } 1085 if rangeErrString != "" { 1086 return Time{}, &ParseError{alayout, avalue, stdstr, value, ": " + rangeErrString + " out of range"} 1087 } 1088 if err != nil { 1089 return Time{}, &ParseError{alayout, avalue, stdstr, value, ""} 1090 } 1091 } 1092 if pmSet && hour < 12 { 1093 hour += 12 1094 } else if amSet && hour == 12 { 1095 hour = 0 1096 } 1097 1098 // Convert yday to day, month. 1099 if yday >= 0 { 1100 var d int 1101 var m int 1102 if isLeap(year) { 1103 if yday == 31+29 { 1104 m = int(February) 1105 d = 29 1106 } else if yday > 31+29 { 1107 yday-- 1108 } 1109 } 1110 if yday < 1 || yday > 365 { 1111 return Time{}, &ParseError{alayout, avalue, "", value, ": day-of-year out of range"} 1112 } 1113 if m == 0 { 1114 m = yday/31 + 1 1115 if int(daysBefore[m]) < yday { 1116 m++ 1117 } 1118 d = yday - int(daysBefore[m-1]) 1119 } 1120 // If month, day already seen, yday's m, d must match. 1121 // Otherwise, set them from m, d. 1122 if month >= 0 && month != m { 1123 return Time{}, &ParseError{alayout, avalue, "", value, ": day-of-year does not match month"} 1124 } 1125 month = m 1126 if day >= 0 && day != d { 1127 return Time{}, &ParseError{alayout, avalue, "", value, ": day-of-year does not match day"} 1128 } 1129 day = d 1130 } else { 1131 if month < 0 { 1132 month = int(January) 1133 } 1134 if day < 0 { 1135 day = 1 1136 } 1137 } 1138 1139 // Validate the day of the month. 1140 if day < 1 || day > daysIn(Month(month), year) { 1141 return Time{}, &ParseError{alayout, avalue, "", value, ": day out of range"} 1142 } 1143 1144 if z != nil { 1145 return Date(year, Month(month), day, hour, min, sec, nsec, z), nil 1146 } 1147 1148 if zoneOffset != -1 { 1149 t := Date(year, Month(month), day, hour, min, sec, nsec, UTC) 1150 t.addSec(-int64(zoneOffset)) 1151 1152 // Look for local zone with the given offset. 1153 // If that zone was in effect at the given time, use it. 1154 name, offset, _, _ := local.lookup(uint64(t.sec() + internalToAbsolute)) 1155 if offset == zoneOffset && (zoneName == "" || name == zoneName) { 1156 t.setLoc(local) 1157 return t, nil 1158 } 1159 1160 // Otherwise create fake zone to record offset. 1161 t.setLoc(FixedZone(zoneName, zoneOffset)) 1162 return t, nil 1163 } 1164 1165 if zoneName != "" { 1166 t := Date(year, Month(month), day, hour, min, sec, nsec, UTC) 1167 // Look for local zone with the given offset. 1168 // If that zone was in effect at the given time, use it. 1169 offset, ok := local.lookupName(zoneName, uint64(t.sec()+internalToAbsolute)) 1170 if ok { 1171 t.addSec(-int64(offset)) 1172 t.setLoc(local) 1173 return t, nil 1174 } 1175 1176 // Otherwise, create fake zone with unknown offset. 1177 if len(zoneName) > 3 && zoneName[:3] == "GMT" { 1178 offset, _ = atoi(zoneName[3:]) // Guaranteed OK by parseGMT. 1179 offset *= 3600 1180 } 1181 t.setLoc(FixedZone(zoneName, offset)) 1182 return t, nil 1183 } 1184 1185 // Otherwise, fall back to default. 1186 return Date(year, Month(month), day, hour, min, sec, nsec, defaultLocation), nil 1187 } 1188 1189 // parseTimeZone parses a time zone string and returns its length. Time zones 1190 // are human-generated and unpredictable. We can't do precise error checking. 1191 // On the other hand, for a correct parse there must be a time zone at the 1192 // beginning of the string, so it's almost always true that there's one 1193 // there. We look at the beginning of the string for a run of upper-case letters. 1194 // If there are more than 5, it's an error. 1195 // If there are 4 or 5 and the last is a T, it's a time zone. 1196 // If there are 3, it's a time zone. 1197 // Otherwise, other than special cases, it's not a time zone. 1198 // GMT is special because it can have an hour offset. 1199 func parseTimeZone(value string) (length int, ok bool) { 1200 if len(value) < 3 { 1201 return 0, false 1202 } 1203 // Special case 1: ChST and MeST are the only zones with a lower-case letter. 1204 if len(value) >= 4 && (value[:4] == "ChST" || value[:4] == "MeST") { 1205 return 4, true 1206 } 1207 // Special case 2: GMT may have an hour offset; treat it specially. 1208 if value[:3] == "GMT" { 1209 length = parseGMT(value) 1210 return length, true 1211 } 1212 // Special Case 3: Some time zones are not named, but have +/-00 format 1213 if value[0] == '+' || value[0] == '-' { 1214 length = parseSignedOffset(value) 1215 ok := length > 0 // parseSignedOffset returns 0 in case of bad input 1216 return length, ok 1217 } 1218 // How many upper-case letters are there? Need at least three, at most five. 1219 var nUpper int 1220 for nUpper = 0; nUpper < 6; nUpper++ { 1221 if nUpper >= len(value) { 1222 break 1223 } 1224 if c := value[nUpper]; c < 'A' || 'Z' < c { 1225 break 1226 } 1227 } 1228 switch nUpper { 1229 case 0, 1, 2, 6: 1230 return 0, false 1231 case 5: // Must end in T to match. 1232 if value[4] == 'T' { 1233 return 5, true 1234 } 1235 case 4: 1236 // Must end in T, except one special case. 1237 if value[3] == 'T' || value[:4] == "WITA" { 1238 return 4, true 1239 } 1240 case 3: 1241 return 3, true 1242 } 1243 return 0, false 1244 } 1245 1246 // parseGMT parses a GMT time zone. The input string is known to start "GMT". 1247 // The function checks whether that is followed by a sign and a number in the 1248 // range -23 through +23 excluding zero. 1249 func parseGMT(value string) int { 1250 value = value[3:] 1251 if len(value) == 0 { 1252 return 3 1253 } 1254 1255 return 3 + parseSignedOffset(value) 1256 } 1257 1258 // parseSignedOffset parses a signed timezone offset (e.g. "+03" or "-04"). 1259 // The function checks for a signed number in the range -23 through +23 excluding zero. 1260 // Returns length of the found offset string or 0 otherwise 1261 func parseSignedOffset(value string) int { 1262 sign := value[0] 1263 if sign != '-' && sign != '+' { 1264 return 0 1265 } 1266 x, rem, err := leadingInt(value[1:]) 1267 1268 // fail if nothing consumed by leadingInt 1269 if err != nil || value[1:] == rem { 1270 return 0 1271 } 1272 if sign == '-' { 1273 x = -x 1274 } 1275 if x < -23 || 23 < x { 1276 return 0 1277 } 1278 return len(value) - len(rem) 1279 } 1280 1281 func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string, err error) { 1282 if value[0] != '.' { 1283 err = errBad 1284 return 1285 } 1286 if ns, err = atoi(value[1:nbytes]); err != nil { 1287 return 1288 } 1289 if ns < 0 || 1e9 <= ns { 1290 rangeErrString = "fractional second" 1291 return 1292 } 1293 // We need nanoseconds, which means scaling by the number 1294 // of missing digits in the format, maximum length 10. If it's 1295 // longer than 10, we won't scale. 1296 scaleDigits := 10 - nbytes 1297 for i := 0; i < scaleDigits; i++ { 1298 ns *= 10 1299 } 1300 return 1301 } 1302 1303 var errLeadingInt = errors.New("time: bad [0-9]*") // never printed 1304 1305 // leadingInt consumes the leading [0-9]* from s. 1306 func leadingInt(s string) (x int64, rem string, err error) { 1307 i := 0 1308 for ; i < len(s); i++ { 1309 c := s[i] 1310 if c < '0' || c > '9' { 1311 break 1312 } 1313 if x > (1<<63-1)/10 { 1314 // overflow 1315 return 0, "", errLeadingInt 1316 } 1317 x = x*10 + int64(c) - '0' 1318 if x < 0 { 1319 // overflow 1320 return 0, "", errLeadingInt 1321 } 1322 } 1323 return x, s[i:], nil 1324 } 1325 1326 // leadingFraction consumes the leading [0-9]* from s. 1327 // It is used only for fractions, so does not return an error on overflow, 1328 // it just stops accumulating precision. 1329 func leadingFraction(s string) (x int64, scale float64, rem string) { 1330 i := 0 1331 scale = 1 1332 overflow := false 1333 for ; i < len(s); i++ { 1334 c := s[i] 1335 if c < '0' || c > '9' { 1336 break 1337 } 1338 if overflow { 1339 continue 1340 } 1341 if x > (1<<63-1)/10 { 1342 // It's possible for overflow to give a positive number, so take care. 1343 overflow = true 1344 continue 1345 } 1346 y := x*10 + int64(c) - '0' 1347 if y < 0 { 1348 overflow = true 1349 continue 1350 } 1351 x = y 1352 scale *= 10 1353 } 1354 return x, scale, s[i:] 1355 } 1356 1357 var unitMap = map[string]int64{ 1358 "ns": int64(Nanosecond), 1359 "us": int64(Microsecond), 1360 "µs": int64(Microsecond), // U+00B5 = micro symbol 1361 "μs": int64(Microsecond), // U+03BC = Greek letter mu 1362 "ms": int64(Millisecond), 1363 "s": int64(Second), 1364 "m": int64(Minute), 1365 "h": int64(Hour), 1366 } 1367 1368 // ParseDuration parses a duration string. 1369 // A duration string is a possibly signed sequence of 1370 // decimal numbers, each with optional fraction and a unit suffix, 1371 // such as "300ms", "-1.5h" or "2h45m". 1372 // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". 1373 func ParseDuration(s string) (Duration, error) { 1374 // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+ 1375 orig := s 1376 var d int64 1377 neg := false 1378 1379 // Consume [-+]? 1380 if s != "" { 1381 c := s[0] 1382 if c == '-' || c == '+' { 1383 neg = c == '-' 1384 s = s[1:] 1385 } 1386 } 1387 // Special case: if all that is left is "0", this is zero. 1388 if s == "0" { 1389 return 0, nil 1390 } 1391 if s == "" { 1392 return 0, errors.New("time: invalid duration " + orig) 1393 } 1394 for s != "" { 1395 var ( 1396 v, f int64 // integers before, after decimal point 1397 scale float64 = 1 // value = v + f/scale 1398 ) 1399 1400 var err error 1401 1402 // The next character must be [0-9.] 1403 if !(s[0] == '.' || '0' <= s[0] && s[0] <= '9') { 1404 return 0, errors.New("time: invalid duration " + orig) 1405 } 1406 // Consume [0-9]* 1407 pl := len(s) 1408 v, s, err = leadingInt(s) 1409 if err != nil { 1410 return 0, errors.New("time: invalid duration " + orig) 1411 } 1412 pre := pl != len(s) // whether we consumed anything before a period 1413 1414 // Consume (\.[0-9]*)? 1415 post := false 1416 if s != "" && s[0] == '.' { 1417 s = s[1:] 1418 pl := len(s) 1419 f, scale, s = leadingFraction(s) 1420 post = pl != len(s) 1421 } 1422 if !pre && !post { 1423 // no digits (e.g. ".s" or "-.s") 1424 return 0, errors.New("time: invalid duration " + orig) 1425 } 1426 1427 // Consume unit. 1428 i := 0 1429 for ; i < len(s); i++ { 1430 c := s[i] 1431 if c == '.' || '0' <= c && c <= '9' { 1432 break 1433 } 1434 } 1435 if i == 0 { 1436 return 0, errors.New("time: missing unit in duration " + orig) 1437 } 1438 u := s[:i] 1439 s = s[i:] 1440 unit, ok := unitMap[u] 1441 if !ok { 1442 return 0, errors.New("time: unknown unit " + u + " in duration " + orig) 1443 } 1444 if v > (1<<63-1)/unit { 1445 // overflow 1446 return 0, errors.New("time: invalid duration " + orig) 1447 } 1448 v *= unit 1449 if f > 0 { 1450 // float64 is needed to be nanosecond accurate for fractions of hours. 1451 // v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit) 1452 v += int64(float64(f) * (float64(unit) / scale)) 1453 if v < 0 { 1454 // overflow 1455 return 0, errors.New("time: invalid duration " + orig) 1456 } 1457 } 1458 d += v 1459 if d < 0 { 1460 // overflow 1461 return 0, errors.New("time: invalid duration " + orig) 1462 } 1463 } 1464 1465 if neg { 1466 d = -d 1467 } 1468 return Duration(d), nil 1469 }