Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

accept timezone for timestamps #1432

Merged
merged 1 commit into from Jul 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions docs/v2/manual.md
Expand Up @@ -1413,6 +1413,19 @@ In this example the flag could be used like this:
$ myapp --meeting 2019-08-12T15:04:05
```

When the layout doesn't contain timezones, timestamp will render with UTC. To
change behavior, a default timezone can be provided with flag definition:

```go
app := &cli.App{
Flags: []cli.Flag{
&cli.TimestampFlag{Name: "meeting", Layout: "2006-01-02T15:04:05", Timezone: time.Local},
},
}
```

(time.Local contains the system's local time zone.)

Side note: quotes may be necessary around the date depending on your layout (if
you have spaces for instance)

Expand Down
1 change: 1 addition & 0 deletions flag-spec.yaml
Expand Up @@ -43,6 +43,7 @@ flag_types:
value_pointer: true
struct_fields:
- { name: Layout, type: string }
- { name: Timezone, type: "*time.Location" }

# TODO: enable UintSlice
# UintSlice: {}
Expand Down
12 changes: 12 additions & 0 deletions flag_test.go
Expand Up @@ -2364,6 +2364,18 @@ func TestTimestampFlagApply_Fail_Parse_Wrong_Time(t *testing.T) {
expect(t, err, fmt.Errorf("invalid value \"2006-01-02T15:04:05Z\" for flag -time: parsing time \"2006-01-02T15:04:05Z\" as \"Jan 2, 2006 at 3:04pm (MST)\": cannot parse \"2006-01-02T15:04:05Z\" as \"Jan\""))
}

func TestTimestampFlagApply_Timezoned(t *testing.T) {
pdt := time.FixedZone("PDT", -7*60*60)
expectedResult, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
fl := TimestampFlag{Name: "time", Aliases: []string{"t"}, Layout: time.ANSIC, Timezone: pdt}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)

err := set.Parse([]string{"--time", "Mon Jan 2 08:04:05 2006"})
expect(t, err, nil)
expect(t, *fl.Value.timestamp, expectedResult.In(pdt))
}

func TestTimestampFlagValueFromContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
now := time.Now()
Expand Down
18 changes: 17 additions & 1 deletion flag_timestamp.go
Expand Up @@ -11,6 +11,7 @@ type Timestamp struct {
timestamp *time.Time
hasBeenSet bool
layout string
location *time.Location
}

// Timestamp constructor
Expand All @@ -31,9 +32,22 @@ func (t *Timestamp) SetLayout(layout string) {
t.layout = layout
}

// Set perceived timezone of the to-be parsed time string
func (t *Timestamp) SetLocation(loc *time.Location) {
t.location = loc
}

// Parses the string value to timestamp
func (t *Timestamp) Set(value string) error {
timestamp, err := time.Parse(t.layout, value)
var timestamp time.Time
var err error

if t.location != nil {
timestamp, err = time.ParseInLocation(t.layout, value, t.location)
} else {
timestamp, err = time.Parse(t.layout, value)
}

if err != nil {
return err
}
Expand Down Expand Up @@ -104,9 +118,11 @@ func (f *TimestampFlag) Apply(set *flag.FlagSet) error {
f.Value = &Timestamp{}
}
f.Value.SetLayout(f.Layout)
f.Value.SetLocation(f.Timezone)

if f.Destination != nil {
f.Destination.SetLayout(f.Layout)
f.Destination.SetLocation(f.Timezone)
}

if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
Expand Down
8 changes: 8 additions & 0 deletions godoc-current.txt
Expand Up @@ -269,6 +269,9 @@ type App struct {
Version string
// Description of the program
Description string
// DefaultCommand is the (optional) name of a command
// to run if no command names are passed as CLI arguments.
DefaultCommand string
// List of commands to execute
Commands []*Command
// List of flags to parse
Expand Down Expand Up @@ -1754,6 +1757,9 @@ func (t *Timestamp) Set(value string) error
func (t *Timestamp) SetLayout(layout string)
Set the timestamp string layout for future parsing

func (t *Timestamp) SetLocation(loc *time.Location)
Set perceived timezone of the to-be parsed time string

func (t *Timestamp) SetTimestamp(value time.Time)
Set the timestamp value directly

Expand Down Expand Up @@ -1782,6 +1788,8 @@ type TimestampFlag struct {
EnvVars []string

Layout string

Timezone *time.Location
}
TimestampFlag is a flag with type *Timestamp

Expand Down
2 changes: 2 additions & 0 deletions zz_generated.flags.go
Expand Up @@ -280,6 +280,8 @@ type TimestampFlag struct {
EnvVars []string

Layout string

Timezone *time.Location
}

// String returns a readable representation of this value (for usage defaults)
Expand Down