@@ -4,6 +4,9 @@ package mpd
4
4
5
5
import (
6
6
"encoding/xml"
7
+ "errors"
8
+ "strconv"
9
+ "strings"
7
10
"time"
8
11
)
9
12
@@ -13,6 +16,15 @@ func (d Duration) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
13
16
return xml.Attr {name , d .String ()}, nil
14
17
}
15
18
19
+ func (d * Duration ) UnmarshalXMLAttr (attr xml.Attr ) error {
20
+ dur , err := parseDuration (attr .Value )
21
+ if err != nil {
22
+ return err
23
+ }
24
+ * d = Duration (dur )
25
+ return nil
26
+ }
27
+
16
28
// String renders a Duration in XML Duration Data Type format
17
29
func (d * Duration ) String () string {
18
30
// Largest time is 2540400h10m10.000000000s
@@ -126,3 +138,80 @@ func fmtInt(buf []byte, v uint64) int {
126
138
}
127
139
return w
128
140
}
141
+
142
+ func parseDuration (str string ) (time.Duration , error ) {
143
+ if len (str ) < 3 {
144
+ return 0 , errors .New ("input duration too short" )
145
+ }
146
+
147
+ var minus bool
148
+ offset := 0
149
+ if str [offset ] == '-' {
150
+ minus = true
151
+ offset ++
152
+ }
153
+
154
+ if str [offset ] != 'P' {
155
+ return 0 , errors .New ("input duration does not have a valid prefix" )
156
+ }
157
+ offset ++
158
+
159
+ var dateStr , timeStr string
160
+ if i := strings .IndexByte (str [offset :], 'T' ); i != - 1 {
161
+ dateStr = str [offset : offset + i ]
162
+ timeStr = str [offset + i + 1 :]
163
+ } else {
164
+ dateStr = str [offset :]
165
+ }
166
+
167
+ var sum float64
168
+ if len (dateStr ) > 0 {
169
+ if i := strings .IndexByte (dateStr , 'Y' ); i != - 1 {
170
+ return 0 , errors .New ("input duration contains Years notation" )
171
+ }
172
+
173
+ if i := strings .IndexByte (dateStr , 'M' ); i != - 1 {
174
+ return 0 , errors .New ("input duration contains Months notation" )
175
+ }
176
+
177
+ if i := strings .IndexByte (dateStr , 'D' ); i != - 1 {
178
+ days , err := strconv .Atoi (dateStr [0 :i ])
179
+ if err != nil {
180
+ return 0 , err
181
+ }
182
+ sum += float64 (days ) * 86400
183
+ }
184
+ }
185
+
186
+ if len (timeStr ) > 0 {
187
+ var pos int
188
+ if i := strings .IndexByte (timeStr [pos :], 'H' ); i != - 1 {
189
+ hours , err := strconv .ParseInt (timeStr [pos :pos + i ], 10 , 64 )
190
+ if err != nil {
191
+ return 0 , err
192
+ }
193
+ sum += float64 (hours ) * 3600
194
+ pos += i + 1
195
+ }
196
+ if i := strings .IndexByte (timeStr [pos :], 'M' ); i != - 1 {
197
+ minutes , err := strconv .ParseInt (timeStr [pos :pos + i ], 10 , 64 )
198
+ if err != nil {
199
+ return 0 , err
200
+ }
201
+ sum += float64 (minutes ) * 60
202
+ pos += i + 1
203
+ }
204
+ if i := strings .IndexByte (timeStr [pos :], 'S' ); i != - 1 {
205
+ seconds , err := strconv .ParseFloat (timeStr [pos :pos + i ], 64 )
206
+ if err != nil {
207
+ return 0 , err
208
+ }
209
+ sum += seconds
210
+ }
211
+ }
212
+
213
+ if minus {
214
+ sum = - sum
215
+ }
216
+ return time .Duration (sum * float64 (time .Second )), nil
217
+ }
0 commit comments