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