diff --git a/cmd/touch/touch.go b/cmd/touch/touch.go index b868784a6..9eb9cf8f8 100644 --- a/cmd/touch/touch.go +++ b/cmd/touch/touch.go @@ -26,10 +26,19 @@ var ( const ( defaultLayout string = "060102" + layoutDate string = "2006-01-02" layoutDateWithTime string = "2006-01-02T15:04:05" layoutDateWithTimeNano string = "2006-01-02T15:04:05.999999999" ) +var timeLayouts = []string{ + time.RFC3339Nano, + layoutDateWithTimeNano, + layoutDateWithTime, + layoutDate, + defaultLayout, +} + func init() { cmd.Root.AddCommand(commandDefinition) cmdFlags := commandDefinition.Flags() @@ -56,9 +65,11 @@ This will touch ` + "`--transfers`" + ` files concurrently. If ` + "`--timestamp`" + ` is used then sets the modification time to that time instead of the current time. Times may be specified as one of: -- 'YYMMDD' - e.g. 17.10.30 +- 'YYMMDD' - e.g. 171030 +- 'YYYY-MM-DD' - e.g. 2006-01-02 - 'YYYY-MM-DDTHH:MM:SS' - e.g. 2006-01-02T15:04:05 - 'YYYY-MM-DDTHH:MM:SS.SSS' - e.g. 2006-01-02T15:04:05.123456789 +- 'YYYY-MM-DDTHH:MM:SSZ' - e.g. 2006-01-02T15:04:05Z Note that value of ` + "`--timestamp`" + ` is in UTC. If you want local time then add the ` + "`--localtime`" + ` flag. @@ -100,16 +111,19 @@ func newFsDst(args []string) (f fs.Fs, remote string) { // parseTimeArgument parses a timestamp string according to specific layouts func parseTimeArgument(timeString string) (time.Time, error) { - layout := defaultLayout - if len(timeString) == len(layoutDateWithTime) { - layout = layoutDateWithTime - } else if len(timeString) > len(layoutDateWithTime) { - layout = layoutDateWithTimeNano + var err error + for _, layout := range timeLayouts { + var t time.Time + if localTime { + t, err = time.ParseInLocation(layout, timeString, time.Local) + } else { + t, err = time.Parse(layout, timeString) + } + if err == nil { + return t, nil + } } - if localTime { - return time.ParseInLocation(layout, timeString, time.Local) - } - return time.Parse(layout, timeString) + return time.Time{}, err } // timeOfTouch returns the time value set on files diff --git a/cmd/touch/touch_test.go b/cmd/touch/touch_test.go index 40ff84e1b..513d8b0a1 100644 --- a/cmd/touch/touch_test.go +++ b/cmd/touch/touch_test.go @@ -3,6 +3,7 @@ package touch import ( "context" "testing" + "time" _ "github.com/rclone/rclone/backend/local" "github.com/rclone/rclone/fs" @@ -21,6 +22,32 @@ func checkFile(t *testing.T, r fs.Fs, path string, content string) { fstest.CheckItems(t, r, file1) } +func TestParseTimeArgument(t *testing.T) { + oldLocalTime := localTime + localTime = false + t.Cleanup(func() { + localTime = oldLocalTime + }) + + for _, test := range []struct { + in string + want time.Time + }{ + {"171030", fstest.Time("2017-10-30T00:00:00Z")}, + {"2024-05-01", fstest.Time("2024-05-01T00:00:00Z")}, + {"2024-05-01T12:00:00", fstest.Time("2024-05-01T12:00:00Z")}, + {"2024-05-01T12:00:00.123456789", fstest.Time("2024-05-01T12:00:00.123456789Z")}, + {"2024-05-01T12:00:00Z", fstest.Time("2024-05-01T12:00:00Z")}, + {"2024-05-01T12:00:00.123456789Z", fstest.Time("2024-05-01T12:00:00.123456789Z")}, + } { + t.Run(test.in, func(t *testing.T) { + got, err := parseTimeArgument(test.in) + require.NoError(t, err) + require.Equal(t, test.want, got) + }) + } +} + // TestMain drives the tests func TestMain(m *testing.M) { fstest.TestMain(m) diff --git a/docs/content/commands/rclone_touch.md b/docs/content/commands/rclone_touch.md index 663a89dc5..202694ee3 100644 --- a/docs/content/commands/rclone_touch.md +++ b/docs/content/commands/rclone_touch.md @@ -24,9 +24,11 @@ This will touch `--transfers` files concurrently. If `--timestamp` is used then sets the modification time to that time instead of the current time. Times may be specified as one of: -- 'YYMMDD' - e.g. 17.10.30 +- 'YYMMDD' - e.g. 171030 +- 'YYYY-MM-DD' - e.g. 2006-01-02 - 'YYYY-MM-DDTHH:MM:SS' - e.g. 2006-01-02T15:04:05 - 'YYYY-MM-DDTHH:MM:SS.SSS' - e.g. 2006-01-02T15:04:05.123456789 +- 'YYYY-MM-DDTHH:MM:SSZ' - e.g. 2006-01-02T15:04:05Z Note that value of `--timestamp` is in UTC. If you want local time then add the `--localtime` flag.