File: parseduration.go

package info (click to toggle)
rclone 1.45-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 24,300 kB
  • sloc: python: 364; sh: 255; makefile: 190; xml: 30
file content (103 lines) | stat: -rw-r--r-- 2,357 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package fs

import (
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"
)

// Duration is a time.Duration with some more parsing options
type Duration time.Duration

// DurationOff is the default value for flags which can be turned off
const DurationOff = Duration((1 << 63) - 1)

// Turn Duration into a string
func (d Duration) String() string {
	if d == DurationOff {
		return "off"
	}
	for i := len(ageSuffixes) - 2; i >= 0; i-- {
		ageSuffix := &ageSuffixes[i]
		if math.Abs(float64(d)) >= float64(ageSuffix.Multiplier) {
			timeUnits := float64(d) / float64(ageSuffix.Multiplier)
			return strconv.FormatFloat(timeUnits, 'f', -1, 64) + ageSuffix.Suffix
		}
	}
	return time.Duration(d).String()
}

// IsSet returns if the duration is != DurationOff
func (d Duration) IsSet() bool {
	return d != DurationOff
}

// We use time conventions
var ageSuffixes = []struct {
	Suffix     string
	Multiplier time.Duration
}{
	{Suffix: "d", Multiplier: time.Hour * 24},
	{Suffix: "w", Multiplier: time.Hour * 24 * 7},
	{Suffix: "M", Multiplier: time.Hour * 24 * 30},
	{Suffix: "y", Multiplier: time.Hour * 24 * 365},

	// Default to second
	{Suffix: "", Multiplier: time.Second},
}

// ParseDuration parses a duration string. Accept ms|s|m|h|d|w|M|y suffixes. Defaults to second if not provided
func ParseDuration(age string) (time.Duration, error) {
	var period float64

	if age == "off" {
		return time.Duration(DurationOff), nil
	}

	// Attempt to parse as a time.Duration first
	d, err := time.ParseDuration(age)
	if err == nil {
		return d, nil
	}

	for _, ageSuffix := range ageSuffixes {
		if strings.HasSuffix(age, ageSuffix.Suffix) {
			numberString := age[:len(age)-len(ageSuffix.Suffix)]
			var err error
			period, err = strconv.ParseFloat(numberString, 64)
			if err != nil {
				return time.Duration(0), err
			}
			period *= float64(ageSuffix.Multiplier)
			break
		}
	}

	return time.Duration(period), nil
}

// Set a Duration
func (d *Duration) Set(s string) error {
	duration, err := ParseDuration(s)
	if err != nil {
		return err
	}
	*d = Duration(duration)
	return nil
}

// Type of the value
func (d Duration) Type() string {
	return "duration"
}

// Scan implements the fmt.Scanner interface
func (d *Duration) Scan(s fmt.ScanState, ch rune) error {
	token, err := s.Token(true, nil)
	if err != nil {
		return err
	}
	return d.Set(string(token))
}