Skip to content

Commit d5d53b8

Browse files
authored
Merge pull request #2 from creativecreature/time
fix: Change time format
2 parents 4c917b9 + 4a42955 commit d5d53b8

24 files changed

+166
-156
lines changed

buffer.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
package pulse
22

3+
import "time"
4+
35
// Buffer represents a buffer that has been opened during an active coding session.
46
type Buffer struct {
5-
OpenedClosed []int64
7+
OpenedClosed []time.Time
68
Filename string
79
Repository string
810
Filepath string
911
Filetype string
1012
}
1113

1214
// NewBuffer creates a new buffer.
13-
func NewBuffer(filename, repo, filetype, filepath string, openedAt int64) Buffer {
15+
func NewBuffer(filename, repo, filetype, filepath string, openedAt time.Time) Buffer {
1416
return Buffer{
15-
OpenedClosed: []int64{openedAt},
17+
OpenedClosed: []time.Time{openedAt},
1618
Filename: filename,
1719
Repository: repo,
1820
Filetype: filetype,
@@ -21,7 +23,7 @@ func NewBuffer(filename, repo, filetype, filepath string, openedAt int64) Buffer
2123
}
2224

2325
// Open should be called when a buffer is opened.
24-
func (b *Buffer) Open(time int64) {
26+
func (b *Buffer) Open(time time.Time) {
2527
b.OpenedClosed = append(b.OpenedClosed, time)
2628
}
2729

@@ -31,20 +33,20 @@ func (b *Buffer) IsOpen() bool {
3133
}
3234

3335
// LastOpened returns the last time the buffer was opened.
34-
func (b *Buffer) LastOpened() int64 {
36+
func (b *Buffer) LastOpened() time.Time {
3537
return b.OpenedClosed[len(b.OpenedClosed)-1]
3638
}
3739

3840
// Close should be called when a buffer is closed.
39-
func (b *Buffer) Close(time int64) {
41+
func (b *Buffer) Close(time time.Time) {
4042
b.OpenedClosed = append(b.OpenedClosed, time)
4143
}
4244

4345
// Duration returns the total duration that the buffer has been open.
44-
func (b *Buffer) Duration() int64 {
45-
var duration int64
46+
func (b *Buffer) Duration() time.Duration {
47+
var duration time.Duration
4648
for i := 0; i < len(b.OpenedClosed); i += 2 {
47-
duration += b.OpenedClosed[i+1] - b.OpenedClosed[i]
49+
duration += b.OpenedClosed[i+1].Sub(b.OpenedClosed[i])
4850
}
4951
return duration
5052
}

buffer_stack.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func (b *bufferStack) files() Files {
3636
sortOrder = append(sortOrder, buffer.Filepath)
3737
pathFile[buffer.Filepath] = fileFromBuffer(buffer)
3838
} else {
39-
file.DurationMs += buffer.Duration()
39+
file.Duration += buffer.Duration()
4040
pathFile[buffer.Filepath] = file
4141
}
4242
}

clock.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ type Clock interface {
1111
Now() time.Time
1212
NewTicker(d time.Duration) (<-chan time.Time, func())
1313
NewTimer(d time.Duration) (<-chan time.Time, func() bool)
14-
GetTime() int64
1514
}
1615

1716
type RealClock struct{}
@@ -34,10 +33,6 @@ func (c *RealClock) NewTimer(d time.Duration) (<-chan time.Time, func() bool) {
3433
return t.C, t.Stop
3534
}
3635

37-
func (c *RealClock) GetTime() int64 {
38-
return time.Now().UTC().UnixMilli()
39-
}
40-
4136
type testTimer struct {
4237
deadline time.Time
4338
ch chan time.Time
@@ -109,12 +104,6 @@ func (c *TestClock) Now() time.Time {
109104
return c.time
110105
}
111106

112-
func (c *TestClock) GetTime() int64 {
113-
c.mu.Lock()
114-
defer c.mu.Unlock()
115-
return c.time.UnixMilli()
116-
}
117-
118107
func (c *TestClock) NewTicker(d time.Duration) (<-chan time.Time, func()) {
119108
c.mu.Lock()
120109
defer c.mu.Unlock()

coding_session.go

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
package pulse
22

3+
import "time"
4+
35
// CodingSession represents an ongoing coding session.
46
type CodingSession struct {
57
// startStops is a slice of timestamps representing the start and stop times of
68
// an ongoing coding session. This ensures accurate time tracking when switching
79
// between multiple editor processes. We only count time for one at a time.
8-
startStops []int64
10+
startStops []time.Time
911
bufStack *bufferStack
1012
EditorID string
11-
StartedAt int64
13+
StartedAt time.Time
1214
OS string
1315
Editor string
1416
}
1517

1618
// StartSession creates a new coding session.
17-
func StartSession(editorID string, startedAt int64, os, editor string) *CodingSession {
19+
func StartSession(editorID string, startedAt time.Time, os, editor string) *CodingSession {
1820
return &CodingSession{
19-
startStops: []int64{startedAt},
21+
startStops: []time.Time{startedAt},
2022
bufStack: newBufferStack(),
2123
EditorID: editorID,
2224
StartedAt: startedAt,
@@ -26,23 +28,23 @@ func StartSession(editorID string, startedAt int64, os, editor string) *CodingSe
2628
}
2729

2830
// Pause should be called when another editor process gains focus.
29-
func (s *CodingSession) Pause(time int64) {
31+
func (s *CodingSession) Pause(time time.Time) {
3032
if currentBuffer := s.bufStack.peek(); currentBuffer != nil {
3133
currentBuffer.Close(time)
3234
}
3335
s.startStops = append(s.startStops, time)
3436
}
3537

3638
// PauseTime is used to determine which coding session to resume.
37-
func (s *CodingSession) PauseTime() int64 {
39+
func (s *CodingSession) PauseTime() time.Time {
3840
if len(s.startStops) == 0 {
39-
return 0
41+
return time.Time{}
4042
}
4143
return s.startStops[len(s.startStops)-1]
4244
}
4345

4446
// Resume should be called when the editor regains focus.
45-
func (s *CodingSession) Resume(time int64) {
47+
func (s *CodingSession) Resume(time time.Time) {
4648
if currentBuffer := s.bufStack.peek(); currentBuffer != nil {
4749
currentBuffer.Open(time)
4850
}
@@ -64,10 +66,10 @@ func (s *CodingSession) HasBuffers() bool {
6466
}
6567

6668
// Duration returns the total duration of the coding session.
67-
func (s *CodingSession) Duration() int64 {
68-
var duration int64
69+
func (s *CodingSession) Duration() time.Duration {
70+
var duration time.Duration
6971
for i := 0; i < len(s.startStops); i += 2 {
70-
duration += s.startStops[i+1] - s.startStops[i]
72+
duration += s.startStops[i+1].Sub(s.startStops[i])
7173
}
7274
return duration
7375
}
@@ -79,7 +81,7 @@ func (s *CodingSession) Active() bool {
7981

8082
// End ends the active coding sessions. It sets the total duration in
8183
// milliseconds, and turns the stack of buffers into a slice of files.
82-
func (s *CodingSession) End(endedAt int64) Session {
84+
func (s *CodingSession) End(endedAt time.Time) Session {
8385
if currentBuffer := s.bufStack.peek(); currentBuffer != nil && currentBuffer.IsOpen() {
8486
currentBuffer.Close(endedAt)
8587
}
@@ -89,11 +91,11 @@ func (s *CodingSession) End(endedAt int64) Session {
8991
}
9092

9193
return Session{
92-
StartedAt: s.StartedAt,
93-
EndedAt: endedAt,
94-
DurationMs: s.Duration(),
95-
OS: s.OS,
96-
Editor: s.Editor,
97-
Files: s.bufStack.files(),
94+
StartedAt: s.StartedAt,
95+
EndedAt: endedAt,
96+
Duration: s.Duration(),
97+
OS: s.OS,
98+
Editor: s.Editor,
99+
Files: s.bufStack.files(),
98100
}
99101
}

coding_session_test.go

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,51 +2,58 @@ package pulse_test
22

33
import (
44
"testing"
5+
"time"
56

67
"github.com/creativecreature/pulse"
78
)
89

910
func TestActiveSession(t *testing.T) {
11+
t.Parallel()
12+
13+
mockClock := pulse.NewTestClock(time.Now())
14+
1015
// Start a new coding session
11-
activeSession := pulse.StartSession("1337", 100, "linux", "nvim")
16+
activeSession := pulse.StartSession("1337", mockClock.Now(), "linux", "nvim")
1217

13-
// Open the first buffer
18+
// Open the first buffer, and wait 400ms.
1419
bufferOne := pulse.NewBuffer(
1520
"init.lua",
1621
"dotfiles",
1722
"lua",
1823
"dotfiles/editors/nvim/init.lua",
19-
101,
24+
mockClock.Now(),
2025
)
2126
activeSession.PushBuffer(bufferOne)
27+
mockClock.Add(400 * time.Millisecond)
2228

23-
// Open a second buffer.
29+
// Open a second buffer, and wait 200ms.
2430
bufferTwo := pulse.NewBuffer(
2531
"plugins.lua",
2632
"dotfiles",
2733
"lua",
2834
"dotfiles/editors/nvim/plugins.lua",
29-
301,
35+
mockClock.Now(),
3036
)
3137
activeSession.PushBuffer(bufferTwo)
38+
mockClock.Add(200 * time.Millisecond)
3239

33-
// Open the same file as buffer one. The total duration for these
40+
// Open the first buffer again. The total duration for these
3441
// buffers should be merged when we end the coding session.
3542
bufferThree := pulse.NewBuffer(
3643
"init.lua",
3744
"dotfiles",
3845
"lua",
3946
"dotfiles/editors/nvim/init.lua",
40-
611,
47+
mockClock.Now(),
4148
)
4249
activeSession.PushBuffer(bufferThree)
50+
mockClock.Add(time.Millisecond * 100)
4351

44-
endedAt := int64(700)
45-
finishedSession := activeSession.End(endedAt)
52+
finishedSession := activeSession.End(mockClock.Now())
4653

4754
// Assert that the duration of the session was set correctly.
48-
if finishedSession.DurationMs != 600 {
49-
t.Errorf("Expected the session duration to be 600, got %d", finishedSession.DurationMs)
55+
if finishedSession.Duration.Milliseconds() != 700 {
56+
t.Errorf("Expected the session duration to be 600, got %d", finishedSession.Duration.Milliseconds())
5057
}
5158

5259
// Assert that the buffers have been merged into files.
@@ -55,11 +62,13 @@ func TestActiveSession(t *testing.T) {
5562
}
5663

5764
// Assert that the merged buffers has both durations.
58-
if finishedSession.Files[0].DurationMs != 289 {
59-
t.Errorf("Expected the merged duration for init.lua to be 289, got %d", finishedSession.Files[0].DurationMs)
65+
initLuaDuration := finishedSession.Files[0].Duration.Milliseconds()
66+
if initLuaDuration != 500 {
67+
t.Errorf("Expected the merged duration for init.lua to be 500, got %d", initLuaDuration)
6068
}
6169

62-
if finishedSession.Files[1].DurationMs != 310 {
63-
t.Errorf("Expected the duration for plugins.lua to be 310, got %d", finishedSession.Files[1].DurationMs)
70+
pluginsLuaDuration := finishedSession.Files[1].Duration.Milliseconds()
71+
if pluginsLuaDuration != 200 {
72+
t.Errorf("Expected the duration for plugins.lua to be 200, got %d", pluginsLuaDuration)
6473
}
6574
}

disk/disk.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ func (s *Storage) dayDir() (string, error) {
5555

5656
// filename returns the name we'll use when writing the session to disk.
5757
func (s *Storage) filename(session pulse.Session) string {
58-
startTime := time.UnixMilli(session.StartedAt).Format("15:04:05.000")
59-
endTime := time.UnixMilli(session.EndedAt).Format("15:04:05.000")
58+
startTime := session.StartedAt.Format("15:04:05.000")
59+
endTime := session.EndedAt.Format("15:04:05.000")
6060
return fmt.Sprintf("%s-%s.json", startTime, endTime)
6161
}
6262

disk/disk_test.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,34 +47,34 @@ func TestStorageReadWriteClean(t *testing.T) {
4747
now := time.Now()
4848
sessions := pulse.Sessions{
4949
pulse.Session{
50-
StartedAt: now.UnixMilli(),
51-
EndedAt: now.Add(time.Hour).UnixMilli(),
52-
DurationMs: time.Hour.Milliseconds(),
53-
OS: "linux",
54-
Editor: "nvim",
50+
StartedAt: now,
51+
EndedAt: now.Add(time.Hour),
52+
Duration: time.Hour,
53+
OS: "linux",
54+
Editor: "nvim",
5555
Files: pulse.Files{
5656
pulse.File{
5757
Name: "main.go",
5858
Path: "/cmd/main.go",
5959
Repository: "pulse",
6060
Filetype: "go",
61-
DurationMs: time.Hour.Milliseconds(),
61+
Duration: time.Hour,
6262
},
6363
},
6464
},
6565
pulse.Session{
66-
StartedAt: now.Add(time.Minute).UnixMilli(),
67-
EndedAt: now.Add(time.Minute * 11).UnixMilli(),
68-
DurationMs: time.Hour.Milliseconds(),
69-
OS: "linux",
70-
Editor: "nvim",
66+
StartedAt: now.Add(time.Minute),
67+
EndedAt: now.Add(time.Minute * 11),
68+
Duration: time.Hour,
69+
OS: "linux",
70+
Editor: "nvim",
7171
Files: pulse.Files{
7272
pulse.File{
7373
Name: "main.go",
7474
Path: "/cmd/main.go",
7575
Repository: "pulse",
7676
Filetype: "go",
77-
DurationMs: time.Minute.Milliseconds() * 10,
77+
Duration: time.Minute * 10,
7878
},
7979
},
8080
},

file.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package pulse
22

3+
import "time"
4+
35
// File represents a file that has been opened during a coding session.
46
type File struct {
5-
Name string `json:"name"`
6-
Path string `json:"path"`
7-
Repository string `json:"repository"`
8-
Filetype string `json:"filetype"`
9-
DurationMs int64 `json:"duration_ms"`
7+
Name string `json:"name"`
8+
Path string `json:"path"`
9+
Repository string `json:"repository"`
10+
Filetype string `json:"filetype"`
11+
Duration time.Duration `json:"duration"`
1012
}
1113

1214
// fileFromBuffer turns a code buffer into a file.
@@ -16,7 +18,7 @@ func fileFromBuffer(b Buffer) File {
1618
Path: b.Filepath,
1719
Repository: b.Repository,
1820
Filetype: b.Filetype,
19-
DurationMs: b.Duration(),
21+
Duration: b.Duration(),
2022
}
2123
}
2224

repository.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func repositoryPathFile(sessions []Session) map[string]map[string]AggregatedFile
3232
Name: file.Name,
3333
Path: file.Path,
3434
Filetype: file.Filetype,
35-
DurationMs: file.DurationMs,
35+
DurationMs: file.Duration.Milliseconds(),
3636
}
3737

3838
// Check if it is the first time we're seeing a repository

0 commit comments

Comments
 (0)