Source file
src/time/format.go
1
2
3
4
5 package time
6
7 import (
8 "errors"
9 "internal/stringslite"
10 )
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 const (
105 Layout = "01/02 03:04:05PM '06 -0700"
106 ANSIC = "Mon Jan _2 15:04:05 2006"
107 UnixDate = "Mon Jan _2 15:04:05 MST 2006"
108 RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
109 RFC822 = "02 Jan 06 15:04 MST"
110 RFC822Z = "02 Jan 06 15:04 -0700"
111 RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
112 RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
113 RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700"
114 RFC3339 = "2006-01-02T15:04:05Z07:00"
115 RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
116 Kitchen = "3:04PM"
117
118 Stamp = "Jan _2 15:04:05"
119 StampMilli = "Jan _2 15:04:05.000"
120 StampMicro = "Jan _2 15:04:05.000000"
121 StampNano = "Jan _2 15:04:05.000000000"
122 DateTime = "2006-01-02 15:04:05"
123 DateOnly = "2006-01-02"
124 TimeOnly = "15:04:05"
125 )
126
127 const (
128 _ = iota
129 stdLongMonth = iota + stdNeedDate
130 stdMonth
131 stdNumMonth
132 stdZeroMonth
133 stdLongWeekDay
134 stdWeekDay
135 stdDay
136 stdUnderDay
137 stdZeroDay
138 stdUnderYearDay
139 stdZeroYearDay
140 stdHour = iota + stdNeedClock
141 stdHour12
142 stdZeroHour12
143 stdMinute
144 stdZeroMinute
145 stdSecond
146 stdZeroSecond
147 stdLongYear = iota + stdNeedDate
148 stdYear
149 stdPM = iota + stdNeedClock
150 stdpm
151 stdTZ = iota
152 stdISO8601TZ
153 stdISO8601SecondsTZ
154 stdISO8601ShortTZ
155 stdISO8601ColonTZ
156 stdISO8601ColonSecondsTZ
157 stdNumTZ
158 stdNumSecondsTz
159 stdNumShortTZ
160 stdNumColonTZ
161 stdNumColonSecondsTZ
162 stdFracSecond0
163 stdFracSecond9
164
165 stdNeedDate = 1 << 8
166 stdNeedClock = 2 << 8
167 stdArgShift = 16
168 stdSeparatorShift = 28
169 stdMask = 1<<stdArgShift - 1
170 )
171
172
173 var std0x = [...]int{stdZeroMonth, stdZeroDay, stdZeroHour12, stdZeroMinute, stdZeroSecond, stdYear}
174
175
176
177 func startsWithLowerCase(str string) bool {
178 if len(str) == 0 {
179 return false
180 }
181 c := str[0]
182 return 'a' <= c && c <= 'z'
183 }
184
185
186
187 func nextStdChunk(layout string) (prefix string, std int, suffix string) {
188 for i := 0; i < len(layout); i++ {
189 switch c := int(layout[i]); c {
190 case 'J':
191 if len(layout) >= i+3 && layout[i:i+3] == "Jan" {
192 if len(layout) >= i+7 && layout[i:i+7] == "January" {
193 return layout[0:i], stdLongMonth, layout[i+7:]
194 }
195 if !startsWithLowerCase(layout[i+3:]) {
196 return layout[0:i], stdMonth, layout[i+3:]
197 }
198 }
199
200 case 'M':
201 if len(layout) >= i+3 {
202 if layout[i:i+3] == "Mon" {
203 if len(layout) >= i+6 && layout[i:i+6] == "Monday" {
204 return layout[0:i], stdLongWeekDay, layout[i+6:]
205 }
206 if !startsWithLowerCase(layout[i+3:]) {
207 return layout[0:i], stdWeekDay, layout[i+3:]
208 }
209 }
210 if layout[i:i+3] == "MST" {
211 return layout[0:i], stdTZ, layout[i+3:]
212 }
213 }
214
215 case '0':
216 if len(layout) >= i+2 && '1' <= layout[i+1] && layout[i+1] <= '6' {
217 return layout[0:i], std0x[layout[i+1]-'1'], layout[i+2:]
218 }
219 if len(layout) >= i+3 && layout[i+1] == '0' && layout[i+2] == '2' {
220 return layout[0:i], stdZeroYearDay, layout[i+3:]
221 }
222
223 case '1':
224 if len(layout) >= i+2 && layout[i+1] == '5' {
225 return layout[0:i], stdHour, layout[i+2:]
226 }
227 return layout[0:i], stdNumMonth, layout[i+1:]
228
229 case '2':
230 if len(layout) >= i+4 && layout[i:i+4] == "2006" {
231 return layout[0:i], stdLongYear, layout[i+4:]
232 }
233 return layout[0:i], stdDay, layout[i+1:]
234
235 case '_':
236 if len(layout) >= i+2 && layout[i+1] == '2' {
237
238 if len(layout) >= i+5 && layout[i+1:i+5] == "2006" {
239 return layout[0 : i+1], stdLongYear, layout[i+5:]
240 }
241 return layout[0:i], stdUnderDay, layout[i+2:]
242 }
243 if len(layout) >= i+3 && layout[i+1] == '_' && layout[i+2] == '2' {
244 return layout[0:i], stdUnderYearDay, layout[i+3:]
245 }
246
247 case '3':
248 return layout[0:i], stdHour12, layout[i+1:]
249
250 case '4':
251 return layout[0:i], stdMinute, layout[i+1:]
252
253 case '5':
254 return layout[0:i], stdSecond, layout[i+1:]
255
256 case 'P':
257 if len(layout) >= i+2 && layout[i+1] == 'M' {
258 return layout[0:i], stdPM, layout[i+2:]
259 }
260
261 case 'p':
262 if len(layout) >= i+2 && layout[i+1] == 'm' {
263 return layout[0:i], stdpm, layout[i+2:]
264 }
265
266 case '-':
267 if len(layout) >= i+7 && layout[i:i+7] == "-070000" {
268 return layout[0:i], stdNumSecondsTz, layout[i+7:]
269 }
270 if len(layout) >= i+9 && layout[i:i+9] == "-07:00:00" {
271 return layout[0:i], stdNumColonSecondsTZ, layout[i+9:]
272 }
273 if len(layout) >= i+5 && layout[i:i+5] == "-0700" {
274 return layout[0:i], stdNumTZ, layout[i+5:]
275 }
276 if len(layout) >= i+6 && layout[i:i+6] == "-07:00" {
277 return layout[0:i], stdNumColonTZ, layout[i+6:]
278 }
279 if len(layout) >= i+3 && layout[i:i+3] == "-07" {
280 return layout[0:i], stdNumShortTZ, layout[i+3:]
281 }
282
283 case 'Z':
284 if len(layout) >= i+7 && layout[i:i+7] == "Z070000" {
285 return layout[0:i], stdISO8601SecondsTZ, layout[i+7:]
286 }
287 if len(layout) >= i+9 && layout[i:i+9] == "Z07:00:00" {
288 return layout[0:i], stdISO8601ColonSecondsTZ, layout[i+9:]
289 }
290 if len(layout) >= i+5 && layout[i:i+5] == "Z0700" {
291 return layout[0:i], stdISO8601TZ, layout[i+5:]
292 }
293 if len(layout) >= i+6 && layout[i:i+6] == "Z07:00" {
294 return layout[0:i], stdISO8601ColonTZ, layout[i+6:]
295 }
296 if len(layout) >= i+3 && layout[i:i+3] == "Z07" {
297 return layout[0:i], stdISO8601ShortTZ, layout[i+3:]
298 }
299
300 case '.', ',':
301 if i+1 < len(layout) && (layout[i+1] == '0' || layout[i+1] == '9') {
302 ch := layout[i+1]
303 j := i + 1
304 for j < len(layout) && layout[j] == ch {
305 j++
306 }
307
308 if !isDigit(layout, j) {
309 code := stdFracSecond0
310 if layout[i+1] == '9' {
311 code = stdFracSecond9
312 }
313 std := stdFracSecond(code, j-(i+1), c)
314 return layout[0:i], std, layout[j:]
315 }
316 }
317 }
318 }
319 return layout, 0, ""
320 }
321
322 var longDayNames = []string{
323 "Sunday",
324 "Monday",
325 "Tuesday",
326 "Wednesday",
327 "Thursday",
328 "Friday",
329 "Saturday",
330 }
331
332 var shortDayNames = []string{
333 "Sun",
334 "Mon",
335 "Tue",
336 "Wed",
337 "Thu",
338 "Fri",
339 "Sat",
340 }
341
342 var shortMonthNames = []string{
343 "Jan",
344 "Feb",
345 "Mar",
346 "Apr",
347 "May",
348 "Jun",
349 "Jul",
350 "Aug",
351 "Sep",
352 "Oct",
353 "Nov",
354 "Dec",
355 }
356
357 var longMonthNames = []string{
358 "January",
359 "February",
360 "March",
361 "April",
362 "May",
363 "June",
364 "July",
365 "August",
366 "September",
367 "October",
368 "November",
369 "December",
370 }
371
372
373
374 func match(s1, s2 string) bool {
375 for i := 0; i < len(s1); i++ {
376 c1 := s1[i]
377 c2 := s2[i]
378 if c1 != c2 {
379
380 c1 |= 'a' - 'A'
381 c2 |= 'a' - 'A'
382 if c1 != c2 || c1 < 'a' || c1 > 'z' {
383 return false
384 }
385 }
386 }
387 return true
388 }
389
390 func lookup(tab []string, val string) (int, string, error) {
391 for i, v := range tab {
392 if len(val) >= len(v) && match(val[0:len(v)], v) {
393 return i, val[len(v):], nil
394 }
395 }
396 return -1, val, errBad
397 }
398
399
400
401
402 func appendInt(b []byte, x int, width int) []byte {
403 u := uint(x)
404 if x < 0 {
405 b = append(b, '-')
406 u = uint(-x)
407 }
408
409
410 utod := func(u uint) byte { return '0' + byte(u) }
411 switch {
412 case width == 2 && u < 1e2:
413 return append(b, utod(u/1e1), utod(u%1e1))
414 case width == 4 && u < 1e4:
415 return append(b, utod(u/1e3), utod(u/1e2%1e1), utod(u/1e1%1e1), utod(u%1e1))
416 }
417
418
419 var n int
420 if u == 0 {
421 n = 1
422 }
423 for u2 := u; u2 > 0; u2 /= 10 {
424 n++
425 }
426
427
428 for pad := width - n; pad > 0; pad-- {
429 b = append(b, '0')
430 }
431
432
433 if len(b)+n <= cap(b) {
434 b = b[:len(b)+n]
435 } else {
436 b = append(b, make([]byte, n)...)
437 }
438
439
440 i := len(b) - 1
441 for u >= 10 && i > 0 {
442 q := u / 10
443 b[i] = utod(u - q*10)
444 u = q
445 i--
446 }
447 b[i] = utod(u)
448 return b
449 }
450
451
452 var errAtoi = errors.New("time: invalid number")
453
454
455 func atoi[bytes []byte | string](s bytes) (x int, err error) {
456 neg := false
457 if len(s) > 0 && (s[0] == '-' || s[0] == '+') {
458 neg = s[0] == '-'
459 s = s[1:]
460 }
461 q, rem, err := leadingInt(s)
462 x = int(q)
463 if err != nil || len(rem) > 0 {
464 return 0, errAtoi
465 }
466 if neg {
467 x = -x
468 }
469 return x, nil
470 }
471
472
473
474
475 func stdFracSecond(code, n, c int) int {
476
477 if c == '.' {
478 return code | ((n & 0xfff) << stdArgShift)
479 }
480 return code | ((n & 0xfff) << stdArgShift) | 1<<stdSeparatorShift
481 }
482
483 func digitsLen(std int) int {
484 return (std >> stdArgShift) & 0xfff
485 }
486
487 func separator(std int) byte {
488 if (std >> stdSeparatorShift) == 0 {
489 return '.'
490 }
491 return ','
492 }
493
494
495
496 func appendNano(b []byte, nanosec int, std int) []byte {
497 trim := std&stdMask == stdFracSecond9
498 n := digitsLen(std)
499 if trim && (n == 0 || nanosec == 0) {
500 return b
501 }
502 dot := separator(std)
503 b = append(b, dot)
504 b = appendInt(b, nanosec, 9)
505 if n < 9 {
506 b = b[:len(b)-9+n]
507 }
508 if trim {
509 for len(b) > 0 && b[len(b)-1] == '0' {
510 b = b[:len(b)-1]
511 }
512 if len(b) > 0 && b[len(b)-1] == dot {
513 b = b[:len(b)-1]
514 }
515 }
516 return b
517 }
518
519
520
521
522
523
524
525
526
527
528
529
530 func (t Time) String() string {
531 s := t.Format("2006-01-02 15:04:05.999999999 -0700 MST")
532
533
534 if t.wall&hasMonotonic != 0 {
535 m2 := uint64(t.ext)
536 sign := byte('+')
537 if t.ext < 0 {
538 sign = '-'
539 m2 = -m2
540 }
541 m1, m2 := m2/1e9, m2%1e9
542 m0, m1 := m1/1e9, m1%1e9
543 buf := make([]byte, 0, 24)
544 buf = append(buf, " m="...)
545 buf = append(buf, sign)
546 wid := 0
547 if m0 != 0 {
548 buf = appendInt(buf, int(m0), 0)
549 wid = 9
550 }
551 buf = appendInt(buf, int(m1), wid)
552 buf = append(buf, '.')
553 buf = appendInt(buf, int(m2), 9)
554 s += string(buf)
555 }
556 return s
557 }
558
559
560
561 func (t Time) GoString() string {
562 abs := t.abs()
563 year, month, day, _ := absDate(abs, true)
564 hour, minute, second := absClock(abs)
565
566 buf := make([]byte, 0, len("time.Date(9999, time.September, 31, 23, 59, 59, 999999999, time.Local)"))
567 buf = append(buf, "time.Date("...)
568 buf = appendInt(buf, year, 0)
569 if January <= month && month <= December {
570 buf = append(buf, ", time."...)
571 buf = append(buf, longMonthNames[month-1]...)
572 } else {
573
574
575 buf = appendInt(buf, int(month), 0)
576 }
577 buf = append(buf, ", "...)
578 buf = appendInt(buf, day, 0)
579 buf = append(buf, ", "...)
580 buf = appendInt(buf, hour, 0)
581 buf = append(buf, ", "...)
582 buf = appendInt(buf, minute, 0)
583 buf = append(buf, ", "...)
584 buf = appendInt(buf, second, 0)
585 buf = append(buf, ", "...)
586 buf = appendInt(buf, t.Nanosecond(), 0)
587 buf = append(buf, ", "...)
588 switch loc := t.Location(); loc {
589 case UTC, nil:
590 buf = append(buf, "time.UTC"...)
591 case Local:
592 buf = append(buf, "time.Local"...)
593 default:
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609 buf = append(buf, `time.Location(`...)
610 buf = append(buf, quote(loc.name)...)
611 buf = append(buf, ')')
612 }
613 buf = append(buf, ')')
614 return string(buf)
615 }
616
617
618
619
620
621
622
623 func (t Time) Format(layout string) string {
624 const bufSize = 64
625 var b []byte
626 max := len(layout) + 10
627 if max < bufSize {
628 var buf [bufSize]byte
629 b = buf[:0]
630 } else {
631 b = make([]byte, 0, max)
632 }
633 b = t.AppendFormat(b, layout)
634 return string(b)
635 }
636
637
638
639 func (t Time) AppendFormat(b []byte, layout string) []byte {
640
641 switch layout {
642 case RFC3339:
643 return t.appendFormatRFC3339(b, false)
644 case RFC3339Nano:
645 return t.appendFormatRFC3339(b, true)
646 default:
647 return t.appendFormat(b, layout)
648 }
649 }
650
651 func (t Time) appendFormat(b []byte, layout string) []byte {
652 var (
653 name, offset, abs = t.locabs()
654
655 year int = -1
656 month Month
657 day int
658 yday int
659 hour int = -1
660 min int
661 sec int
662 )
663
664
665 for layout != "" {
666 prefix, std, suffix := nextStdChunk(layout)
667 if prefix != "" {
668 b = append(b, prefix...)
669 }
670 if std == 0 {
671 break
672 }
673 layout = suffix
674
675
676 if year < 0 && std&stdNeedDate != 0 {
677 year, month, day, yday = absDate(abs, true)
678 yday++
679 }
680
681
682 if hour < 0 && std&stdNeedClock != 0 {
683 hour, min, sec = absClock(abs)
684 }
685
686 switch std & stdMask {
687 case stdYear:
688 y := year
689 if y < 0 {
690 y = -y
691 }
692 b = appendInt(b, y%100, 2)
693 case stdLongYear:
694 b = appendInt(b, year, 4)
695 case stdMonth:
696 b = append(b, month.String()[:3]...)
697 case stdLongMonth:
698 m := month.String()
699 b = append(b, m...)
700 case stdNumMonth:
701 b = appendInt(b, int(month), 0)
702 case stdZeroMonth:
703 b = appendInt(b, int(month), 2)
704 case stdWeekDay:
705 b = append(b, absWeekday(abs).String()[:3]...)
706 case stdLongWeekDay:
707 s := absWeekday(abs).String()
708 b = append(b, s...)
709 case stdDay:
710 b = appendInt(b, day, 0)
711 case stdUnderDay:
712 if day < 10 {
713 b = append(b, ' ')
714 }
715 b = appendInt(b, day, 0)
716 case stdZeroDay:
717 b = appendInt(b, day, 2)
718 case stdUnderYearDay:
719 if yday < 100 {
720 b = append(b, ' ')
721 if yday < 10 {
722 b = append(b, ' ')
723 }
724 }
725 b = appendInt(b, yday, 0)
726 case stdZeroYearDay:
727 b = appendInt(b, yday, 3)
728 case stdHour:
729 b = appendInt(b, hour, 2)
730 case stdHour12:
731
732 hr := hour % 12
733 if hr == 0 {
734 hr = 12
735 }
736 b = appendInt(b, hr, 0)
737 case stdZeroHour12:
738
739 hr := hour % 12
740 if hr == 0 {
741 hr = 12
742 }
743 b = appendInt(b, hr, 2)
744 case stdMinute:
745 b = appendInt(b, min, 0)
746 case stdZeroMinute:
747 b = appendInt(b, min, 2)
748 case stdSecond:
749 b = appendInt(b, sec, 0)
750 case stdZeroSecond:
751 b = appendInt(b, sec, 2)
752 case stdPM:
753 if hour >= 12 {
754 b = append(b, "PM"...)
755 } else {
756 b = append(b, "AM"...)
757 }
758 case stdpm:
759 if hour >= 12 {
760 b = append(b, "pm"...)
761 } else {
762 b = append(b, "am"...)
763 }
764 case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumColonTZ, stdNumSecondsTz, stdNumShortTZ, stdNumColonSecondsTZ:
765
766
767 if offset == 0 && (std == stdISO8601TZ || std == stdISO8601ColonTZ || std == stdISO8601SecondsTZ || std == stdISO8601ShortTZ || std == stdISO8601ColonSecondsTZ) {
768 b = append(b, 'Z')
769 break
770 }
771 zone := offset / 60
772 absoffset := offset
773 if zone < 0 {
774 b = append(b, '-')
775 zone = -zone
776 absoffset = -absoffset
777 } else {
778 b = append(b, '+')
779 }
780 b = appendInt(b, zone/60, 2)
781 if std == stdISO8601ColonTZ || std == stdNumColonTZ || std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ {
782 b = append(b, ':')
783 }
784 if std != stdNumShortTZ && std != stdISO8601ShortTZ {
785 b = appendInt(b, zone%60, 2)
786 }
787
788
789 if std == stdISO8601SecondsTZ || std == stdNumSecondsTz || std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ {
790 if std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ {
791 b = append(b, ':')
792 }
793 b = appendInt(b, absoffset%60, 2)
794 }
795
796 case stdTZ:
797 if name != "" {
798 b = append(b, name...)
799 break
800 }
801
802
803 zone := offset / 60
804 if zone < 0 {
805 b = append(b, '-')
806 zone = -zone
807 } else {
808 b = append(b, '+')
809 }
810 b = appendInt(b, zone/60, 2)
811 b = appendInt(b, zone%60, 2)
812 case stdFracSecond0, stdFracSecond9:
813 b = appendNano(b, t.Nanosecond(), std)
814 }
815 }
816 return b
817 }
818
819 var errBad = errors.New("bad value for field")
820
821
822 type ParseError struct {
823 Layout string
824 Value string
825 LayoutElem string
826 ValueElem string
827 Message string
828 }
829
830
831
832 func newParseError(layout, value, layoutElem, valueElem, message string) *ParseError {
833 valueCopy := stringslite.Clone(value)
834 valueElemCopy := stringslite.Clone(valueElem)
835 return &ParseError{layout, valueCopy, layoutElem, valueElemCopy, message}
836 }
837
838
839
840 const (
841 lowerhex = "0123456789abcdef"
842 runeSelf = 0x80
843 runeError = '\uFFFD'
844 )
845
846 func quote(s string) string {
847 buf := make([]byte, 1, len(s)+2)
848 buf[0] = '"'
849 for i, c := range s {
850 if c >= runeSelf || c < ' ' {
851
852
853
854
855
856
857 var width int
858 if c == runeError {
859 width = 1
860 if i+2 < len(s) && s[i:i+3] == string(runeError) {
861 width = 3
862 }
863 } else {
864 width = len(string(c))
865 }
866 for j := 0; j < width; j++ {
867 buf = append(buf, `\x`...)
868 buf = append(buf, lowerhex[s[i+j]>>4])
869 buf = append(buf, lowerhex[s[i+j]&0xF])
870 }
871 } else {
872 if c == '"' || c == '\\' {
873 buf = append(buf, '\\')
874 }
875 buf = append(buf, string(c)...)
876 }
877 }
878 buf = append(buf, '"')
879 return string(buf)
880 }
881
882
883 func (e *ParseError) Error() string {
884 if e.Message == "" {
885 return "parsing time " +
886 quote(e.Value) + " as " +
887 quote(e.Layout) + ": cannot parse " +
888 quote(e.ValueElem) + " as " +
889 quote(e.LayoutElem)
890 }
891 return "parsing time " +
892 quote(e.Value) + e.Message
893 }
894
895
896 func isDigit[bytes []byte | string](s bytes, i int) bool {
897 if len(s) <= i {
898 return false
899 }
900 c := s[i]
901 return '0' <= c && c <= '9'
902 }
903
904
905
906
907 func getnum(s string, fixed bool) (int, string, error) {
908 if !isDigit(s, 0) {
909 return 0, s, errBad
910 }
911 if !isDigit(s, 1) {
912 if fixed {
913 return 0, s, errBad
914 }
915 return int(s[0] - '0'), s[1:], nil
916 }
917 return int(s[0]-'0')*10 + int(s[1]-'0'), s[2:], nil
918 }
919
920
921
922
923 func getnum3(s string, fixed bool) (int, string, error) {
924 var n, i int
925 for i = 0; i < 3 && isDigit(s, i); i++ {
926 n = n*10 + int(s[i]-'0')
927 }
928 if i == 0 || fixed && i != 3 {
929 return 0, s, errBad
930 }
931 return n, s[i:], nil
932 }
933
934 func cutspace(s string) string {
935 for len(s) > 0 && s[0] == ' ' {
936 s = s[1:]
937 }
938 return s
939 }
940
941
942
943 func skip(value, prefix string) (string, error) {
944 for len(prefix) > 0 {
945 if prefix[0] == ' ' {
946 if len(value) > 0 && value[0] != ' ' {
947 return value, errBad
948 }
949 prefix = cutspace(prefix)
950 value = cutspace(value)
951 continue
952 }
953 if len(value) == 0 || value[0] != prefix[0] {
954 return value, errBad
955 }
956 prefix = prefix[1:]
957 value = value[1:]
958 }
959 return value, nil
960 }
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004 func Parse(layout, value string) (Time, error) {
1005
1006 if layout == RFC3339 || layout == RFC3339Nano {
1007 if t, ok := parseRFC3339(value, Local); ok {
1008 return t, nil
1009 }
1010 }
1011 return parse(layout, value, UTC, Local)
1012 }
1013
1014
1015
1016
1017
1018
1019 func ParseInLocation(layout, value string, loc *Location) (Time, error) {
1020
1021 if layout == RFC3339 || layout == RFC3339Nano {
1022 if t, ok := parseRFC3339(value, loc); ok {
1023 return t, nil
1024 }
1025 }
1026 return parse(layout, value, loc, loc)
1027 }
1028
1029 func parse(layout, value string, defaultLocation, local *Location) (Time, error) {
1030 alayout, avalue := layout, value
1031 rangeErrString := ""
1032 amSet := false
1033 pmSet := false
1034
1035
1036 var (
1037 year int
1038 month int = -1
1039 day int = -1
1040 yday int = -1
1041 hour int
1042 min int
1043 sec int
1044 nsec int
1045 z *Location
1046 zoneOffset int = -1
1047 zoneName string
1048 )
1049
1050
1051 for {
1052 var err error
1053 prefix, std, suffix := nextStdChunk(layout)
1054 stdstr := layout[len(prefix) : len(layout)-len(suffix)]
1055 value, err = skip(value, prefix)
1056 if err != nil {
1057 return Time{}, newParseError(alayout, avalue, prefix, value, "")
1058 }
1059 if std == 0 {
1060 if len(value) != 0 {
1061 return Time{}, newParseError(alayout, avalue, "", value, ": extra text: "+quote(value))
1062 }
1063 break
1064 }
1065 layout = suffix
1066 var p string
1067 hold := value
1068 switch std & stdMask {
1069 case stdYear:
1070 if len(value) < 2 {
1071 err = errBad
1072 break
1073 }
1074 p, value = value[0:2], value[2:]
1075 year, err = atoi(p)
1076 if err != nil {
1077 break
1078 }
1079 if year >= 69 {
1080 year += 1900
1081 } else {
1082 year += 2000
1083 }
1084 case stdLongYear:
1085 if len(value) < 4 || !isDigit(value, 0) {
1086 err = errBad
1087 break
1088 }
1089 p, value = value[0:4], value[4:]
1090 year, err = atoi(p)
1091 case stdMonth:
1092 month, value, err = lookup(shortMonthNames, value)
1093 month++
1094 case stdLongMonth:
1095 month, value, err = lookup(longMonthNames, value)
1096 month++
1097 case stdNumMonth, stdZeroMonth:
1098 month, value, err = getnum(value, std == stdZeroMonth)
1099 if err == nil && (month <= 0 || 12 < month) {
1100 rangeErrString = "month"
1101 }
1102 case stdWeekDay:
1103
1104 _, value, err = lookup(shortDayNames, value)
1105 case stdLongWeekDay:
1106 _, value, err = lookup(longDayNames, value)
1107 case stdDay, stdUnderDay, stdZeroDay:
1108 if std == stdUnderDay && len(value) > 0 && value[0] == ' ' {
1109 value = value[1:]
1110 }
1111 day, value, err = getnum(value, std == stdZeroDay)
1112
1113
1114 case stdUnderYearDay, stdZeroYearDay:
1115 for i := 0; i < 2; i++ {
1116 if std == stdUnderYearDay && len(value) > 0 && value[0] == ' ' {
1117 value = value[1:]
1118 }
1119 }
1120 yday, value, err = getnum3(value, std == stdZeroYearDay)
1121
1122
1123 case stdHour:
1124 hour, value, err = getnum(value, false)
1125 if hour < 0 || 24 <= hour {
1126 rangeErrString = "hour"
1127 }
1128 case stdHour12, stdZeroHour12:
1129 hour, value, err = getnum(value, std == stdZeroHour12)
1130 if hour < 0 || 12 < hour {
1131 rangeErrString = "hour"
1132 }
1133 case stdMinute, stdZeroMinute:
1134 min, value, err = getnum(value, std == stdZeroMinute)
1135 if min < 0 || 60 <= min {
1136 rangeErrString = "minute"
1137 }
1138 case stdSecond, stdZeroSecond:
1139 sec, value, err = getnum(value, std == stdZeroSecond)
1140 if err != nil {
1141 break
1142 }
1143 if sec < 0 || 60 <= sec {
1144 rangeErrString = "second"
1145 break
1146 }
1147
1148
1149 if len(value) >= 2 && commaOrPeriod(value[0]) && isDigit(value, 1) {
1150 _, std, _ = nextStdChunk(layout)
1151 std &= stdMask
1152 if std == stdFracSecond0 || std == stdFracSecond9 {
1153
1154 break
1155 }
1156
1157 n := 2
1158 for ; n < len(value) && isDigit(value, n); n++ {
1159 }
1160 nsec, rangeErrString, err = parseNanoseconds(value, n)
1161 value = value[n:]
1162 }
1163 case stdPM:
1164 if len(value) < 2 {
1165 err = errBad
1166 break
1167 }
1168 p, value = value[0:2], value[2:]
1169 switch p {
1170 case "PM":
1171 pmSet = true
1172 case "AM":
1173 amSet = true
1174 default:
1175 err = errBad
1176 }
1177 case stdpm:
1178 if len(value) < 2 {
1179 err = errBad
1180 break
1181 }
1182 p, value = value[0:2], value[2:]
1183 switch p {
1184 case "pm":
1185 pmSet = true
1186 case "am":
1187 amSet = true
1188 default:
1189 err = errBad
1190 }
1191 case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ:
1192 if (std == stdISO8601TZ || std == stdISO8601ShortTZ || std == stdISO8601ColonTZ) && len(value) >= 1 && value[0] == 'Z' {
1193 value = value[1:]
1194 z = UTC
1195 break
1196 }
1197 var sign, hour, min, seconds string
1198 if std == stdISO8601ColonTZ || std == stdNumColonTZ {
1199 if len(value) < 6 {
1200 err = errBad
1201 break
1202 }
1203 if value[3] != ':' {
1204 err = errBad
1205 break
1206 }
1207 sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], "00", value[6:]
1208 } else if std == stdNumShortTZ || std == stdISO8601ShortTZ {
1209 if len(value) < 3 {
1210 err = errBad
1211 break
1212 }
1213 sign, hour, min, seconds, value = value[0:1], value[1:3], "00", "00", value[3:]
1214 } else if std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ {
1215 if len(value) < 9 {
1216 err = errBad
1217 break
1218 }
1219 if value[3] != ':' || value[6] != ':' {
1220 err = errBad
1221 break
1222 }
1223 sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], value[7:9], value[9:]
1224 } else if std == stdISO8601SecondsTZ || std == stdNumSecondsTz {
1225 if len(value) < 7 {
1226 err = errBad
1227 break
1228 }
1229 sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], value[5:7], value[7:]
1230 } else {
1231 if len(value) < 5 {
1232 err = errBad
1233 break
1234 }
1235 sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], "00", value[5:]
1236 }
1237 var hr, mm, ss int
1238 hr, _, err = getnum(hour, true)
1239 if err == nil {
1240 mm, _, err = getnum(min, true)
1241 }
1242 if err == nil {
1243 ss, _, err = getnum(seconds, true)
1244 }
1245 zoneOffset = (hr*60+mm)*60 + ss
1246 switch sign[0] {
1247 case '+':
1248 case '-':
1249 zoneOffset = -zoneOffset
1250 default:
1251 err = errBad
1252 }
1253 case stdTZ:
1254
1255 if len(value) >= 3 && value[0:3] == "UTC" {
1256 z = UTC
1257 value = value[3:]
1258 break
1259 }
1260 n, ok := parseTimeZone(value)
1261 if !ok {
1262 err = errBad
1263 break
1264 }
1265 zoneName, value = value[:n], value[n:]
1266
1267 case stdFracSecond0:
1268
1269
1270 ndigit := 1 + digitsLen(std)
1271 if len(value) < ndigit {
1272 err = errBad
1273 break
1274 }
1275 nsec, rangeErrString, err = parseNanoseconds(value, ndigit)
1276 value = value[ndigit:]
1277
1278 case stdFracSecond9:
1279 if len(value) < 2 || !commaOrPeriod(value[0]) || value[1] < '0' || '9' < value[1] {
1280
1281 break
1282 }
1283
1284
1285 i := 0
1286 for i+1 < len(value) && '0' <= value[i+1] && value[i+1] <= '9' {
1287 i++
1288 }
1289 nsec, rangeErrString, err = parseNanoseconds(value, 1+i)
1290 value = value[1+i:]
1291 }
1292 if rangeErrString != "" {
1293 return Time{}, newParseError(alayout, avalue, stdstr, value, ": "+rangeErrString+" out of range")
1294 }
1295 if err != nil {
1296 return Time{}, newParseError(alayout, avalue, stdstr, hold, "")
1297 }
1298 }
1299 if pmSet && hour < 12 {
1300 hour += 12
1301 } else if amSet && hour == 12 {
1302 hour = 0
1303 }
1304
1305
1306 if yday >= 0 {
1307 var d int
1308 var m int
1309 if isLeap(year) {
1310 if yday == 31+29 {
1311 m = int(February)
1312 d = 29
1313 } else if yday > 31+29 {
1314 yday--
1315 }
1316 }
1317 if yday < 1 || yday > 365 {
1318 return Time{}, newParseError(alayout, avalue, "", value, ": day-of-year out of range")
1319 }
1320 if m == 0 {
1321 m = (yday-1)/31 + 1
1322 if int(daysBefore[m]) < yday {
1323 m++
1324 }
1325 d = yday - int(daysBefore[m-1])
1326 }
1327
1328
1329 if month >= 0 && month != m {
1330 return Time{}, newParseError(alayout, avalue, "", value, ": day-of-year does not match month")
1331 }
1332 month = m
1333 if day >= 0 && day != d {
1334 return Time{}, newParseError(alayout, avalue, "", value, ": day-of-year does not match day")
1335 }
1336 day = d
1337 } else {
1338 if month < 0 {
1339 month = int(January)
1340 }
1341 if day < 0 {
1342 day = 1
1343 }
1344 }
1345
1346
1347 if day < 1 || day > daysIn(Month(month), year) {
1348 return Time{}, newParseError(alayout, avalue, "", value, ": day out of range")
1349 }
1350
1351 if z != nil {
1352 return Date(year, Month(month), day, hour, min, sec, nsec, z), nil
1353 }
1354
1355 if zoneOffset != -1 {
1356 t := Date(year, Month(month), day, hour, min, sec, nsec, UTC)
1357 t.addSec(-int64(zoneOffset))
1358
1359
1360
1361 name, offset, _, _, _ := local.lookup(t.unixSec())
1362 if offset == zoneOffset && (zoneName == "" || name == zoneName) {
1363 t.setLoc(local)
1364 return t, nil
1365 }
1366
1367
1368 zoneNameCopy := stringslite.Clone(zoneName)
1369 t.setLoc(FixedZone(zoneNameCopy, zoneOffset))
1370 return t, nil
1371 }
1372
1373 if zoneName != "" {
1374 t := Date(year, Month(month), day, hour, min, sec, nsec, UTC)
1375
1376
1377 offset, ok := local.lookupName(zoneName, t.unixSec())
1378 if ok {
1379 t.addSec(-int64(offset))
1380 t.setLoc(local)
1381 return t, nil
1382 }
1383
1384
1385 if len(zoneName) > 3 && zoneName[:3] == "GMT" {
1386 offset, _ = atoi(zoneName[3:])
1387 offset *= 3600
1388 }
1389 zoneNameCopy := stringslite.Clone(zoneName)
1390 t.setLoc(FixedZone(zoneNameCopy, offset))
1391 return t, nil
1392 }
1393
1394
1395 return Date(year, Month(month), day, hour, min, sec, nsec, defaultLocation), nil
1396 }
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408 func parseTimeZone(value string) (length int, ok bool) {
1409 if len(value) < 3 {
1410 return 0, false
1411 }
1412
1413 if len(value) >= 4 && (value[:4] == "ChST" || value[:4] == "MeST") {
1414 return 4, true
1415 }
1416
1417 if value[:3] == "GMT" {
1418 length = parseGMT(value)
1419 return length, true
1420 }
1421
1422 if value[0] == '+' || value[0] == '-' {
1423 length = parseSignedOffset(value)
1424 ok := length > 0
1425 return length, ok
1426 }
1427
1428 var nUpper int
1429 for nUpper = 0; nUpper < 6; nUpper++ {
1430 if nUpper >= len(value) {
1431 break
1432 }
1433 if c := value[nUpper]; c < 'A' || 'Z' < c {
1434 break
1435 }
1436 }
1437 switch nUpper {
1438 case 0, 1, 2, 6:
1439 return 0, false
1440 case 5:
1441 if value[4] == 'T' {
1442 return 5, true
1443 }
1444 case 4:
1445
1446 if value[3] == 'T' || value[:4] == "WITA" {
1447 return 4, true
1448 }
1449 case 3:
1450 return 3, true
1451 }
1452 return 0, false
1453 }
1454
1455
1456
1457
1458 func parseGMT(value string) int {
1459 value = value[3:]
1460 if len(value) == 0 {
1461 return 3
1462 }
1463
1464 return 3 + parseSignedOffset(value)
1465 }
1466
1467
1468
1469
1470 func parseSignedOffset(value string) int {
1471 sign := value[0]
1472 if sign != '-' && sign != '+' {
1473 return 0
1474 }
1475 x, rem, err := leadingInt(value[1:])
1476
1477
1478 if err != nil || value[1:] == rem {
1479 return 0
1480 }
1481 if x > 23 {
1482 return 0
1483 }
1484 return len(value) - len(rem)
1485 }
1486
1487 func commaOrPeriod(b byte) bool {
1488 return b == '.' || b == ','
1489 }
1490
1491 func parseNanoseconds[bytes []byte | string](value bytes, nbytes int) (ns int, rangeErrString string, err error) {
1492 if !commaOrPeriod(value[0]) {
1493 err = errBad
1494 return
1495 }
1496 if nbytes > 10 {
1497 value = value[:10]
1498 nbytes = 10
1499 }
1500 if ns, err = atoi(value[1:nbytes]); err != nil {
1501 return
1502 }
1503 if ns < 0 {
1504 rangeErrString = "fractional second"
1505 return
1506 }
1507
1508
1509 scaleDigits := 10 - nbytes
1510 for i := 0; i < scaleDigits; i++ {
1511 ns *= 10
1512 }
1513 return
1514 }
1515
1516 var errLeadingInt = errors.New("time: bad [0-9]*")
1517
1518
1519 func leadingInt[bytes []byte | string](s bytes) (x uint64, rem bytes, err error) {
1520 i := 0
1521 for ; i < len(s); i++ {
1522 c := s[i]
1523 if c < '0' || c > '9' {
1524 break
1525 }
1526 if x > 1<<63/10 {
1527
1528 return 0, rem, errLeadingInt
1529 }
1530 x = x*10 + uint64(c) - '0'
1531 if x > 1<<63 {
1532
1533 return 0, rem, errLeadingInt
1534 }
1535 }
1536 return x, s[i:], nil
1537 }
1538
1539
1540
1541
1542 func leadingFraction(s string) (x uint64, scale float64, rem string) {
1543 i := 0
1544 scale = 1
1545 overflow := false
1546 for ; i < len(s); i++ {
1547 c := s[i]
1548 if c < '0' || c > '9' {
1549 break
1550 }
1551 if overflow {
1552 continue
1553 }
1554 if x > (1<<63-1)/10 {
1555
1556 overflow = true
1557 continue
1558 }
1559 y := x*10 + uint64(c) - '0'
1560 if y > 1<<63 {
1561 overflow = true
1562 continue
1563 }
1564 x = y
1565 scale *= 10
1566 }
1567 return x, scale, s[i:]
1568 }
1569
1570 var unitMap = map[string]uint64{
1571 "ns": uint64(Nanosecond),
1572 "us": uint64(Microsecond),
1573 "µs": uint64(Microsecond),
1574 "μs": uint64(Microsecond),
1575 "ms": uint64(Millisecond),
1576 "s": uint64(Second),
1577 "m": uint64(Minute),
1578 "h": uint64(Hour),
1579 }
1580
1581
1582
1583
1584
1585
1586 func ParseDuration(s string) (Duration, error) {
1587
1588 orig := s
1589 var d uint64
1590 neg := false
1591
1592
1593 if s != "" {
1594 c := s[0]
1595 if c == '-' || c == '+' {
1596 neg = c == '-'
1597 s = s[1:]
1598 }
1599 }
1600
1601 if s == "0" {
1602 return 0, nil
1603 }
1604 if s == "" {
1605 return 0, errors.New("time: invalid duration " + quote(orig))
1606 }
1607 for s != "" {
1608 var (
1609 v, f uint64
1610 scale float64 = 1
1611 )
1612
1613 var err error
1614
1615
1616 if !(s[0] == '.' || '0' <= s[0] && s[0] <= '9') {
1617 return 0, errors.New("time: invalid duration " + quote(orig))
1618 }
1619
1620 pl := len(s)
1621 v, s, err = leadingInt(s)
1622 if err != nil {
1623 return 0, errors.New("time: invalid duration " + quote(orig))
1624 }
1625 pre := pl != len(s)
1626
1627
1628 post := false
1629 if s != "" && s[0] == '.' {
1630 s = s[1:]
1631 pl := len(s)
1632 f, scale, s = leadingFraction(s)
1633 post = pl != len(s)
1634 }
1635 if !pre && !post {
1636
1637 return 0, errors.New("time: invalid duration " + quote(orig))
1638 }
1639
1640
1641 i := 0
1642 for ; i < len(s); i++ {
1643 c := s[i]
1644 if c == '.' || '0' <= c && c <= '9' {
1645 break
1646 }
1647 }
1648 if i == 0 {
1649 return 0, errors.New("time: missing unit in duration " + quote(orig))
1650 }
1651 u := s[:i]
1652 s = s[i:]
1653 unit, ok := unitMap[u]
1654 if !ok {
1655 return 0, errors.New("time: unknown unit " + quote(u) + " in duration " + quote(orig))
1656 }
1657 if v > 1<<63/unit {
1658
1659 return 0, errors.New("time: invalid duration " + quote(orig))
1660 }
1661 v *= unit
1662 if f > 0 {
1663
1664
1665 v += uint64(float64(f) * (float64(unit) / scale))
1666 if v > 1<<63 {
1667
1668 return 0, errors.New("time: invalid duration " + quote(orig))
1669 }
1670 }
1671 d += v
1672 if d > 1<<63 {
1673 return 0, errors.New("time: invalid duration " + quote(orig))
1674 }
1675 }
1676 if neg {
1677 return -Duration(d), nil
1678 }
1679 if d > 1<<63-1 {
1680 return 0, errors.New("time: invalid duration " + quote(orig))
1681 }
1682 return Duration(d), nil
1683 }
1684
View as plain text