Add basic library code to manage projects, activities and times.

This commit is contained in:
Olli 2025-08-29 11:56:45 +02:00
commit fb576f3d51
7 changed files with 663 additions and 0 deletions

81
lib/stats.go Normal file
View file

@ -0,0 +1,81 @@
package lib
import (
"sort"
"time"
)
// TotalTime represents the time spent per project and activity including a total summary.
type TotalTime struct {
Totals []*TotalTimeEntry
TotalSum time.Duration
}
// TotalTimeEntry represents the time spent for a project and an activity.
type TotalTimeEntry struct {
ProjectID string
Project string
ActivityID string
Activity string
Duration time.Duration
}
// GetTimeTotals collects the time spent per project and activity for a time range.
func GetTimeTotals(start, end time.Time) (TotalTime, error) {
totalTime := TotalTime{
Totals: []*TotalTimeEntry{},
}
entries, entriesErr := readTimeRange(start, end)
if entriesErr != nil {
return totalTime, entriesErr
}
if len(entries) == 0 {
return totalTime, nil
}
totalsMap := make(map[string]map[string]time.Duration)
for _, entry := range entries {
project, projectFound := totalsMap[entry.ProjectID]
if !projectFound {
project = make(map[string]time.Duration)
totalsMap[entry.ProjectID] = project
}
activity := project[entry.ActivityID]
project[entry.ActivityID] = activity + entry.End.Sub(entry.Start)
}
if len(totalsMap) == 0 {
return totalTime, nil
}
for projectID, activities := range totalsMap {
for activity, duration := range activities {
totalEntry := TotalTimeEntry{
ProjectID: projectID,
ActivityID: activity,
Duration: duration,
}
totalTime.Totals = append(totalTime.Totals, &totalEntry)
totalTime.TotalSum = totalTime.TotalSum + duration
}
}
return totalTime, nil
}
// GetTimeSummary gathers time entries for a given day. The entries are sorted by start time ascending.
func GetTimeSummary() ([]*Time, error) {
dayStart := time.Now().Truncate(24 * time.Hour)
dayEnd := time.Now().Truncate(24*time.Hour).AddDate(0, 0, 1).Add(-1 * time.Second)
entries, entriesErr := readTimeRange(dayStart, dayEnd)
if entriesErr != nil {
return nil, entriesErr
}
sort.Slice(entries, func(i, j int) bool {
return entries[i].Start.Before(entries[j].Start)
})
return entries, nil
}