...
1 package ber
2
3 import (
4 "bytes"
5 "errors"
6 "fmt"
7 "strconv"
8 "time"
9 )
10
11
12 var ErrInvalidTimeFormat = errors.New("invalid time format")
13
14 var zeroTime = time.Time{}
15
16
17
18
19
20 func ParseGeneralizedTime(v []byte) (time.Time, error) {
21 var format string
22 var fract time.Duration
23
24 str := []byte(DecodeString(v))
25 tzIndex := bytes.IndexAny(str, "Z+-")
26 if tzIndex < 0 {
27 return zeroTime, ErrInvalidTimeFormat
28 }
29
30 dot := bytes.IndexAny(str, ".,")
31 switch dot {
32 case -1:
33 switch tzIndex {
34 case 10:
35 format = `2006010215Z`
36 case 12:
37 format = `200601021504Z`
38 case 14:
39 format = `20060102150405Z`
40 default:
41 return zeroTime, ErrInvalidTimeFormat
42 }
43
44 case 10, 12:
45 if tzIndex < dot {
46 return zeroTime, ErrInvalidTimeFormat
47 }
48
49 str[dot] = '.'
50
51
52
53
54
55
56
57 f, err := strconv.ParseFloat(string(str[dot:tzIndex]), 64)
58 if err != nil {
59 return zeroTime, fmt.Errorf("failed to parse float: %s", err)
60 }
61
62 str = append(str[:dot], str[tzIndex:]...)
63 tzIndex = dot
64
65 if dot == 10 {
66 fract = time.Duration(int64(f * float64(time.Hour)))
67 format = `2006010215Z`
68 } else {
69 fract = time.Duration(int64(f * float64(time.Minute)))
70 format = `200601021504Z`
71 }
72
73 case 14:
74 if tzIndex < dot {
75 return zeroTime, ErrInvalidTimeFormat
76 }
77 str[dot] = '.'
78
79 format = `20060102150405Z`
80
81 default:
82 return zeroTime, ErrInvalidTimeFormat
83 }
84
85 l := len(str)
86 switch l - tzIndex {
87 case 1:
88 if str[l-1] != 'Z' {
89 return zeroTime, ErrInvalidTimeFormat
90 }
91 case 3:
92 format += `0700`
93 str = append(str, []byte("00")...)
94 case 5:
95 format += `0700`
96 default:
97 return zeroTime, ErrInvalidTimeFormat
98 }
99
100 t, err := time.Parse(format, string(str))
101 if err != nil {
102 return zeroTime, fmt.Errorf("%s: %s", ErrInvalidTimeFormat, err)
103 }
104 return t.Add(fract), nil
105 }
106
View as plain text