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