tme

Toggl like Time Manager
git clone git://gtms.dev:tme
Log | Files | Refs

commit 6304741cb9c7d9fd0749ec6bb2a439a5ac923198
parent 43b7ada48fb26971cb5e0cb256d82157fb47a736
Author: Tomas Nemec <nemi@skaut.cz>
Date:   Sat, 11 Feb 2023 00:44:10 +0100

feat: better parsing of time

Diffstat:
Mcommand.go | 9+++++----
Mtme/time.go | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Atme/time_test.go | 44++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 151 insertions(+), 19 deletions(-)

diff --git a/command.go b/command.go @@ -221,7 +221,7 @@ func (c Command) report() { } for _, entry := range entries { - if entry.Start.After(sinceTime) { + if entry.Start.After(sinceTime) || entry.Start.Equal(sinceTime) { duration += entry.Duration() formatEntry(group, entry) } @@ -248,15 +248,16 @@ func formatEntries(group tme.Group, entryTime *tme.Time) { func formatEntry(group tme.Group, entry tme.Entry) { groupPath := group.Path duration := entry.Duration().Round(time.Second) + timeLayout := "15:04 02/01/2006" switch e := entry.(type) { case tme.CompletedEntry: var start string - start = e.Start.Format(tme.DateTimeLayout) - stop := e.Stop.Format(tme.DateTimeLayout) + start = e.Start.Format(timeLayout) + stop := e.Stop.Format(timeLayout) fmt.Printf("%s\t%s\t%v\t%s\n", groupPath, start, stop, duration) case tme.RunningEntry: - start := e.Start.Format(tme.DateTimeLayout) + start := e.Start.Format(timeLayout) fmt.Printf("%s\t%s\t%s\t%s\n", groupPath, start, "running", duration) } } diff --git a/tme/time.go b/tme/time.go @@ -1,10 +1,12 @@ package tme -import "time" +import ( + "fmt" + "strings" + "time" +) const ( - TimeLayout = "15:04" - DateTimeLayout = "15:04 02/01/2006" FileNameLayout = "0601021504" DataTimeLayout = time.RFC3339 ) @@ -21,18 +23,103 @@ func NewTimeToday() *Time { return &Time{time.Now()} } +// TODO(tms) 11.02.23: Simplify func (et *Time) ParseArg(raw string) (time.Time, error) { - t, err := time.Parse(TimeLayout, raw) - return time.Date( - et.context.Year(), - et.context.Month(), - et.context.Day(), - t.Hour(), - t.Minute(), - 0, - 0, - et.context.Location(), - ), err + parts := strings.Split(raw, " ") + hour := et.context.Hour() + min := et.context.Minute() + sec := et.context.Second() + year, mon, day := et.context.Date() + + var parsed bool + part := parts[0] + + t, err := time.Parse("15", part) + if err == nil { + parsed = true + hour = t.Hour() + min = 0 + sec = 0 + } + + t, err = time.Parse("15:4", part) + if err == nil { + parsed = true + hour = t.Hour() + min = t.Minute() + sec = 0 + } + + t, err = time.Parse("15:4:5", part) + if err == nil { + parsed = true + hour = t.Hour() + min = t.Minute() + sec = t.Second() + } + + t, err = time.Parse("2/1", part) + if err == nil { + parsed = true + hour = 0 + min = 0 + sec = 0 + day = t.Day() + mon = t.Month() + year = et.context.Year() + } + + t, err = time.Parse("1/2006", part) + if err == nil { + parsed = true + hour = 0 + min = 0 + sec = 0 + day = 1 + mon = t.Month() + year = t.Year() + } + + t, err = time.Parse("2/1/2006", part) + if err == nil { + parsed = true + hour = 0 + min = 0 + sec = 0 + day = t.Day() + mon = t.Month() + year = t.Year() + } + + if !parsed && len(raw) > 0 { + return time.Now(), fmt.Errorf("Cannot parse %q", raw) + } + + if len(parts) > 1 { + part = parts[1] + t, err := time.Parse("2", part) + if err == nil { + day = t.Day() + mon = et.context.Month() + year = et.context.Year() + } + + t, err = time.Parse("2/1", part) + if err == nil { + day = t.Day() + mon = t.Month() + year = et.context.Year() + } + + t, err = time.Parse("2/1/2006", part) + if err == nil { + day = t.Day() + mon = t.Month() + year = t.Year() + } + } + + return time.Date(year, mon, day, hour, min, sec, 0, et.context.Location()), nil } func (et *Time) ParseEntry(raw string) (time.Time, error) { @@ -43,7 +130,7 @@ func (et *Time) ParseEntry(raw string) (time.Time, error) { t.Day(), t.Hour(), t.Minute(), - 0, + t.Second(), 0, et.context.Location(), ), err diff --git a/tme/time_test.go b/tme/time_test.go @@ -0,0 +1,44 @@ +package tme + +import ( + "testing" + "time" +) + +func TestParseArg(t *testing.T) { + layout := "15:4:5 2/1/2006" + context, _ := time.Parse(layout, "1:1:1 1/1/2001") + var check = func(raw string, expected string) { + t.Helper() + t.Run("", func(b *testing.T) { + b.Helper() + tmeTime := NewTime(context) + expected, _ := time.Parse(layout, expected) + parsed, err := tmeTime.ParseArg(raw) + if err != nil { + b.Fatal(err) + } + + if !parsed.Equal(expected) { + b.Errorf("Parsed %v; Expected %v", parsed, expected) + } + }) + } + + check("5", "5:0:0 1/1/2001") + check("5:5", "5:5:0 1/1/2001") + check("5:5:5", "5:5:5 1/1/2001") + check("5:5 5", "5:5:0 5/1/2001") + check("5:5 5/5", "5:5:0 5/5/2001") + check("5:5 5/5/2005", "5:5:0 5/5/2005") + + check("5/5", "0:0:0 5/5/2001") + check("5/5/2005", "0:0:0 5/5/2005") + check("5/2005", "0:0:0 1/5/2005") + + check("5:05", "5:5:0 1/1/2001") + check("05:05", "5:5:0 1/1/2001") + check("05:5 05/5/2005", "5:5:0 5/5/2005") + check("5:5 5/05/2005", "5:5:0 5/5/2005") + check("5:05 5/05/2005", "5:5:0 5/5/2005") +}