Skip to content

Commit f5a4cce

Browse files
committed
add fractional support
Signed-off-by: iTrooz <hey@itrooz.fr>
1 parent c3d1119 commit f5a4cce

File tree

2 files changed

+46
-9
lines changed

2 files changed

+46
-9
lines changed

pkg/cmd/util/flag/duration.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,28 +31,33 @@ var unitMap = map[string]uint64{
3131
"yr": uint64(365 * 24 * time.Hour),
3232
}
3333

34-
// ParseDuration parses strings like "2d5h10m"
34+
// ParseDuration parses strings like "2d5h10.5m"
35+
// it does not support negative durations.
3536
func ParseDuration(s string) (Duration, error) {
3637
s = strings.TrimSpace(s)
3738
if s == "" {
3839
return Duration{Duration: 0}, nil
3940
}
4041

41-
var total uint64
42+
var total float64
4243
i := 0
4344
n := len(s)
4445

4546
for i < n {
46-
// Get number
47+
// Get number (including decimal point)
4748
j := i
48-
for j < n && unicode.IsDigit(rune(s[j])) {
49+
hasDot := false
50+
for j < n && (unicode.IsDigit(rune(s[j])) || (s[j] == '.' && !hasDot)) {
51+
if s[j] == '.' {
52+
hasDot = true
53+
}
4954
j++
5055
}
5156
if j == i {
5257
return Duration{}, fmt.Errorf("expected number at pos %d", i)
5358
}
5459
numStr := s[i:j]
55-
num, err := strconv.ParseUint(numStr, 10, 64)
60+
num, err := strconv.ParseFloat(numStr, 64)
5661
if err != nil {
5762
return Duration{}, err
5863
}
@@ -73,15 +78,15 @@ func ParseDuration(s string) (Duration, error) {
7378
return Duration{}, fmt.Errorf("unknown unit %q", unit)
7479
}
7580
// Add to total
76-
total += num * val
81+
total += num * float64(val)
7782

7883
i = k
7984
for i < n && s[i] == ' ' {
8085
i++
8186
}
8287
}
8388

84-
// Convert integer seconds into time.Duration
89+
// Convert to time.Duration (nanoseconds)
8590
return Duration{Duration: time.Duration(total)}, nil
8691
}
8792

pkg/cmd/util/flag/duration_test.go

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,38 @@ func TestParseDuration(t *testing.T) {
104104
wantErr: false,
105105
},
106106

107+
// Fractional values
108+
{
109+
name: "basic fraction",
110+
input: "5.5s",
111+
expected: time.Duration(5.5 * float64(time.Second)),
112+
wantErr: false,
113+
},
114+
{
115+
name: "fraction with no decimal part",
116+
input: "5.s",
117+
expected: time.Duration(5 * float64(time.Second)),
118+
wantErr: false,
119+
},
120+
{
121+
name: "fractional with multiple decimals",
122+
input: "1.25h30.5m",
123+
expected: time.Duration(1.25*float64(time.Hour) + 30.5*float64(time.Minute)),
124+
wantErr: false,
125+
},
126+
{
127+
name: "fractional zero",
128+
input: "0.0s",
129+
expected: 0,
130+
wantErr: false,
131+
},
132+
{
133+
name: "mixed integer and fractional",
134+
input: "2h1.5m30s",
135+
expected: 2*time.Hour + time.Duration(1.5*float64(time.Minute)) + 30*time.Second,
136+
wantErr: false,
137+
},
138+
107139
// Error cases
108140
{
109141
name: "invalid character at start",
@@ -142,8 +174,8 @@ func TestParseDuration(t *testing.T) {
142174
wantErr: true,
143175
},
144176
{
145-
name: "decimal number",
146-
input: "5.5s",
177+
name: "multiple decimal points",
178+
input: "5.5.5s",
147179
expected: 0,
148180
wantErr: true,
149181
},

0 commit comments

Comments
 (0)