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