Skip to content
This repository has been archived by the owner on Dec 8, 2024. It is now read-only.

Time Parsing fix for #EXT-X-PROGRAM-DATE-TIME #78

Merged
merged 6 commits into from
Mar 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ import (

var reKeyValue = regexp.MustCompile(`([a-zA-Z_-]+)=("[^"]+"|[^",]+)`)

// Allow globally apply and/or override Time Parser function.
// Available variants:
// * FullTimeParse - implements full featured ISO/IEC 8601:2004
// * StrictTimeParse - implements only RFC3339 Nanoseconds format
var TimeParse func(value string) (time.Time, error) = FullTimeParse

// Decode parses a master playlist passed from the buffer. If `strict`
// parameter is true then it returns first syntax error.
func (p *MasterPlaylist) Decode(data bytes.Buffer, strict bool) error {
Expand Down Expand Up @@ -501,7 +507,7 @@ func decodeLineOfMediaPlaylist(p *MediaPlaylist, wv *WV, state *decodingState, l
case !state.tagProgramDateTime && strings.HasPrefix(line, "#EXT-X-PROGRAM-DATE-TIME:"):
state.tagProgramDateTime = true
state.listType = MEDIA
if state.programDateTime, err = time.Parse(DATETIME, line[25:]); strict && err != nil {
if state.programDateTime, err = TimeParse(line[25:]); strict && err != nil {
return err
}
case !state.tagRange && strings.HasPrefix(line, "#EXT-X-BYTERANGE:"):
Expand Down Expand Up @@ -638,3 +644,27 @@ func decodeLineOfMediaPlaylist(p *MediaPlaylist, wv *WV, state *decodingState, l
}
return err
}

// StrictTimeParse implements RFC3339 with Nanoseconds accuracy.
func StrictTimeParse(value string) (time.Time, error) {
return time.Parse(DATETIME, value)
}

// FullTimeParse implements ISO/IEC 8601:2004.
func FullTimeParse(value string) (time.Time, error) {
layouts := []string{
"2006-01-02T15:04:05.999999999Z0700",
"2006-01-02T15:04:05.999999999Z07:00",
"2006-01-02T15:04:05.999999999Z07",
}
var (
err error
t time.Time
)
for _, layout := range layouts {
if t, err = time.Parse(layout, value); err == nil {
return t, nil
}
}
return t, err
}
52 changes: 52 additions & 0 deletions reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,58 @@ func TestDecodeMediaPlaylistAutoDetectExtend(t *testing.T) {
}
}

// Test for FullTimeParse of EXT-X-PROGRAM-DATE-TIME
// We testing ISO/IEC 8601:2004 where we can get time in UTC, UTC with Nanoseconds
// timeZone in formats '±00:00', '±0000', '±00'
// m3u8.FullTimeParse()
func TestFullTimeParse(t *testing.T) {
var timestamps = []struct {
name string
value string
}{
{"time_in_utc", "2006-01-02T15:04:05Z"},
{"time_in_utc_nano", "2006-01-02T15:04:05.123456789Z"},
{"time_with_positive_zone_and_colon", "2006-01-02T15:04:05+01:00"},
{"time_with_positive_zone_no_colon", "2006-01-02T15:04:05+0100"},
{"time_with_positive_zone_2digits", "2006-01-02T15:04:05+01"},
{"time_with_negative_zone_and_colon", "2006-01-02T15:04:05-01:00"},
{"time_with_negative_zone_no_colon", "2006-01-02T15:04:05-0100"},
{"time_with_negative_zone_2digits", "2006-01-02T15:04:05-01"},
}

var err error
for _, tstamp := range timestamps {
_, err = FullTimeParse(tstamp.value)
if err != nil {
t.Errorf("FullTimeParse Error at %s [%s]: %s", tstamp.name, tstamp.value, err)
}
}
}

// Test for StrictTimeParse of EXT-X-PROGRAM-DATE-TIME
// We testing Strict format of RFC3339 where we can get time in UTC, UTC with Nanoseconds
// timeZone in formats '±00:00', '±0000', '±00'
// m3u8.StrictTimeParse()
func TestStrictTimeParse(t *testing.T) {
var timestamps = []struct {
name string
value string
}{
{"time_in_utc", "2006-01-02T15:04:05Z"},
{"time_in_utc_nano", "2006-01-02T15:04:05.123456789Z"},
{"time_with_positive_zone_and_colon", "2006-01-02T15:04:05+01:00"},
{"time_with_negative_zone_and_colon", "2006-01-02T15:04:05-01:00"},
}

var err error
for _, tstamp := range timestamps {
_, err = StrictTimeParse(tstamp.value)
if err != nil {
t.Errorf("StrictTimeParse Error at %s [%s]: %s", tstamp.name, tstamp.value, err)
}
}
}

/***************************
* Code parsing examples *
***************************/
Expand Down