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