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