| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- package saml
- import (
- "fmt"
- "regexp"
- "strconv"
- "strings"
- "time"
- )
- // Duration is a time.Duration that uses the xsd:duration format for text
- // marshalling and unmarshalling.
- type Duration time.Duration
- // MarshalText implements the encoding.TextMarshaler interface.
- func (d Duration) MarshalText() ([]byte, error) {
- if d == 0 {
- return nil, nil
- }
- out := "PT"
- if d < 0 {
- d *= -1
- out = "-" + out
- }
- h := time.Duration(d) / time.Hour
- m := time.Duration(d) % time.Hour / time.Minute
- s := time.Duration(d) % time.Minute / time.Second
- ns := time.Duration(d) % time.Second
- if h > 0 {
- out += fmt.Sprintf("%dH", h)
- }
- if m > 0 {
- out += fmt.Sprintf("%dM", m)
- }
- if s > 0 || ns > 0 {
- out += fmt.Sprintf("%d", s)
- if ns > 0 {
- out += strings.TrimRight(fmt.Sprintf(".%09d", ns), "0")
- }
- out += "S"
- }
- return []byte(out), nil
- }
- const (
- day = 24 * time.Hour
- month = 30 * day // Assumed to be 30 days.
- year = 365 * day // Assumed to be non-leap year.
- )
- var (
- durationRegexp = regexp.MustCompile(`^(-?)P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(.+))?$`)
- durationTimeRegexp = regexp.MustCompile(`^(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?$`)
- )
- // UnmarshalText implements the encoding.TextUnmarshaler interface.
- func (d *Duration) UnmarshalText(text []byte) error {
- if text == nil {
- *d = 0
- return nil
- }
- var (
- out time.Duration
- sign time.Duration = 1
- )
- match := durationRegexp.FindStringSubmatch(string(text))
- if match == nil || strings.Join(match[2:6], "") == "" {
- return fmt.Errorf("invalid duration (%s)", text)
- }
- if match[1] == "-" {
- sign = -1
- }
- if match[2] != "" {
- y, err := strconv.Atoi(match[2])
- if err != nil {
- return fmt.Errorf("invalid duration years (%s): %s", text, err)
- }
- out += time.Duration(y) * year
- }
- if match[3] != "" {
- m, err := strconv.Atoi(match[3])
- if err != nil {
- return fmt.Errorf("invalid duration months (%s): %s", text, err)
- }
- out += time.Duration(m) * month
- }
- if match[4] != "" {
- d, err := strconv.Atoi(match[4])
- if err != nil {
- return fmt.Errorf("invalid duration days (%s): %s", text, err)
- }
- out += time.Duration(d) * day
- }
- if match[5] != "" {
- match := durationTimeRegexp.FindStringSubmatch(match[5])
- if match == nil {
- return fmt.Errorf("invalid duration (%s)", text)
- }
- if match[1] != "" {
- h, err := strconv.Atoi(match[1])
- if err != nil {
- return fmt.Errorf("invalid duration hours (%s): %s", text, err)
- }
- out += time.Duration(h) * time.Hour
- }
- if match[2] != "" {
- m, err := strconv.Atoi(match[2])
- if err != nil {
- return fmt.Errorf("invalid duration minutes (%s): %s", text, err)
- }
- out += time.Duration(m) * time.Minute
- }
- if match[3] != "" {
- s, err := strconv.ParseFloat(match[3], 64)
- if err != nil {
- return fmt.Errorf("invalid duration seconds (%s): %s", text, err)
- }
- out += time.Duration(s * float64(time.Second))
- }
- }
- *d = Duration(sign * out)
- return nil
- }
|