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