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 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 var buf []byte
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 := []byte("time.Date(")
530 buf = appendInt(buf, t.Year(), 0)
531 month := t.Month()
532 if January <= month && month <= December {
533 buf = append(buf, ", time."...)
534 buf = append(buf, t.Month().String()...)
535 } else {
536
537
538 buf = appendInt(buf, int(month), 0)
539 }
540 buf = append(buf, ", "...)
541 buf = appendInt(buf, t.Day(), 0)
542 buf = append(buf, ", "...)
543 buf = appendInt(buf, t.Hour(), 0)
544 buf = append(buf, ", "...)
545 buf = appendInt(buf, t.Minute(), 0)
546 buf = append(buf, ", "...)
547 buf = appendInt(buf, t.Second(), 0)
548 buf = append(buf, ", "...)
549 buf = appendInt(buf, t.Nanosecond(), 0)
550 buf = append(buf, ", "...)
551 switch loc := t.Location(); loc {
552 case UTC, nil:
553 buf = append(buf, "time.UTC"...)
554 case Local:
555 buf = append(buf, "time.Local"...)
556 default:
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572 buf = append(buf, `time.Location(`...)
573 buf = append(buf, []byte(quote(loc.name))...)
574 buf = append(buf, `)`...)
575 }
576 buf = append(buf, ')')
577 return string(buf)
578 }
579
580
581
582
583
584
585
586 func (t Time) Format(layout string) string {
587 const bufSize = 64
588 var b []byte
589 max := len(layout) + 10
590 if max < bufSize {
591 var buf [bufSize]byte
592 b = buf[:0]
593 } else {
594 b = make([]byte, 0, max)
595 }
596 b = t.AppendFormat(b, layout)
597 return string(b)
598 }
599
600
601
602 func (t Time) AppendFormat(b []byte, layout string) []byte {
603 var (
604 name, offset, abs = t.locabs()
605
606 year int = -1
607 month Month
608 day int
609 yday int
610 hour int = -1
611 min int
612 sec int
613 )
614
615 for layout != "" {
616 prefix, std, suffix := nextStdChunk(layout)
617 if prefix != "" {
618 b = append(b, prefix...)
619 }
620 if std == 0 {
621 break
622 }
623 layout = suffix
624
625
626 if year < 0 && std&stdNeedDate != 0 {
627 year, month, day, yday = absDate(abs, true)
628 yday++
629 }
630
631
632 if hour < 0 && std&stdNeedClock != 0 {
633 hour, min, sec = absClock(abs)
634 }
635
636 switch std & stdMask {
637 case stdYear:
638 y := year
639 if y < 0 {
640 y = -y
641 }
642 b = appendInt(b, y%100, 2)
643 case stdLongYear:
644 b = appendInt(b, year, 4)
645 case stdMonth:
646 b = append(b, month.String()[:3]...)
647 case stdLongMonth:
648 m := month.String()
649 b = append(b, m...)
650 case stdNumMonth:
651 b = appendInt(b, int(month), 0)
652 case stdZeroMonth:
653 b = appendInt(b, int(month), 2)
654 case stdWeekDay:
655 b = append(b, absWeekday(abs).String()[:3]...)
656 case stdLongWeekDay:
657 s := absWeekday(abs).String()
658 b = append(b, s...)
659 case stdDay:
660 b = appendInt(b, day, 0)
661 case stdUnderDay:
662 if day < 10 {
663 b = append(b, ' ')
664 }
665 b = appendInt(b, day, 0)
666 case stdZeroDay:
667 b = appendInt(b, day, 2)
668 case stdUnderYearDay:
669 if yday < 100 {
670 b = append(b, ' ')
671 if yday < 10 {
672 b = append(b, ' ')
673 }
674 }
675 b = appendInt(b, yday, 0)
676 case stdZeroYearDay:
677 b = appendInt(b, yday, 3)
678 case stdHour:
679 b = appendInt(b, hour, 2)
680 case stdHour12:
681
682 hr := hour % 12
683 if hr == 0 {
684 hr = 12
685 }
686 b = appendInt(b, hr, 0)
687 case stdZeroHour12:
688
689 hr := hour % 12
690 if hr == 0 {
691 hr = 12
692 }
693 b = appendInt(b, hr, 2)
694 case stdMinute:
695 b = appendInt(b, min, 0)
696 case stdZeroMinute:
697 b = appendInt(b, min, 2)
698 case stdSecond:
699 b = appendInt(b, sec, 0)
700 case stdZeroSecond:
701 b = appendInt(b, sec, 2)
702 case stdPM:
703 if hour >= 12 {
704 b = append(b, "PM"...)
705 } else {
706 b = append(b, "AM"...)
707 }
708 case stdpm:
709 if hour >= 12 {
710 b = append(b, "pm"...)
711 } else {
712 b = append(b, "am"...)
713 }
714 case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumColonTZ, stdNumSecondsTz, stdNumShortTZ, stdNumColonSecondsTZ:
715
716
717 if offset == 0 && (std == stdISO8601TZ || std == stdISO8601ColonTZ || std == stdISO8601SecondsTZ || std == stdISO8601ShortTZ || std == stdISO8601ColonSecondsTZ) {
718 b = append(b, 'Z')
719 break
720 }
721 zone := offset / 60
722 absoffset := offset
723 if zone < 0 {
724 b = append(b, '-')
725 zone = -zone
726 absoffset = -absoffset
727 } else {
728 b = append(b, '+')
729 }
730 b = appendInt(b, zone/60, 2)
731 if std == stdISO8601ColonTZ || std == stdNumColonTZ || std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ {
732 b = append(b, ':')
733 }
734 if std != stdNumShortTZ && std != stdISO8601ShortTZ {
735 b = appendInt(b, zone%60, 2)
736 }
737
738
739 if std == stdISO8601SecondsTZ || std == stdNumSecondsTz || std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ {
740 if std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ {
741 b = append(b, ':')
742 }
743 b = appendInt(b, absoffset%60, 2)
744 }
745
746 case stdTZ:
747 if name != "" {
748 b = append(b, name...)
749 break
750 }
751
752
753 zone := offset / 60
754 if zone < 0 {
755 b = append(b, '-')
756 zone = -zone
757 } else {
758 b = append(b, '+')
759 }
760 b = appendInt(b, zone/60, 2)
761 b = appendInt(b, zone%60, 2)
762 case stdFracSecond0, stdFracSecond9:
763 b = formatNano(b, uint(t.Nanosecond()), std)
764 }
765 }
766 return b
767 }
768
769 var errBad = errors.New("bad value for field")
770
771
772 type ParseError struct {
773 Layout string
774 Value string
775 LayoutElem string
776 ValueElem string
777 Message string
778 }
779
780
781
782 const (
783 lowerhex = "0123456789abcdef"
784 runeSelf = 0x80
785 runeError = '\uFFFD'
786 )
787
788 func quote(s string) string {
789 buf := make([]byte, 1, len(s)+2)
790 buf[0] = '"'
791 for i, c := range s {
792 if c >= runeSelf || c < ' ' {
793
794
795
796
797
798
799 var width int
800 if c == runeError {
801 width = 1
802 if i+2 < len(s) && s[i:i+3] == string(runeError) {
803 width = 3
804 }
805 } else {
806 width = len(string(c))
807 }
808 for j := 0; j < width; j++ {
809 buf = append(buf, `\x`...)
810 buf = append(buf, lowerhex[s[i+j]>>4])
811 buf = append(buf, lowerhex[s[i+j]&0xF])
812 }
813 } else {
814 if c == '"' || c == '\\' {
815 buf = append(buf, '\\')
816 }
817 buf = append(buf, string(c)...)
818 }
819 }
820 buf = append(buf, '"')
821 return string(buf)
822 }
823
824
825 func (e *ParseError) Error() string {
826 if e.Message == "" {
827 return "parsing time " +
828 quote(e.Value) + " as " +
829 quote(e.Layout) + ": cannot parse " +
830 quote(e.ValueElem) + " as " +
831 quote(e.LayoutElem)
832 }
833 return "parsing time " +
834 quote(e.Value) + e.Message
835 }
836
837
838 func isDigit(s string, i int) bool {
839 if len(s) <= i {
840 return false
841 }
842 c := s[i]
843 return '0' <= c && c <= '9'
844 }
845
846
847
848
849 func getnum(s string, fixed bool) (int, string, error) {
850 if !isDigit(s, 0) {
851 return 0, s, errBad
852 }
853 if !isDigit(s, 1) {
854 if fixed {
855 return 0, s, errBad
856 }
857 return int(s[0] - '0'), s[1:], nil
858 }
859 return int(s[0]-'0')*10 + int(s[1]-'0'), s[2:], nil
860 }
861
862
863
864
865 func getnum3(s string, fixed bool) (int, string, error) {
866 var n, i int
867 for i = 0; i < 3 && isDigit(s, i); i++ {
868 n = n*10 + int(s[i]-'0')
869 }
870 if i == 0 || fixed && i != 3 {
871 return 0, s, errBad
872 }
873 return n, s[i:], nil
874 }
875
876 func cutspace(s string) string {
877 for len(s) > 0 && s[0] == ' ' {
878 s = s[1:]
879 }
880 return s
881 }
882
883
884
885 func skip(value, prefix string) (string, error) {
886 for len(prefix) > 0 {
887 if prefix[0] == ' ' {
888 if len(value) > 0 && value[0] != ' ' {
889 return value, errBad
890 }
891 prefix = cutspace(prefix)
892 value = cutspace(value)
893 continue
894 }
895 if len(value) == 0 || value[0] != prefix[0] {
896 return value, errBad
897 }
898 prefix = prefix[1:]
899 value = value[1:]
900 }
901 return value, nil
902 }
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 func Parse(layout, value string) (Time, error) {
946 return parse(layout, value, UTC, Local)
947 }
948
949
950
951
952
953
954 func ParseInLocation(layout, value string, loc *Location) (Time, error) {
955 return parse(layout, value, loc, loc)
956 }
957
958 func parse(layout, value string, defaultLocation, local *Location) (Time, error) {
959 alayout, avalue := layout, value
960 rangeErrString := ""
961 amSet := false
962 pmSet := false
963
964
965 var (
966 year int
967 month int = -1
968 day int = -1
969 yday int = -1
970 hour int
971 min int
972 sec int
973 nsec int
974 z *Location
975 zoneOffset int = -1
976 zoneName string
977 )
978
979
980 for {
981 var err error
982 prefix, std, suffix := nextStdChunk(layout)
983 stdstr := layout[len(prefix) : len(layout)-len(suffix)]
984 value, err = skip(value, prefix)
985 if err != nil {
986 return Time{}, &ParseError{alayout, avalue, prefix, value, ""}
987 }
988 if std == 0 {
989 if len(value) != 0 {
990 return Time{}, &ParseError{alayout, avalue, "", value, ": extra text: " + quote(value)}
991 }
992 break
993 }
994 layout = suffix
995 var p string
996 switch std & stdMask {
997 case stdYear:
998 if len(value) < 2 {
999 err = errBad
1000 break
1001 }
1002 hold := value
1003 p, value = value[0:2], value[2:]
1004 year, err = atoi(p)
1005 if err != nil {
1006 value = hold
1007 } else if year >= 69 {
1008 year += 1900
1009 } else {
1010 year += 2000
1011 }
1012 case stdLongYear:
1013 if len(value) < 4 || !isDigit(value, 0) {
1014 err = errBad
1015 break
1016 }
1017 p, value = value[0:4], value[4:]
1018 year, err = atoi(p)
1019 case stdMonth:
1020 month, value, err = lookup(shortMonthNames, value)
1021 month++
1022 case stdLongMonth:
1023 month, value, err = lookup(longMonthNames, value)
1024 month++
1025 case stdNumMonth, stdZeroMonth:
1026 month, value, err = getnum(value, std == stdZeroMonth)
1027 if err == nil && (month <= 0 || 12 < month) {
1028 rangeErrString = "month"
1029 }
1030 case stdWeekDay:
1031
1032 _, value, err = lookup(shortDayNames, value)
1033 case stdLongWeekDay:
1034 _, value, err = lookup(longDayNames, value)
1035 case stdDay, stdUnderDay, stdZeroDay:
1036 if std == stdUnderDay && len(value) > 0 && value[0] == ' ' {
1037 value = value[1:]
1038 }
1039 day, value, err = getnum(value, std == stdZeroDay)
1040
1041
1042 case stdUnderYearDay, stdZeroYearDay:
1043 for i := 0; i < 2; i++ {
1044 if std == stdUnderYearDay && len(value) > 0 && value[0] == ' ' {
1045 value = value[1:]
1046 }
1047 }
1048 yday, value, err = getnum3(value, std == stdZeroYearDay)
1049
1050
1051 case stdHour:
1052 hour, value, err = getnum(value, false)
1053 if hour < 0 || 24 <= hour {
1054 rangeErrString = "hour"
1055 }
1056 case stdHour12, stdZeroHour12:
1057 hour, value, err = getnum(value, std == stdZeroHour12)
1058 if hour < 0 || 12 < hour {
1059 rangeErrString = "hour"
1060 }
1061 case stdMinute, stdZeroMinute:
1062 min, value, err = getnum(value, std == stdZeroMinute)
1063 if min < 0 || 60 <= min {
1064 rangeErrString = "minute"
1065 }
1066 case stdSecond, stdZeroSecond:
1067 sec, value, err = getnum(value, std == stdZeroSecond)
1068 if sec < 0 || 60 <= sec {
1069 rangeErrString = "second"
1070 break
1071 }
1072
1073
1074 if len(value) >= 2 && commaOrPeriod(value[0]) && isDigit(value, 1) {
1075 _, std, _ = nextStdChunk(layout)
1076 std &= stdMask
1077 if std == stdFracSecond0 || std == stdFracSecond9 {
1078
1079 break
1080 }
1081
1082 n := 2
1083 for ; n < len(value) && isDigit(value, n); n++ {
1084 }
1085 nsec, rangeErrString, err = parseNanoseconds(value, n)
1086 value = value[n:]
1087 }
1088 case stdPM:
1089 if len(value) < 2 {
1090 err = errBad
1091 break
1092 }
1093 p, value = value[0:2], value[2:]
1094 switch p {
1095 case "PM":
1096 pmSet = true
1097 case "AM":
1098 amSet = true
1099 default:
1100 err = errBad
1101 }
1102 case stdpm:
1103 if len(value) < 2 {
1104 err = errBad
1105 break
1106 }
1107 p, value = value[0:2], value[2:]
1108 switch p {
1109 case "pm":
1110 pmSet = true
1111 case "am":
1112 amSet = true
1113 default:
1114 err = errBad
1115 }
1116 case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ:
1117 if (std == stdISO8601TZ || std == stdISO8601ShortTZ || std == stdISO8601ColonTZ) && len(value) >= 1 && value[0] == 'Z' {
1118 value = value[1:]
1119 z = UTC
1120 break
1121 }
1122 var sign, hour, min, seconds string
1123 if std == stdISO8601ColonTZ || std == stdNumColonTZ {
1124 if len(value) < 6 {
1125 err = errBad
1126 break
1127 }
1128 if value[3] != ':' {
1129 err = errBad
1130 break
1131 }
1132 sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], "00", value[6:]
1133 } else if std == stdNumShortTZ || std == stdISO8601ShortTZ {
1134 if len(value) < 3 {
1135 err = errBad
1136 break
1137 }
1138 sign, hour, min, seconds, value = value[0:1], value[1:3], "00", "00", value[3:]
1139 } else if std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ {
1140 if len(value) < 9 {
1141 err = errBad
1142 break
1143 }
1144 if value[3] != ':' || value[6] != ':' {
1145 err = errBad
1146 break
1147 }
1148 sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], value[7:9], value[9:]
1149 } else if std == stdISO8601SecondsTZ || std == stdNumSecondsTz {
1150 if len(value) < 7 {
1151 err = errBad
1152 break
1153 }
1154 sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], value[5:7], value[7:]
1155 } else {
1156 if len(value) < 5 {
1157 err = errBad
1158 break
1159 }
1160 sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], "00", value[5:]
1161 }
1162 var hr, mm, ss int
1163 hr, err = atoi(hour)
1164 if err == nil {
1165 mm, err = atoi(min)
1166 }
1167 if err == nil {
1168 ss, err = atoi(seconds)
1169 }
1170 zoneOffset = (hr*60+mm)*60 + ss
1171 switch sign[0] {
1172 case '+':
1173 case '-':
1174 zoneOffset = -zoneOffset
1175 default:
1176 err = errBad
1177 }
1178 case stdTZ:
1179
1180 if len(value) >= 3 && value[0:3] == "UTC" {
1181 z = UTC
1182 value = value[3:]
1183 break
1184 }
1185 n, ok := parseTimeZone(value)
1186 if !ok {
1187 err = errBad
1188 break
1189 }
1190 zoneName, value = value[:n], value[n:]
1191
1192 case stdFracSecond0:
1193
1194
1195 ndigit := 1 + digitsLen(std)
1196 if len(value) < ndigit {
1197 err = errBad
1198 break
1199 }
1200 nsec, rangeErrString, err = parseNanoseconds(value, ndigit)
1201 value = value[ndigit:]
1202
1203 case stdFracSecond9:
1204 if len(value) < 2 || !commaOrPeriod(value[0]) || value[1] < '0' || '9' < value[1] {
1205
1206 break
1207 }
1208
1209
1210 i := 0
1211 for i < 9 && i+1 < len(value) && '0' <= value[i+1] && value[i+1] <= '9' {
1212 i++
1213 }
1214 nsec, rangeErrString, err = parseNanoseconds(value, 1+i)
1215 value = value[1+i:]
1216 }
1217 if rangeErrString != "" {
1218 return Time{}, &ParseError{alayout, avalue, stdstr, value, ": " + rangeErrString + " out of range"}
1219 }
1220 if err != nil {
1221 return Time{}, &ParseError{alayout, avalue, stdstr, value, ""}
1222 }
1223 }
1224 if pmSet && hour < 12 {
1225 hour += 12
1226 } else if amSet && hour == 12 {
1227 hour = 0
1228 }
1229
1230
1231 if yday >= 0 {
1232 var d int
1233 var m int
1234 if isLeap(year) {
1235 if yday == 31+29 {
1236 m = int(February)
1237 d = 29
1238 } else if yday > 31+29 {
1239 yday--
1240 }
1241 }
1242 if yday < 1 || yday > 365 {
1243 return Time{}, &ParseError{alayout, avalue, "", value, ": day-of-year out of range"}
1244 }
1245 if m == 0 {
1246 m = (yday-1)/31 + 1
1247 if int(daysBefore[m]) < yday {
1248 m++
1249 }
1250 d = yday - int(daysBefore[m-1])
1251 }
1252
1253
1254 if month >= 0 && month != m {
1255 return Time{}, &ParseError{alayout, avalue, "", value, ": day-of-year does not match month"}
1256 }
1257 month = m
1258 if day >= 0 && day != d {
1259 return Time{}, &ParseError{alayout, avalue, "", value, ": day-of-year does not match day"}
1260 }
1261 day = d
1262 } else {
1263 if month < 0 {
1264 month = int(January)
1265 }
1266 if day < 0 {
1267 day = 1
1268 }
1269 }
1270
1271
1272 if day < 1 || day > daysIn(Month(month), year) {
1273 return Time{}, &ParseError{alayout, avalue, "", value, ": day out of range"}
1274 }
1275
1276 if z != nil {
1277 return Date(year, Month(month), day, hour, min, sec, nsec, z), nil
1278 }
1279
1280 if zoneOffset != -1 {
1281 t := Date(year, Month(month), day, hour, min, sec, nsec, UTC)
1282 t.addSec(-int64(zoneOffset))
1283
1284
1285
1286 name, offset, _, _, _ := local.lookup(t.unixSec())
1287 if offset == zoneOffset && (zoneName == "" || name == zoneName) {
1288 t.setLoc(local)
1289 return t, nil
1290 }
1291
1292
1293 t.setLoc(FixedZone(zoneName, zoneOffset))
1294 return t, nil
1295 }
1296
1297 if zoneName != "" {
1298 t := Date(year, Month(month), day, hour, min, sec, nsec, UTC)
1299
1300
1301 offset, ok := local.lookupName(zoneName, t.unixSec())
1302 if ok {
1303 t.addSec(-int64(offset))
1304 t.setLoc(local)
1305 return t, nil
1306 }
1307
1308
1309 if len(zoneName) > 3 && zoneName[:3] == "GMT" {
1310 offset, _ = atoi(zoneName[3:])
1311 offset *= 3600
1312 }
1313 t.setLoc(FixedZone(zoneName, offset))
1314 return t, nil
1315 }
1316
1317
1318 return Date(year, Month(month), day, hour, min, sec, nsec, defaultLocation), nil
1319 }
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331 func parseTimeZone(value string) (length int, ok bool) {
1332 if len(value) < 3 {
1333 return 0, false
1334 }
1335
1336 if len(value) >= 4 && (value[:4] == "ChST" || value[:4] == "MeST") {
1337 return 4, true
1338 }
1339
1340 if value[:3] == "GMT" {
1341 length = parseGMT(value)
1342 return length, true
1343 }
1344
1345 if value[0] == '+' || value[0] == '-' {
1346 length = parseSignedOffset(value)
1347 ok := length > 0
1348 return length, ok
1349 }
1350
1351 var nUpper int
1352 for nUpper = 0; nUpper < 6; nUpper++ {
1353 if nUpper >= len(value) {
1354 break
1355 }
1356 if c := value[nUpper]; c < 'A' || 'Z' < c {
1357 break
1358 }
1359 }
1360 switch nUpper {
1361 case 0, 1, 2, 6:
1362 return 0, false
1363 case 5:
1364 if value[4] == 'T' {
1365 return 5, true
1366 }
1367 case 4:
1368
1369 if value[3] == 'T' || value[:4] == "WITA" {
1370 return 4, true
1371 }
1372 case 3:
1373 return 3, true
1374 }
1375 return 0, false
1376 }
1377
1378
1379
1380
1381 func parseGMT(value string) int {
1382 value = value[3:]
1383 if len(value) == 0 {
1384 return 3
1385 }
1386
1387 return 3 + parseSignedOffset(value)
1388 }
1389
1390
1391
1392
1393 func parseSignedOffset(value string) int {
1394 sign := value[0]
1395 if sign != '-' && sign != '+' {
1396 return 0
1397 }
1398 x, rem, err := leadingInt(value[1:])
1399
1400
1401 if err != nil || value[1:] == rem {
1402 return 0
1403 }
1404 if sign == '-' {
1405 x = -x
1406 }
1407 if x < -23 || 23 < x {
1408 return 0
1409 }
1410 return len(value) - len(rem)
1411 }
1412
1413 func commaOrPeriod(b byte) bool {
1414 return b == '.' || b == ','
1415 }
1416
1417 func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string, err error) {
1418 if !commaOrPeriod(value[0]) {
1419 err = errBad
1420 return
1421 }
1422 if ns, err = atoi(value[1:nbytes]); err != nil {
1423 return
1424 }
1425 if ns < 0 || 1e9 <= ns {
1426 rangeErrString = "fractional second"
1427 return
1428 }
1429
1430
1431
1432 scaleDigits := 10 - nbytes
1433 for i := 0; i < scaleDigits; i++ {
1434 ns *= 10
1435 }
1436 return
1437 }
1438
1439 var errLeadingInt = errors.New("time: bad [0-9]*")
1440
1441
1442 func leadingInt(s string) (x int64, rem string, err error) {
1443 i := 0
1444 for ; i < len(s); i++ {
1445 c := s[i]
1446 if c < '0' || c > '9' {
1447 break
1448 }
1449 if x > (1<<63-1)/10 {
1450
1451 return 0, "", errLeadingInt
1452 }
1453 x = x*10 + int64(c) - '0'
1454 if x < 0 {
1455
1456 return 0, "", errLeadingInt
1457 }
1458 }
1459 return x, s[i:], nil
1460 }
1461
1462
1463
1464
1465 func leadingFraction(s string) (x int64, scale float64, rem string) {
1466 i := 0
1467 scale = 1
1468 overflow := false
1469 for ; i < len(s); i++ {
1470 c := s[i]
1471 if c < '0' || c > '9' {
1472 break
1473 }
1474 if overflow {
1475 continue
1476 }
1477 if x > (1<<63-1)/10 {
1478
1479 overflow = true
1480 continue
1481 }
1482 y := x*10 + int64(c) - '0'
1483 if y < 0 {
1484 overflow = true
1485 continue
1486 }
1487 x = y
1488 scale *= 10
1489 }
1490 return x, scale, s[i:]
1491 }
1492
1493 var unitMap = map[string]int64{
1494 "ns": int64(Nanosecond),
1495 "us": int64(Microsecond),
1496 "µs": int64(Microsecond),
1497 "μs": int64(Microsecond),
1498 "ms": int64(Millisecond),
1499 "s": int64(Second),
1500 "m": int64(Minute),
1501 "h": int64(Hour),
1502 }
1503
1504
1505
1506
1507
1508
1509 func ParseDuration(s string) (Duration, error) {
1510
1511 orig := s
1512 var d int64
1513 neg := false
1514
1515
1516 if s != "" {
1517 c := s[0]
1518 if c == '-' || c == '+' {
1519 neg = c == '-'
1520 s = s[1:]
1521 }
1522 }
1523
1524 if s == "0" {
1525 return 0, nil
1526 }
1527 if s == "" {
1528 return 0, errors.New("time: invalid duration " + quote(orig))
1529 }
1530 for s != "" {
1531 var (
1532 v, f int64
1533 scale float64 = 1
1534 )
1535
1536 var err error
1537
1538
1539 if !(s[0] == '.' || '0' <= s[0] && s[0] <= '9') {
1540 return 0, errors.New("time: invalid duration " + quote(orig))
1541 }
1542
1543 pl := len(s)
1544 v, s, err = leadingInt(s)
1545 if err != nil {
1546 return 0, errors.New("time: invalid duration " + quote(orig))
1547 }
1548 pre := pl != len(s)
1549
1550
1551 post := false
1552 if s != "" && s[0] == '.' {
1553 s = s[1:]
1554 pl := len(s)
1555 f, scale, s = leadingFraction(s)
1556 post = pl != len(s)
1557 }
1558 if !pre && !post {
1559
1560 return 0, errors.New("time: invalid duration " + quote(orig))
1561 }
1562
1563
1564 i := 0
1565 for ; i < len(s); i++ {
1566 c := s[i]
1567 if c == '.' || '0' <= c && c <= '9' {
1568 break
1569 }
1570 }
1571 if i == 0 {
1572 return 0, errors.New("time: missing unit in duration " + quote(orig))
1573 }
1574 u := s[:i]
1575 s = s[i:]
1576 unit, ok := unitMap[u]
1577 if !ok {
1578 return 0, errors.New("time: unknown unit " + quote(u) + " in duration " + quote(orig))
1579 }
1580 if v > (1<<63-1)/unit {
1581
1582 return 0, errors.New("time: invalid duration " + quote(orig))
1583 }
1584 v *= unit
1585 if f > 0 {
1586
1587
1588 v += int64(float64(f) * (float64(unit) / scale))
1589 if v < 0 {
1590
1591 return 0, errors.New("time: invalid duration " + quote(orig))
1592 }
1593 }
1594 d += v
1595 if d < 0 {
1596
1597 return 0, errors.New("time: invalid duration " + quote(orig))
1598 }
1599 }
1600
1601 if neg {
1602 d = -d
1603 }
1604 return Duration(d), nil
1605 }
1606
View as plain text