153 lines
3.4 KiB
Go
153 lines
3.4 KiB
Go
package cli
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
type TimestampFlag = FlagBase[time.Time, TimestampConfig, timestampValue]
|
|
|
|
// TimestampConfig defines the config for timestamp flags
|
|
type TimestampConfig struct {
|
|
Timezone *time.Location
|
|
// Available layouts for flag value.
|
|
//
|
|
// Note that value for formats with missing year/date will be interpreted as current year/date respectively.
|
|
//
|
|
// Read more about time layouts: https://pkg.go.dev/time#pkg-constants
|
|
Layouts []string
|
|
}
|
|
|
|
// timestampValue wrap to satisfy golang's flag interface.
|
|
type timestampValue struct {
|
|
timestamp *time.Time
|
|
hasBeenSet bool
|
|
layouts []string
|
|
location *time.Location
|
|
}
|
|
|
|
var _ ValueCreator[time.Time, TimestampConfig] = timestampValue{}
|
|
|
|
// Below functions are to satisfy the ValueCreator interface
|
|
|
|
func (t timestampValue) Create(val time.Time, p *time.Time, c TimestampConfig) Value {
|
|
*p = val
|
|
return ×tampValue{
|
|
timestamp: p,
|
|
layouts: c.Layouts,
|
|
location: c.Timezone,
|
|
}
|
|
}
|
|
|
|
func (t timestampValue) ToString(b time.Time) string {
|
|
if b.IsZero() {
|
|
return ""
|
|
}
|
|
return fmt.Sprintf("%v", b)
|
|
}
|
|
|
|
// Timestamp constructor(for internal testing only)
|
|
func newTimestamp(timestamp time.Time) *timestampValue {
|
|
return ×tampValue{timestamp: ×tamp}
|
|
}
|
|
|
|
// Below functions are to satisfy the flag.Value interface
|
|
|
|
// Parses the string value to timestamp
|
|
func (t *timestampValue) Set(value string) error {
|
|
var timestamp time.Time
|
|
var err error
|
|
|
|
if t.location == nil {
|
|
t.location = time.UTC
|
|
}
|
|
|
|
if len(t.layouts) == 0 {
|
|
return errors.New("got nil/empty layouts slice")
|
|
}
|
|
|
|
for _, layout := range t.layouts {
|
|
var locErr error
|
|
|
|
timestamp, locErr = time.ParseInLocation(layout, value, t.location)
|
|
if locErr != nil {
|
|
if err == nil {
|
|
err = locErr
|
|
continue
|
|
}
|
|
|
|
err = newMultiError(err, locErr)
|
|
continue
|
|
}
|
|
|
|
err = nil
|
|
break
|
|
}
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defaultTS, _ := time.ParseInLocation(time.TimeOnly, time.TimeOnly, timestamp.Location())
|
|
|
|
n := time.Now()
|
|
|
|
// If format is missing date (or year only), set it explicitly to current
|
|
if timestamp.Truncate(time.Hour*24).UnixNano() == defaultTS.Truncate(time.Hour*24).UnixNano() {
|
|
timestamp = time.Date(
|
|
n.Year(),
|
|
n.Month(),
|
|
n.Day(),
|
|
timestamp.Hour(),
|
|
timestamp.Minute(),
|
|
timestamp.Second(),
|
|
timestamp.Nanosecond(),
|
|
timestamp.Location(),
|
|
)
|
|
} else if timestamp.Year() == 0 {
|
|
timestamp = time.Date(
|
|
n.Year(),
|
|
timestamp.Month(),
|
|
timestamp.Day(),
|
|
timestamp.Hour(),
|
|
timestamp.Minute(),
|
|
timestamp.Second(),
|
|
timestamp.Nanosecond(),
|
|
timestamp.Location(),
|
|
)
|
|
}
|
|
|
|
if t.timestamp != nil {
|
|
*t.timestamp = timestamp
|
|
}
|
|
t.hasBeenSet = true
|
|
return nil
|
|
}
|
|
|
|
// String returns a readable representation of this value (for usage defaults)
|
|
func (t *timestampValue) String() string {
|
|
return fmt.Sprintf("%#v", t.timestamp)
|
|
}
|
|
|
|
// Value returns the timestamp value stored in the flag
|
|
func (t *timestampValue) Value() *time.Time {
|
|
return t.timestamp
|
|
}
|
|
|
|
// Get returns the flag structure
|
|
func (t *timestampValue) Get() any {
|
|
return *t.timestamp
|
|
}
|
|
|
|
// Timestamp gets the timestamp from a flag name
|
|
func (cmd *Command) Timestamp(name string) time.Time {
|
|
if v, ok := cmd.Value(name).(time.Time); ok {
|
|
tracef("time.Time available for flag name %[1]q with value=%[2]v (cmd=%[3]q)", name, v, cmd.Name)
|
|
return v
|
|
}
|
|
|
|
tracef("time.Time NOT available for flag name %[1]q (cmd=%[2]q)", name, cmd.Name)
|
|
return time.Time{}
|
|
}
|