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