From 54a944ec418e7aba230556aded1d6106a515b32c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferdinand=20M=C3=BCtsch?= Date: Fri, 16 Oct 2020 12:00:20 +0200 Subject: [PATCH] fix: critical summary computation bug (faulty intervals) fix: doubly included heartbeats fix: cross-day heartbeats are ignored for consistency --- services/heartbeat.go | 2 +- services/summary.go | 17 +++++++++++++---- version.txt | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/services/heartbeat.go b/services/heartbeat.go index 62c156f..024cc47 100644 --- a/services/heartbeat.go +++ b/services/heartbeat.go @@ -46,7 +46,7 @@ func (srv *HeartbeatService) GetAllWithin(from, to time.Time, user *models.User) if err := srv.Db. Where(&models.Heartbeat{UserID: user.ID}). Where("time >= ?", from). - Where("time <= ?", to). + Where("time < ?", to). Order("time asc"). Find(&heartbeats).Error; err != nil { return nil, err diff --git a/services/summary.go b/services/summary.go index 42dde30..a323051 100644 --- a/services/summary.go +++ b/services/summary.go @@ -14,6 +14,8 @@ import ( "github.com/muety/wakapi/models" ) +const HeartbeatDiffThreshold = 2 * time.Minute + type SummaryService struct { Config *config.Config Cache *cache.Cache @@ -218,9 +220,16 @@ func (srv *SummaryService) aggregateBy(heartbeats []*models.Heartbeat, summaryTy continue } - timePassed := h.Time.Time().Sub(heartbeats[i-1].Time.Time()) - timeThresholded := math.Min(float64(timePassed), float64(time.Duration(2)*time.Minute)) - durations[key] += time.Duration(int64(timeThresholded)) + t1, t2, tdiff := h.Time.Time(), heartbeats[i-1].Time.Time(), time.Duration(0) + // This is a hack. The time difference between two heartbeats from two subsequent day (e.g. 23:59:59 and 00:00:01) are ignored. + // This is to prevent a discrepancy between summaries computed solely from heartbeats and summaries involving pre-aggregated per-day summaries. + // For the latter, a duration is already pre-computed and information about individual heartbeats is lost, so there can be no cross-day overflow. + // Essentially, we simply ignore such edge-case heartbeats here, which makes the eventual total duration potentially a bit shorter. + if t1.Day() == t2.Day() { + timePassed := t1.Sub(t2) + tdiff = time.Duration(int64(math.Min(float64(timePassed), float64(HeartbeatDiffThreshold)))) + } + durations[key] += tdiff } items := make([]*models.SummaryItem, 0) @@ -269,7 +278,7 @@ func getMissingIntervals(from, to time.Time, existingSummaries []*models.Summary // Post if to.After(existingSummaries[len(existingSummaries)-1].ToTime) { - intervals = append(intervals, &Interval{to, existingSummaries[len(existingSummaries)-1].ToTime}) + intervals = append(intervals, &Interval{existingSummaries[len(existingSummaries)-1].ToTime, to}) } return intervals diff --git a/version.txt b/version.txt index c56eaaa..44fdbc3 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.12.3 \ No newline at end of file +1.12.4 \ No newline at end of file