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