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