-
Notifications
You must be signed in to change notification settings - Fork 4
/
session.go
131 lines (112 loc) · 3.5 KB
/
session.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package pulse
import (
"cmp"
"sort"
"time"
)
// CodingSession represents a coding session that has been aggregated
// for a given time period (day, week, month, year).
type CodingSession struct {
Date time.Time `json:"date"`
Duration time.Duration `json:"duration"`
Repositories Repositories `json:"repositories"`
}
// TruncateDay truncates the time to the start of the day.
func TruncateDay(t time.Time) time.Time {
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
}
func NewCodingSession(buffers Buffers, now time.Time) CodingSession {
repos := make(map[string]Repository)
for _, buf := range buffers {
repo, ok := repos[buf.Repository]
if !ok {
repo = Repository{Name: buf.Repository, Files: make(Files, 0)}
}
file := File{
Name: buf.Filename,
Path: buf.Filepath,
Filetype: buf.Filetype,
Duration: buf.Duration,
}
repo.Duration += file.Duration
repo.Files = append(repo.Files, file)
repos[buf.Repository] = repo
}
var totalDuration time.Duration
repositories := make(Repositories, 0, len(repos))
for _, repo := range repos {
totalDuration += repo.Duration
repositories = append(repositories, repo)
}
session := CodingSession{
Date: TruncateDay(now),
Duration: totalDuration,
Repositories: repositories,
}
return session
}
// Merge takes two coding sessions, merges them, and returns the result.
func (c CodingSession) Merge(other CodingSession) CodingSession {
mergedSession := CodingSession{
Date: cmp.Or(c.Date, other.Date),
Duration: c.Duration + other.Duration,
Repositories: c.Repositories.merge(other.Repositories),
}
return mergedSession
}
func (c CodingSession) DateString() string {
return c.Date.Format("2006-01-02")
}
// CodingSessions represents a slice of coding sessions.
type CodingSessions []CodingSession
func (s CodingSessions) Len() int {
return len(s)
}
func (s CodingSessions) Less(i, j int) bool {
return s[i].Date.Before(s[j].Date)
}
func (s CodingSessions) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func merge(sessions CodingSessions, truncate func(time.Time) time.Time) CodingSessions {
truncatedDateAggregatedSession := make(map[time.Time]CodingSession)
for _, s := range sessions {
s.Date = truncate(s.Date)
currentSession := truncatedDateAggregatedSession[s.Date]
truncatedDateAggregatedSession[s.Date] = s.Merge(currentSession)
}
values := CodingSessions{}
for _, v := range truncatedDateAggregatedSession {
values = append(values, v)
}
sort.Sort(values)
return values
}
// MergeByDay merges sessions that occurred the same day.
func (s CodingSessions) MergeByDay() CodingSessions {
return merge(s, TruncateDay)
}
// MergeByWeek merges sessions that occurred the same week.
func (s CodingSessions) MergeByWeek() CodingSessions {
truncate := func(t time.Time) time.Time {
for t.Weekday() != time.Monday {
t = t.AddDate(0, 0, -1)
}
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
}
return merge(s, truncate)
}
// MergeByMonth merges sessions that occurred the same month.
func (s CodingSessions) MergeByMonth() CodingSessions {
truncate := func(t time.Time) time.Time {
return time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
}
return merge(s, truncate)
}
// MergeByYear merges sessions that occurred the same year.
func (s CodingSessions) MergeByYear() CodingSessions {
truncate := func(t time.Time) time.Time {
return time.Date(t.Year(), time.January, 1, 0, 0, 0, 0, t.Location())
}
return merge(s, truncate)
}