All checks were successful
CI / build (push) Successful in 38s
- ComputeDailyTotals: only assume working from dayStart when first event is 'out' (cross-midnight session); otherwise start idle. Fixes inflated work/break counts in reports, status, export, burnout, salary, and RPG. - leagueToggleCallback: add settings back keyboard when RPG is disabled. - webhook: add graceful HTTP server shutdown on context cancellation.
69 lines
1.8 KiB
Go
69 lines
1.8 KiB
Go
package domain
|
|
|
|
import "sort"
|
|
|
|
// ComputeDailyTotals calculates the total work and break time from a list of events.
|
|
func ComputeDailyTotals(events []Event, minBreakThreshold int64, dayStart, dayEnd int64) DailyTotals {
|
|
if len(events) == 0 {
|
|
return DailyTotals{}
|
|
}
|
|
|
|
sorted := make([]Event, len(events))
|
|
copy(sorted, events)
|
|
sort.Slice(sorted, func(i, j int) bool {
|
|
return sorted[i].OccurredAt < sorted[j].OccurredAt
|
|
})
|
|
|
|
var totalWork, totalBreak int64
|
|
state := StateIdle
|
|
var workStart, breakStart int64
|
|
|
|
if dayStart > 0 && sorted[0].EventType == "out" {
|
|
state = StateWorking
|
|
workStart = dayStart
|
|
} else if sorted[0].EventType == "out" {
|
|
state = StateOnBreak
|
|
}
|
|
|
|
for _, e := range sorted {
|
|
switch {
|
|
case e.EventType == "in" && state == StateIdle:
|
|
state = StateWorking
|
|
workStart = e.OccurredAt
|
|
case e.EventType == "in" && state == StateOnBreak:
|
|
breakElapsed := e.OccurredAt - breakStart
|
|
if breakElapsed >= minBreakThreshold {
|
|
totalBreak += breakElapsed
|
|
} else {
|
|
totalWork += breakElapsed
|
|
}
|
|
state = StateWorking
|
|
workStart = e.OccurredAt
|
|
case e.EventType == "in" && state == StateWorking:
|
|
case e.EventType == "out" && state == StateWorking:
|
|
totalWork += e.OccurredAt - workStart
|
|
state = StateOnBreak
|
|
breakStart = e.OccurredAt
|
|
case e.EventType == "out" && state == StateOnBreak:
|
|
breakStart = e.OccurredAt
|
|
case e.EventType == "out" && state == StateIdle:
|
|
state = StateOnBreak
|
|
breakStart = e.OccurredAt
|
|
}
|
|
}
|
|
|
|
if state == StateWorking && dayEnd > 0 {
|
|
totalWork += dayEnd - workStart
|
|
}
|
|
if state == StateOnBreak && dayEnd > 0 {
|
|
breakElapsed := dayEnd - breakStart
|
|
if breakElapsed >= minBreakThreshold {
|
|
totalBreak += breakElapsed
|
|
} else {
|
|
totalWork += breakElapsed
|
|
}
|
|
}
|
|
|
|
return DailyTotals{TotalSeconds: totalWork, BreakSeconds: totalBreak}
|
|
}
|