2020-10-20 11:29:26 +00:00
package flagutil
import (
"flag"
"fmt"
"strconv"
"strings"
2023-09-01 07:27:51 +00:00
"time"
2020-10-20 11:29:26 +00:00
"github.com/VictoriaMetrics/metricsql"
)
// NewDuration returns new `duration` flag with the given name, defaultValue and description.
//
// DefaultValue is in months.
2022-05-02 07:12:05 +00:00
func NewDuration ( name string , defaultValue string , description string ) * Duration {
2020-10-20 11:29:26 +00:00
description += "\nThe following optional suffixes are supported: h (hour), d (day), w (week), y (year). If suffix isn't set, then the duration is counted in months"
2022-05-02 07:12:05 +00:00
d := & Duration { }
if err := d . Set ( defaultValue ) ; err != nil {
panic ( fmt . Sprintf ( "BUG: can not parse default value %s for flag %s" , defaultValue , name ) )
2020-10-20 11:29:26 +00:00
}
2022-05-02 07:12:05 +00:00
flag . Var ( d , name , description )
return d
2020-10-20 11:29:26 +00:00
}
// Duration is a flag for holding duration.
type Duration struct {
2023-09-03 08:33:37 +00:00
// msecs contains parsed duration in milliseconds.
msecs int64
2020-10-20 11:29:26 +00:00
valueString string
}
2023-09-01 07:27:51 +00:00
// Duration convert to time.Duration.
func ( d * Duration ) Duration ( ) time . Duration {
2023-09-03 08:33:37 +00:00
return time . Millisecond * time . Duration ( d . msecs )
2023-09-01 07:27:51 +00:00
}
2020-10-20 11:29:26 +00:00
// String implements flag.Value interface
func ( d * Duration ) String ( ) string {
return d . valueString
}
// Set implements flag.Value interface
func ( d * Duration ) Set ( value string ) error {
// An attempt to parse value in months.
months , err := strconv . ParseFloat ( value , 64 )
if err == nil {
if months > maxMonths {
return fmt . Errorf ( "duration months must be smaller than %d; got %g" , maxMonths , months )
}
if months < 0 {
return fmt . Errorf ( "duration months cannot be negative; got %g" , months )
}
2023-09-03 08:33:37 +00:00
d . msecs = int64 ( months * msecsPer31Days )
2020-10-20 11:29:26 +00:00
d . valueString = value
return nil
}
// Parse duration.
value = strings . ToLower ( value )
if strings . HasSuffix ( value , "m" ) {
return fmt . Errorf ( "duration in months must be set without `m` suffix due to ambiguity with duration in minutes; got %s" , value )
}
msecs , err := metricsql . PositiveDurationValue ( value , 0 )
if err != nil {
return err
}
2023-09-03 08:33:37 +00:00
d . msecs = msecs
2020-10-20 11:29:26 +00:00
d . valueString = value
return nil
}
const maxMonths = 12 * 100
2023-09-03 08:33:37 +00:00
const msecsPer31Days = 31 * 24 * 3600 * 1000