touch: parse documented timestamp formats

This commit is contained in:
Nicholas Velten
2026-09-09 10:24:48 +01:00
committed by Nick Craig-Wood
parent ea589de941
commit e45210765c
3 changed files with 54 additions and 11 deletions
+24 -10
View File
@@ -26,10 +26,19 @@ var (
const ( const (
defaultLayout string = "060102" defaultLayout string = "060102"
layoutDate string = "2006-01-02"
layoutDateWithTime string = "2006-01-02T15:04:05" layoutDateWithTime string = "2006-01-02T15:04:05"
layoutDateWithTimeNano string = "2006-01-02T15:04:05.999999999" layoutDateWithTimeNano string = "2006-01-02T15:04:05.999999999"
) )
var timeLayouts = []string{
time.RFC3339Nano,
layoutDateWithTimeNano,
layoutDateWithTime,
layoutDate,
defaultLayout,
}
func init() { func init() {
cmd.Root.AddCommand(commandDefinition) cmd.Root.AddCommand(commandDefinition)
cmdFlags := commandDefinition.Flags() cmdFlags := commandDefinition.Flags()
@@ -56,9 +65,11 @@ This will touch ` + "`--transfers`" + ` files concurrently.
If ` + "`--timestamp`" + ` is used then sets the modification time to that If ` + "`--timestamp`" + ` is used then sets the modification time to that
time instead of the current time. Times may be specified as one of: 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' - 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: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 Note that value of ` + "`--timestamp`" + ` is in UTC. If you want local time
then add the ` + "`--localtime`" + ` flag. 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 // parseTimeArgument parses a timestamp string according to specific layouts
func parseTimeArgument(timeString string) (time.Time, error) { func parseTimeArgument(timeString string) (time.Time, error) {
layout := defaultLayout var err error
if len(timeString) == len(layoutDateWithTime) { for _, layout := range timeLayouts {
layout = layoutDateWithTime var t time.Time
} else if len(timeString) > len(layoutDateWithTime) { if localTime {
layout = layoutDateWithTimeNano 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.Time{}, err
return time.ParseInLocation(layout, timeString, time.Local)
}
return time.Parse(layout, timeString)
} }
// timeOfTouch returns the time value set on files // timeOfTouch returns the time value set on files
+27
View File
@@ -3,6 +3,7 @@ package touch
import ( import (
"context" "context"
"testing" "testing"
"time"
_ "github.com/rclone/rclone/backend/local" _ "github.com/rclone/rclone/backend/local"
"github.com/rclone/rclone/fs" "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) 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 // TestMain drives the tests
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
fstest.TestMain(m) fstest.TestMain(m)
+3 -1
View File
@@ -24,9 +24,11 @@ This will touch `--transfers` files concurrently.
If `--timestamp` is used then sets the modification time to that If `--timestamp` is used then sets the modification time to that
time instead of the current time. Times may be specified as one of: 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' - 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: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 Note that value of `--timestamp` is in UTC. If you want local time
then add the `--localtime` flag. then add the `--localtime` flag.