Skip to content

Commit

Permalink
Merge pull request #1432 from julian7/timezoned-timestamp
Browse files Browse the repository at this point in the history
accept timezone for timestamps
  • Loading branch information
meatballhat committed Jul 10, 2022
2 parents d29120f + 1335a70 commit 2e71cb8
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 1 deletion.
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

0 comments on commit 2e71cb8

Please sign in to comment.