Source file src/pkg/time/format.go
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 "errors" 8 9 // These are predefined layouts for use in Time.Format. 10 // The standard time used in the layouts is: 11 // Mon Jan 2 15:04:05 MST 2006 12 // which is Unix time 1136243045. Since MST is GMT-0700, 13 // the standard time can be thought of as 14 // 01/02 03:04:05PM '06 -0700 15 // To define your own format, write down what the standard time would look 16 // like formatted your way; see the values of constants like ANSIC, 17 // StampMicro or Kitchen for examples. 18 // 19 // Within the format string, an underscore _ represents a space that may be 20 // replaced by a digit if the following number (a day) has two digits; for 21 // compatibility with fixed-width Unix time formats. 22 // 23 // A decimal point followed by one or more zeros represents a fractional 24 // second, printed to the given number of decimal places. A decimal point 25 // followed by one or more nines represents a fractional second, printed to 26 // the given number of decimal places, with trailing zeros removed. 27 // When parsing (only), the input may contain a fractional second 28 // field immediately after the seconds field, even if the layout does not 29 // signify its presence. In that case a decimal point followed by a maximal 30 // series of digits is parsed as a fractional second. 31 // 32 // Numeric time zone offsets format as follows: 33 // -0700 ±hhmm 34 // -07:00 ±hh:mm 35 // Replacing the sign in the format with a Z triggers 36 // the ISO 8601 behavior of printing Z instead of an 37 // offset for the UTC zone. Thus: 38 // Z0700 Z or ±hhmm 39 // Z07:00 Z or ±hh:mm 40 const ( 41 ANSIC = "Mon Jan _2 15:04:05 2006" 42 UnixDate = "Mon Jan _2 15:04:05 MST 2006" 43 RubyDate = "Mon Jan 02 15:04:05 -0700 2006" 44 RFC822 = "02 Jan 06 15:04 MST" 45 RFC822Z = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone 46 RFC850 = "Monday, 02-Jan-06 15:04:05 MST" 47 RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST" 48 RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone 49 RFC3339 = "2006-01-02T15:04:05Z07:00" 50 RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00" 51 Kitchen = "3:04PM" 52 // Handy time stamps. 53 Stamp = "Jan _2 15:04:05" 54 StampMilli = "Jan _2 15:04:05.000" 55 StampMicro = "Jan _2 15:04:05.000000" 56 StampNano = "Jan _2 15:04:05.000000000" 57 ) 58 59 const ( 60 stdLongMonth = "January" 61 stdMonth = "Jan" 62 stdNumMonth = "1" 63 stdZeroMonth = "01" 64 stdLongWeekDay = "Monday" 65 stdWeekDay = "Mon" 66 stdDay = "2" 67 stdUnderDay = "_2" 68 stdZeroDay = "02" 69 stdHour = "15" 70 stdHour12 = "3" 71 stdZeroHour12 = "03" 72 stdMinute = "4" 73 stdZeroMinute = "04" 74 stdSecond = "5" 75 stdZeroSecond = "05" 76 stdLongYear = "2006" 77 stdYear = "06" 78 stdPM = "PM" 79 stdpm = "pm" 80 stdTZ = "MST" 81 stdISO8601TZ = "Z0700" // prints Z for UTC 82 stdISO8601ColonTZ = "Z07:00" // prints Z for UTC 83 stdNumTZ = "-0700" // always numeric 84 stdNumShortTZ = "-07" // always numeric 85 stdNumColonTZ = "-07:00" // always numeric 86 ) 87 88 // nextStdChunk finds the first occurrence of a std string in 89 // layout and returns the text before, the std string, and the text after. 90 func nextStdChunk(layout string) (prefix, std, suffix string) { 91 for i := 0; i < len(layout); i++ { 92 switch layout[i] { 93 case 'J': // January, Jan 94 if len(layout) >= i+7 && layout[i:i+7] == stdLongMonth { 95 return layout[0:i], stdLongMonth, layout[i+7:] 96 } 97 if len(layout) >= i+3 && layout[i:i+3] == stdMonth { 98 return layout[0:i], stdMonth, layout[i+3:] 99 } 100 101 case 'M': // Monday, Mon, MST 102 if len(layout) >= i+6 && layout[i:i+6] == stdLongWeekDay { 103 return layout[0:i], stdLongWeekDay, layout[i+6:] 104 } 105 if len(layout) >= i+3 { 106 if layout[i:i+3] == stdWeekDay { 107 return layout[0:i], stdWeekDay, layout[i+3:] 108 } 109 if layout[i:i+3] == stdTZ { 110 return layout[0:i], stdTZ, layout[i+3:] 111 } 112 } 113 114 case '0': // 01, 02, 03, 04, 05, 06 115 if len(layout) >= i+2 && '1' <= layout[i+1] && layout[i+1] <= '6' { 116 return layout[0:i], layout[i : i+2], layout[i+2:] 117 } 118 119 case '1': // 15, 1 120 if len(layout) >= i+2 && layout[i+1] == '5' { 121 return layout[0:i], stdHour, layout[i+2:] 122 } 123 return layout[0:i], stdNumMonth, layout[i+1:] 124 125 case '2': // 2006, 2 126 if len(layout) >= i+4 && layout[i:i+4] == stdLongYear { 127 return layout[0:i], stdLongYear, layout[i+4:] 128 } 129 return layout[0:i], stdDay, layout[i+1:] 130 131 case '_': // _2 132 if len(layout) >= i+2 && layout[i+1] == '2' { 133 return layout[0:i], stdUnderDay, layout[i+2:] 134 } 135 136 case '3', '4', '5': // 3, 4, 5 137 return layout[0:i], layout[i : i+1], layout[i+1:] 138 139 case 'P': // PM 140 if len(layout) >= i+2 && layout[i+1] == 'M' { 141 return layout[0:i], layout[i : i+2], layout[i+2:] 142 } 143 144 case 'p': // pm 145 if len(layout) >= i+2 && layout[i+1] == 'm' { 146 return layout[0:i], layout[i : i+2], layout[i+2:] 147 } 148 149 case '-': // -0700, -07:00, -07 150 if len(layout) >= i+5 && layout[i:i+5] == stdNumTZ { 151 return layout[0:i], layout[i : i+5], layout[i+5:] 152 } 153 if len(layout) >= i+6 && layout[i:i+6] == stdNumColonTZ { 154 return layout[0:i], layout[i : i+6], layout[i+6:] 155 } 156 if len(layout) >= i+3 && layout[i:i+3] == stdNumShortTZ { 157 return layout[0:i], layout[i : i+3], layout[i+3:] 158 } 159 case 'Z': // Z0700, Z07:00 160 if len(layout) >= i+5 && layout[i:i+5] == stdISO8601TZ { 161 return layout[0:i], layout[i : i+5], layout[i+5:] 162 } 163 if len(layout) >= i+6 && layout[i:i+6] == stdISO8601ColonTZ { 164 return layout[0:i], layout[i : i+6], layout[i+6:] 165 } 166 case '.': // .000 or .999 - repeated digits for fractional seconds. 167 if i+1 < len(layout) && (layout[i+1] == '0' || layout[i+1] == '9') { 168 ch := layout[i+1] 169 j := i + 1 170 for j < len(layout) && layout[j] == ch { 171 j++ 172 } 173 // String of digits must end here - only fractional second is all digits. 174 if !isDigit(layout, j) { 175 return layout[0:i], layout[i:j], layout[j:] 176 } 177 } 178 } 179 } 180 return layout, "", "" 181 } 182 183 var longDayNames = []string{ 184 "Sunday", 185 "Monday", 186 "Tuesday", 187 "Wednesday", 188 "Thursday", 189 "Friday", 190 "Saturday", 191 } 192 193 var shortDayNames = []string{ 194 "Sun", 195 "Mon", 196 "Tue", 197 "Wed", 198 "Thu", 199 "Fri", 200 "Sat", 201 } 202 203 var shortMonthNames = []string{ 204 "---", 205 "Jan", 206 "Feb", 207 "Mar", 208 "Apr", 209 "May", 210 "Jun", 211 "Jul", 212 "Aug", 213 "Sep", 214 "Oct", 215 "Nov", 216 "Dec", 217 } 218 219 var longMonthNames = []string{ 220 "---", 221 "January", 222 "February", 223 "March", 224 "April", 225 "May", 226 "June", 227 "July", 228 "August", 229 "September", 230 "October", 231 "November", 232 "December", 233 } 234 235 // match returns true if s1 and s2 match ignoring case. 236 // It is assumed s1 and s2 are the same length. 237 func match(s1, s2 string) bool { 238 for i := 0; i < len(s1); i++ { 239 c1 := s1[i] 240 c2 := s2[i] 241 if c1 != c2 { 242 // Switch to lower-case; 'a'-'A' is known to be a single bit. 243 c1 |= 'a' - 'A' 244 c2 |= 'a' - 'A' 245 if c1 != c2 || c1 < 'a' || c1 > 'z' { 246 return false 247 } 248 } 249 } 250 return true 251 } 252 253 func lookup(tab []string, val string) (int, string, error) { 254 for i, v := range tab { 255 if len(val) >= len(v) && match(val[0:len(v)], v) { 256 return i, val[len(v):], nil 257 } 258 } 259 return -1, val, errBad 260 } 261 262 // Duplicates functionality in strconv, but avoids dependency. 263 func itoa(x int) string { 264 var buf [32]byte 265 n := len(buf) 266 if x == 0 { 267 return "0" 268 } 269 u := uint(x) 270 if x < 0 { 271 u = -u 272 } 273 for u > 0 { 274 n-- 275 buf[n] = byte(u%10 + '0') 276 u /= 10 277 } 278 if x < 0 { 279 n-- 280 buf[n] = '-' 281 } 282 return string(buf[n:]) 283 } 284 285 // Never printed, just needs to be non-nil for return by atoi. 286 var atoiError = errors.New("time: invalid number") 287 288 // Duplicates functionality in strconv, but avoids dependency. 289 func atoi(s string) (x int, err error) { 290 neg := false 291 if s != "" && s[0] == '-' { 292 neg = true 293 s = s[1:] 294 } 295 x, rem, err := leadingInt(s) 296 if err != nil || rem != "" { 297 return 0, atoiError 298 } 299 if neg { 300 x = -x 301 } 302 return x, nil 303 } 304 305 func pad(i int, padding string) string { 306 s := itoa(i) 307 if i < 10 { 308 s = padding + s 309 } 310 return s 311 } 312 313 func zeroPad(i int) string { return pad(i, "0") } 314 315 // formatNano formats a fractional second, as nanoseconds. 316 func formatNano(nanosec, n int, trim bool) string { 317 // User might give us bad data. Make sure it's positive and in range. 318 // They'll get nonsense output but it will have the right format. 319 s := itoa(int(uint(nanosec) % 1e9)) 320 // Zero pad left without fmt. 321 if len(s) < 9 { 322 s = "000000000"[:9-len(s)] + s 323 } 324 if n > 9 { 325 n = 9 326 } 327 if trim { 328 for n > 0 && s[n-1] == '0' { 329 n-- 330 } 331 if n == 0 { 332 return "" 333 } 334 } 335 return "." + s[:n] 336 } 337 338 // String returns the time formatted using the format string 339 // "2006-01-02 15:04:05.999999999 -0700 MST" 340 func (t Time) String() string { 341 return t.Format("2006-01-02 15:04:05.999999999 -0700 MST") 342 } 343 344 type buffer []byte 345 346 func (b *buffer) WriteString(s string) { 347 *b = append(*b, s...) 348 } 349 350 func (b *buffer) String() string { 351 return string([]byte(*b)) 352 } 353 354 // Format returns a textual representation of the time value formatted 355 // according to layout. The layout defines the format by showing the 356 // representation of the standard time, 357 // Mon Jan 2 15:04:05 -0700 MST 2006 358 // which is then used to describe the time to be formatted. Predefined 359 // layouts ANSIC, UnixDate, RFC3339 and others describe standard 360 // representations. For more information about the formats and the 361 // definition of the standard time, see the documentation for ANSIC. 362 func (t Time) Format(layout string) string { 363 var ( 364 year int = -1 365 month Month 366 day int 367 hour int = -1 368 min int 369 sec int 370 b buffer 371 ) 372 // Each iteration generates one std value. 373 for { 374 prefix, std, suffix := nextStdChunk(layout) 375 b.WriteString(prefix) 376 if std == "" { 377 break 378 } 379 380 // Compute year, month, day if needed. 381 if year < 0 { 382 // Jan 01 02 2006 383 if a, z := std[0], std[len(std)-1]; a == 'J' || a == 'j' || z == '1' || z == '2' || z == '6' { 384 year, month, day = t.Date() 385 } 386 } 387 388 // Compute hour, minute, second if needed. 389 if hour < 0 { 390 // 03 04 05 15 pm 391 if z := std[len(std)-1]; z == '3' || z == '4' || z == '5' || z == 'm' || z == 'M' { 392 hour, min, sec = t.Clock() 393 } 394 } 395 396 var p string 397 switch std { 398 case stdYear: 399 p = zeroPad(year % 100) 400 case stdLongYear: 401 // Pad year to at least 4 digits. 402 p = itoa(year) 403 switch { 404 case year <= -1000: 405 // ok 406 case year <= -100: 407 p = p[:1] + "0" + p[1:] 408 case year <= -10: 409 p = p[:1] + "00" + p[1:] 410 case year < 0: 411 p = p[:1] + "000" + p[1:] 412 case year < 10: 413 p = "000" + p 414 case year < 100: 415 p = "00" + p 416 case year < 1000: 417 p = "0" + p 418 } 419 case stdMonth: 420 p = month.String()[:3] 421 case stdLongMonth: 422 p = month.String() 423 case stdNumMonth: 424 p = itoa(int(month)) 425 case stdZeroMonth: 426 p = zeroPad(int(month)) 427 case stdWeekDay: 428 p = t.Weekday().String()[:3] 429 case stdLongWeekDay: 430 p = t.Weekday().String() 431 case stdDay: 432 p = itoa(day) 433 case stdUnderDay: 434 p = pad(day, " ") 435 case stdZeroDay: 436 p = zeroPad(day) 437 case stdHour: 438 p = zeroPad(hour) 439 case stdHour12: 440 // Noon is 12PM, midnight is 12AM. 441 hr := hour % 12 442 if hr == 0 { 443 hr = 12 444 } 445 p = itoa(hr) 446 case stdZeroHour12: 447 // Noon is 12PM, midnight is 12AM. 448 hr := hour % 12 449 if hr == 0 { 450 hr = 12 451 } 452 p = zeroPad(hr) 453 case stdMinute: 454 p = itoa(min) 455 case stdZeroMinute: 456 p = zeroPad(min) 457 case stdSecond: 458 p = itoa(sec) 459 case stdZeroSecond: 460 p = zeroPad(sec) 461 case stdPM: 462 if hour >= 12 { 463 p = "PM" 464 } else { 465 p = "AM" 466 } 467 case stdpm: 468 if hour >= 12 { 469 p = "pm" 470 } else { 471 p = "am" 472 } 473 case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumColonTZ: 474 // Ugly special case. We cheat and take the "Z" variants 475 // to mean "the time zone as formatted for ISO 8601". 476 _, offset := t.Zone() 477 if offset == 0 && std[0] == 'Z' { 478 p = "Z" 479 break 480 } 481 zone := offset / 60 // convert to minutes 482 if zone < 0 { 483 p = "-" 484 zone = -zone 485 } else { 486 p = "+" 487 } 488 p += zeroPad(zone / 60) 489 if std == stdISO8601ColonTZ || std == stdNumColonTZ { 490 p += ":" 491 } 492 p += zeroPad(zone % 60) 493 case stdTZ: 494 name, offset := t.Zone() 495 if name != "" { 496 p = name 497 } else { 498 // No time zone known for this time, but we must print one. 499 // Use the -0700 format. 500 zone := offset / 60 // convert to minutes 501 if zone < 0 { 502 p = "-" 503 zone = -zone 504 } else { 505 p = "+" 506 } 507 p += zeroPad(zone / 60) 508 p += zeroPad(zone % 60) 509 } 510 default: 511 if len(std) >= 2 && (std[0:2] == ".0" || std[0:2] == ".9") { 512 p = formatNano(t.Nanosecond(), len(std)-1, std[1] == '9') 513 } 514 } 515 b.WriteString(p) 516 layout = suffix 517 } 518 return b.String() 519 } 520 521 var errBad = errors.New("bad value for field") // placeholder not passed to user 522 523 // ParseError describes a problem parsing a time string. 524 type ParseError struct { 525 Layout string 526 Value string 527 LayoutElem string 528 ValueElem string 529 Message string 530 } 531 532 func quote(s string) string { 533 return "\"" + s + "\"" 534 } 535 536 // Error returns the string representation of a ParseError. 537 func (e *ParseError) Error() string { 538 if e.Message == "" { 539 return "parsing time " + 540 quote(e.Value) + " as " + 541 quote(e.Layout) + ": cannot parse " + 542 quote(e.ValueElem) + " as " + 543 quote(e.LayoutElem) 544 } 545 return "parsing time " + 546 quote(e.Value) + e.Message 547 } 548 549 // isDigit returns true if s[i] is a decimal digit, false if not or 550 // if s[i] is out of range. 551 func isDigit(s string, i int) bool { 552 if len(s) <= i { 553 return false 554 } 555 c := s[i] 556 return '0' <= c && c <= '9' 557 } 558 559 // getnum parses s[0:1] or s[0:2] (fixed forces the latter) 560 // as a decimal integer and returns the integer and the 561 // remainder of the string. 562 func getnum(s string, fixed bool) (int, string, error) { 563 if !isDigit(s, 0) { 564 return 0, s, errBad 565 } 566 if !isDigit(s, 1) { 567 if fixed { 568 return 0, s, errBad 569 } 570 return int(s[0] - '0'), s[1:], nil 571 } 572 return int(s[0]-'0')*10 + int(s[1]-'0'), s[2:], nil 573 } 574 575 func cutspace(s string) string { 576 for len(s) > 0 && s[0] == ' ' { 577 s = s[1:] 578 } 579 return s 580 } 581 582 // skip removes the given prefix from value, 583 // treating runs of space characters as equivalent. 584 func skip(value, prefix string) (string, error) { 585 for len(prefix) > 0 { 586 if prefix[0] == ' ' { 587 if len(value) > 0 && value[0] != ' ' { 588 return "", errBad 589 } 590 prefix = cutspace(prefix) 591 value = cutspace(value) 592 continue 593 } 594 if len(value) == 0 || value[0] != prefix[0] { 595 return "", errBad 596 } 597 prefix = prefix[1:] 598 value = value[1:] 599 } 600 return value, nil 601 } 602 603 // Parse parses a formatted string and returns the time value it represents. 604 // The layout defines the format by showing the representation of the 605 // standard time, 606 // Mon Jan 2 15:04:05 -0700 MST 2006 607 // which is then used to describe the string to be parsed. Predefined layouts 608 // ANSIC, UnixDate, RFC3339 and others describe standard representations. For 609 // more information about the formats and the definition of the standard 610 // time, see the documentation for ANSIC. 611 // 612 // Elements omitted from the value are assumed to be zero or, when 613 // zero is impossible, one, so parsing "3:04pm" returns the time 614 // corresponding to Jan 1, year 0, 15:04:00 UTC. 615 // Years must be in the range 0000..9999. The day of the week is checked 616 // for syntax but it is otherwise ignored. 617 func Parse(layout, value string) (Time, error) { 618 alayout, avalue := layout, value 619 rangeErrString := "" // set if a value is out of range 620 amSet := false // do we need to subtract 12 from the hour for midnight? 621 pmSet := false // do we need to add 12 to the hour? 622 623 // Time being constructed. 624 var ( 625 year int 626 month int = 1 // January 627 day int = 1 628 hour int 629 min int 630 sec int 631 nsec int 632 z *Location 633 zoneOffset int = -1 634 zoneName string 635 ) 636 637 // Each iteration processes one std value. 638 for { 639 var err error 640 prefix, std, suffix := nextStdChunk(layout) 641 value, err = skip(value, prefix) 642 if err != nil { 643 return Time{}, &ParseError{alayout, avalue, prefix, value, ""} 644 } 645 if len(std) == 0 { 646 if len(value) != 0 { 647 return Time{}, &ParseError{alayout, avalue, "", value, ": extra text: " + value} 648 } 649 break 650 } 651 layout = suffix 652 var p string 653 switch std { 654 case stdYear: 655 if len(value) < 2 { 656 err = errBad 657 break 658 } 659 p, value = value[0:2], value[2:] 660 year, err = atoi(p) 661 if year >= 69 { // Unix time starts Dec 31 1969 in some time zones 662 year += 1900 663 } else { 664 year += 2000 665 } 666 case stdLongYear: 667 if len(value) < 4 || !isDigit(value, 0) { 668 err = errBad 669 break 670 } 671 p, value = value[0:4], value[4:] 672 year, err = atoi(p) 673 case stdMonth: 674 month, value, err = lookup(shortMonthNames, value) 675 case stdLongMonth: 676 month, value, err = lookup(longMonthNames, value) 677 case stdNumMonth, stdZeroMonth: 678 month, value, err = getnum(value, std == stdZeroMonth) 679 if month <= 0 || 12 < month { 680 rangeErrString = "month" 681 } 682 case stdWeekDay: 683 // Ignore weekday except for error checking. 684 _, value, err = lookup(shortDayNames, value) 685 case stdLongWeekDay: 686 _, value, err = lookup(longDayNames, value) 687 case stdDay, stdUnderDay, stdZeroDay: 688 if std == stdUnderDay && len(value) > 0 && value[0] == ' ' { 689 value = value[1:] 690 } 691 day, value, err = getnum(value, std == stdZeroDay) 692 if day < 0 || 31 < day { 693 rangeErrString = "day" 694 } 695 case stdHour: 696 hour, value, err = getnum(value, false) 697 if hour < 0 || 24 <= hour { 698 rangeErrString = "hour" 699 } 700 case stdHour12, stdZeroHour12: 701 hour, value, err = getnum(value, std == stdZeroHour12) 702 if hour < 0 || 12 < hour { 703 rangeErrString = "hour" 704 } 705 case stdMinute, stdZeroMinute: 706 min, value, err = getnum(value, std == stdZeroMinute) 707 if min < 0 || 60 <= min { 708 rangeErrString = "minute" 709 } 710 case stdSecond, stdZeroSecond: 711 sec, value, err = getnum(value, std == stdZeroSecond) 712 if sec < 0 || 60 <= sec { 713 rangeErrString = "second" 714 } 715 // Special case: do we have a fractional second but no 716 // fractional second in the format? 717 if len(value) >= 2 && value[0] == '.' && isDigit(value, 1) { 718 _, std, _ := nextStdChunk(layout) 719 if len(std) > 0 && std[0] == '.' && isDigit(std, 1) { 720 // Fractional second in the layout; proceed normally 721 break 722 } 723 // No fractional second in the layout but we have one in the input. 724 n := 2 725 for ; n < len(value) && isDigit(value, n); n++ { 726 } 727 nsec, rangeErrString, err = parseNanoseconds(value, n) 728 value = value[n:] 729 } 730 case stdPM: 731 if len(value) < 2 { 732 err = errBad 733 break 734 } 735 p, value = value[0:2], value[2:] 736 switch p { 737 case "PM": 738 pmSet = true 739 case "AM": 740 amSet = true 741 default: 742 err = errBad 743 } 744 case stdpm: 745 if len(value) < 2 { 746 err = errBad 747 break 748 } 749 p, value = value[0:2], value[2:] 750 switch p { 751 case "pm": 752 pmSet = true 753 case "am": 754 amSet = true 755 default: 756 err = errBad 757 } 758 case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ: 759 if std[0] == 'Z' && len(value) >= 1 && value[0] == 'Z' { 760 value = value[1:] 761 z = UTC 762 break 763 } 764 var sign, hour, min string 765 if std == stdISO8601ColonTZ || std == stdNumColonTZ { 766 if len(value) < 6 { 767 err = errBad 768 break 769 } 770 if value[3] != ':' { 771 err = errBad 772 break 773 } 774 sign, hour, min, value = value[0:1], value[1:3], value[4:6], value[6:] 775 } else if std == stdNumShortTZ { 776 if len(value) < 3 { 777 err = errBad 778 break 779 } 780 sign, hour, min, value = value[0:1], value[1:3], "00", value[3:] 781 } else { 782 if len(value) < 5 { 783 err = errBad 784 break 785 } 786 sign, hour, min, value = value[0:1], value[1:3], value[3:5], value[5:] 787 } 788 var hr, mm int 789 hr, err = atoi(hour) 790 if err == nil { 791 mm, err = atoi(min) 792 } 793 zoneOffset = (hr*60 + mm) * 60 // offset is in seconds 794 switch sign[0] { 795 case '+': 796 case '-': 797 zoneOffset = -zoneOffset 798 default: 799 err = errBad 800 } 801 case stdTZ: 802 // Does it look like a time zone? 803 if len(value) >= 3 && value[0:3] == "UTC" { 804 z = UTC 805 value = value[3:] 806 break 807 } 808 809 if len(value) >= 3 && value[2] == 'T' { 810 p, value = value[0:3], value[3:] 811 } else if len(value) >= 4 && value[3] == 'T' { 812 p, value = value[0:4], value[4:] 813 } else { 814 err = errBad 815 break 816 } 817 for i := 0; i < len(p); i++ { 818 if p[i] < 'A' || 'Z' < p[i] { 819 err = errBad 820 } 821 } 822 if err != nil { 823 break 824 } 825 // It's a valid format. 826 zoneName = p 827 default: 828 if len(value) < len(std) { 829 err = errBad 830 break 831 } 832 if len(std) >= 2 && std[0:2] == ".0" { 833 nsec, rangeErrString, err = parseNanoseconds(value, len(std)) 834 value = value[len(std):] 835 } 836 } 837 if rangeErrString != "" { 838 return Time{}, &ParseError{alayout, avalue, std, value, ": " + rangeErrString + " out of range"} 839 } 840 if err != nil { 841 return Time{}, &ParseError{alayout, avalue, std, value, ""} 842 } 843 } 844 if pmSet && hour < 12 { 845 hour += 12 846 } else if amSet && hour == 12 { 847 hour = 0 848 } 849 850 // TODO: be more aggressive checking day? 851 if z != nil { 852 return Date(year, Month(month), day, hour, min, sec, nsec, z), nil 853 } 854 855 t := Date(year, Month(month), day, hour, min, sec, nsec, UTC) 856 if zoneOffset != -1 { 857 t.sec -= int64(zoneOffset) 858 859 // Look for local zone with the given offset. 860 // If that zone was in effect at the given time, use it. 861 name, offset, _, _, _ := Local.lookup(t.sec + internalToUnix) 862 if offset == zoneOffset && (zoneName == "" || name == zoneName) { 863 t.loc = Local 864 return t, nil 865 } 866 867 // Otherwise create fake zone to record offset. 868 t.loc = FixedZone(zoneName, zoneOffset) 869 return t, nil 870 } 871 872 if zoneName != "" { 873 // Look for local zone with the given offset. 874 // If that zone was in effect at the given time, use it. 875 offset, _, ok := Local.lookupName(zoneName) 876 if ok { 877 name, off, _, _, _ := Local.lookup(t.sec + internalToUnix - int64(offset)) 878 if name == zoneName && off == offset { 879 t.sec -= int64(offset) 880 t.loc = Local 881 return t, nil 882 } 883 } 884 885 // Otherwise, create fake zone with unknown offset. 886 t.loc = FixedZone(zoneName, 0) 887 return t, nil 888 } 889 890 // Otherwise, fall back to UTC. 891 return t, nil 892 } 893 894 func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string, err error) { 895 if value[0] != '.' { 896 err = errBad 897 return 898 } 899 ns, err = atoi(value[1:nbytes]) 900 if err != nil { 901 return 902 } 903 if ns < 0 || 1e9 <= ns { 904 rangeErrString = "fractional second" 905 return 906 } 907 // We need nanoseconds, which means scaling by the number 908 // of missing digits in the format, maximum length 10. If it's 909 // longer than 10, we won't scale. 910 scaleDigits := 10 - nbytes 911 for i := 0; i < scaleDigits; i++ { 912 ns *= 10 913 } 914 return 915 } 916 917 var errLeadingInt = errors.New("time: bad [0-9]*") // never printed 918 919 // leadingInt consumes the leading [0-9]* from s. 920 func leadingInt(s string) (x int, rem string, err error) { 921 i := 0 922 for ; i < len(s); i++ { 923 c := s[i] 924 if c < '0' || c > '9' { 925 break 926 } 927 if x >= (1<<31-10)/10 { 928 // overflow 929 return 0, "", errLeadingInt 930 } 931 x = x*10 + int(c) - '0' 932 } 933 return x, s[i:], nil 934 } 935 936 var unitMap = map[string]float64{ 937 "ns": float64(Nanosecond), 938 "us": float64(Microsecond), 939 "µs": float64(Microsecond), // U+00B5 = micro symbol 940 "μs": float64(Microsecond), // U+03BC = Greek letter mu 941 "ms": float64(Millisecond), 942 "s": float64(Second), 943 "m": float64(Minute), 944 "h": float64(Hour), 945 } 946 947 // ParseDuration parses a duration string. 948 // A duration string is a possibly signed sequence of 949 // decimal numbers, each with optional fraction and a unit suffix, 950 // such as "300ms", "-1.5h" or "2h45m". 951 // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". 952 func ParseDuration(s string) (Duration, error) { 953 // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+ 954 orig := s 955 f := float64(0) 956 neg := false 957 958 // Consume [-+]? 959 if s != "" { 960 c := s[0] 961 if c == '-' || c == '+' { 962 neg = c == '-' 963 s = s[1:] 964 } 965 } 966 // Special case: if all that is left is "0", this is zero. 967 if s == "0" { 968 return 0, nil 969 } 970 if s == "" { 971 return 0, errors.New("time: invalid duration " + orig) 972 } 973 for s != "" { 974 g := float64(0) // this element of the sequence 975 976 var x int 977 var err error 978 979 // The next character must be [0-9.] 980 if !(s[0] == '.' || ('0' <= s[0] && s[0] <= '9')) { 981 return 0, errors.New("time: invalid duration " + orig) 982 } 983 // Consume [0-9]* 984 pl := len(s) 985 x, s, err = leadingInt(s) 986 if err != nil { 987 return 0, errors.New("time: invalid duration " + orig) 988 } 989 g = float64(x) 990 pre := pl != len(s) // whether we consumed anything before a period 991 992 // Consume (\.[0-9]*)? 993 post := false 994 if s != "" && s[0] == '.' { 995 s = s[1:] 996 pl := len(s) 997 x, s, err = leadingInt(s) 998 if err != nil { 999 return 0, errors.New("time: invalid duration " + orig) 1000 } 1001 scale := 1 1002 for n := pl - len(s); n > 0; n-- { 1003 scale *= 10 1004 } 1005 g += float64(x) / float64(scale) 1006 post = pl != len(s) 1007 } 1008 if !pre && !post { 1009 // no digits (e.g. ".s" or "-.s") 1010 return 0, errors.New("time: invalid duration " + orig) 1011 } 1012 1013 // Consume unit. 1014 i := 0 1015 for ; i < len(s); i++ { 1016 c := s[i] 1017 if c == '.' || ('0' <= c && c <= '9') { 1018 break 1019 } 1020 } 1021 if i == 0 { 1022 return 0, errors.New("time: missing unit in duration " + orig) 1023 } 1024 u := s[:i] 1025 s = s[i:] 1026 unit, ok := unitMap[u] 1027 if !ok { 1028 return 0, errors.New("time: unknown unit " + u + " in duration " + orig) 1029 } 1030 1031 f += g * unit 1032 } 1033 1034 if neg { 1035 f = -f 1036 } 1037 return Duration(f), nil 1038 }