@@ -4,6 +4,9 @@ package mpd
44
55import (
66 "encoding/xml"
7+ "errors"
8+ "strconv"
9+ "strings"
710 "time"
811)
912
@@ -13,6 +16,15 @@ func (d Duration) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
1316 return xml.Attr {name , d .String ()}, nil
1417}
1518
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+
1628// String renders a Duration in XML Duration Data Type format
1729func (d * Duration ) String () string {
1830 // Largest time is 2540400h10m10.000000000s
@@ -126,3 +138,95 @@ func fmtInt(buf []byte, v uint64) int {
126138 }
127139 return w
128140}
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+ base := time .Unix (0 , 0 )
160+ t := base
161+
162+ var dateStr , timeStr string
163+ if i := strings .IndexByte (str [offset :], 'T' ); i != - 1 {
164+ dateStr = str [offset : offset + i ]
165+ timeStr = str [offset + i + 1 :]
166+ } else {
167+ dateStr = str [offset :]
168+ }
169+
170+ if len (dateStr ) > 0 {
171+ var pos int
172+ var err error
173+ var years , months , days int
174+ if i := strings .IndexByte (dateStr [pos :], 'Y' ); i != - 1 {
175+ years , err = strconv .Atoi (dateStr [pos : pos + i ])
176+ if err != nil {
177+ return 0 , err
178+ }
179+ pos += i + 1
180+ }
181+
182+ if i := strings .IndexByte (dateStr [pos :], 'M' ); i != - 1 {
183+ months , err = strconv .Atoi (dateStr [pos : pos + i ])
184+ if err != nil {
185+ return 0 , err
186+ }
187+ pos += i + 1
188+ }
189+
190+ if i := strings .IndexByte (dateStr [pos :], 'D' ); i != - 1 {
191+ days , err = strconv .Atoi (dateStr [pos : pos + i ])
192+ if err != nil {
193+ return 0 , err
194+ }
195+ }
196+ t = t .AddDate (years , months , days )
197+ }
198+
199+ if len (timeStr ) > 0 {
200+ var pos int
201+ var sum float64
202+ if i := strings .IndexByte (timeStr [pos :], 'H' ); i != - 1 {
203+ hours , err := strconv .ParseInt (timeStr [pos :pos + i ], 10 , 64 )
204+ if err != nil {
205+ return 0 , err
206+ }
207+ sum += float64 (hours ) * 3600
208+ pos += i + 1
209+ }
210+ if i := strings .IndexByte (timeStr [pos :], 'M' ); i != - 1 {
211+ minutes , err := strconv .ParseInt (timeStr [pos :pos + i ], 10 , 64 )
212+ if err != nil {
213+ return 0 , err
214+ }
215+ sum += float64 (minutes ) * 60
216+ pos += i + 1
217+ }
218+ if i := strings .IndexByte (timeStr [pos :], 'S' ); i != - 1 {
219+ seconds , err := strconv .ParseFloat (timeStr [pos :pos + i ], 64 )
220+ if err != nil {
221+ return 0 , err
222+ }
223+ sum += seconds
224+ }
225+ t = t .Add (time .Duration (sum * float64 (time .Second )))
226+ }
227+
228+ if minus {
229+ return - t .Sub (base ), nil
230+ }
231+ return t .Sub (base ), nil
232+ }
0 commit comments