// Parses an ISO8601 (with designators) string. // See the following links for examples: // - http://www.postgresql.org/docs/9.1/static/datatype-datetime.html#DATATYPE-INTERVAL-INPUT-EXAMPLES // - https://en.wikipedia.org/wiki/ISO_8601#Time_intervals // - https://en.wikipedia.org/wiki/ISO_8601#Durations func iso8601ToDuration(s string) (duration.Duration, error) { var d duration.Duration if len(s) == 0 || s[0] != 'P' { return d, fmt.Errorf("interval: invalid iso8601 duration %s", s) } // Advance to offset 1, since we don't care about the leading P. l := intervalLexer{str: s, offset: 1, err: nil} unitMap := isoDateUnitMap for l.offset < len(s) { // Check if we're in the time part yet. if s[l.offset] == 'T' { unitMap = isoTimeUnitMap l.offset++ } v := l.consumeInt() u := l.consumeUnit('T') if l.err != nil { return d, l.err } if unit, ok := unitMap[u]; ok { d = d.Add(unit.Mul(v)) } else { return d, fmt.Errorf("interval: unknown unit %s in iso8601 duration %s", u, s) } } return d, nil }
// EncodeDurationDescending is the descending version of EncodeDurationAscending. func EncodeDurationDescending(b []byte, d duration.Duration) ([]byte, error) { sortNanos, months, days, err := d.Encode() if err != nil { // TODO(dan): Handle this using d.EncodeBigInt() and the // durationBigNeg/durationBigPos markers. return b, err } b = append(b, durationMarker) b = EncodeVarintDescending(b, sortNanos) b = EncodeVarintDescending(b, months) b = EncodeVarintDescending(b, days) return b, nil }
// Parses a duration in the "traditional" Postgres format. func postgresToDuration(s string) (duration.Duration, error) { var d duration.Duration l := intervalLexer{str: s, offset: 0, err: nil} for l.offset != len(l.str) { v := l.consumeInt() l.consumeSpaces() u := l.consumeUnit(' ') l.consumeSpaces() if unit, ok := postgresUnitMap[u]; ok { d = d.Add(unit.Mul(v)) } else { return d, fmt.Errorf("interval: unknown unit %s in postgres duration %s", u, s) } } return d, nil }