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