summaryrefslogtreecommitdiff
path: root/internal/schedule/stats.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-06-12 20:54:13 +0300
committerPaul Buetow <paul@buetow.org>2025-06-12 20:54:13 +0300
commit09ad1901e93158ccbbfd64033849e1835fb3ecb8 (patch)
tree8bc13caeefd0e231531265ae2973121ed9a16a0a /internal/schedule/stats.go
parentc9ae38674e91eeddf9f26fc64d4ddd3a3a3fbbfe (diff)
improve stats calculation to exclude pause periods
- Modify newStats() and gatherPostedStats() to accept config parameter - Add calculatePausedDays() helper function for pause period overlap calculation - Update postsPerDay and totalPostsPerDay calculations to exclude paused days - Prevent artificially low throughput during pause periods - Add comprehensive unit tests for pause-aware stats functionality - Maintain backward compatibility when no pause is configured Fixes issue where Gos would post aggressively after vacation periods due to including pause days in throughput calculations. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'internal/schedule/stats.go')
-rw-r--r--internal/schedule/stats.go71
1 files changed, 66 insertions, 5 deletions
diff --git a/internal/schedule/stats.go b/internal/schedule/stats.go
index eba2eee..b0f35d1 100644
--- a/internal/schedule/stats.go
+++ b/internal/schedule/stats.go
@@ -7,6 +7,7 @@ import (
"time"
"codeberg.org/snonux/gos/internal/colour"
+ "codeberg.org/snonux/gos/internal/config"
"codeberg.org/snonux/gos/internal/entry"
"codeberg.org/snonux/gos/internal/oi"
"codeberg.org/snonux/gos/internal/platforms"
@@ -31,10 +32,10 @@ type stats struct {
pauseDays int
}
-func newStats(dir string, lookback time.Duration, target, pauseDays, maxQueuedDays int) (stats, error) {
+func newStats(dir string, lookback time.Duration, target, pauseDays, maxQueuedDays int, cfg config.Config) (stats, error) {
s := stats{postsPerDayTarget: float64(target) / 7, pauseDays: pauseDays}
- if err := s.gatherPostedStats(dir, pastTime(lookback)); err != nil {
+ if err := s.gatherPostedStats(dir, pastTime(lookback), cfg); err != nil {
return s, err
}
if err := s.gatherQueuedStats(dir); err != nil {
@@ -71,7 +72,7 @@ func (s stats) targetHit() bool {
return false
}
-func (s *stats) gatherPostedStats(dir string, lookbackTime time.Time) error {
+func (s *stats) gatherPostedStats(dir string, lookbackTime time.Time, cfg config.Config) error {
var (
now time.Time = timestamp.NowTime()
newest time.Time = timestamp.OldestValidTime()
@@ -114,12 +115,26 @@ func (s *stats) gatherPostedStats(dir string, lookbackTime time.Time) error {
since := now.Sub(oldest)
s.sinceDays = since.Abs().Hours() / 24.0
- s.postsPerDay = float64(s.posted) / float64(s.sinceDays)
+
+ // Subtract paused days from the calculation period
+ pausedDays := calculatePausedDays(oldest, now, cfg)
+ activeDays := s.sinceDays - pausedDays
+ if activeDays > 0 {
+ s.postsPerDay = float64(s.posted) / activeDays
+ } else {
+ s.postsPerDay = 0
+ }
s.lastPostDaysAgo = now.Sub(newest).Hours() / 24.0
since = now.Sub(totalOldest)
s.totalSinceDays = since.Abs().Hours() / 24.0
- s.totalPostsPerDay = float64(s.totalPosted) / float64(s.totalSinceDays)
+ totalPausedDays := calculatePausedDays(totalOldest, now, cfg)
+ totalActiveDays := s.totalSinceDays - totalPausedDays
+ if totalActiveDays > 0 {
+ s.totalPostsPerDay = float64(s.totalPosted) / totalActiveDays
+ } else {
+ s.totalPostsPerDay = 0
+ }
return nil
}
@@ -164,3 +179,49 @@ func (s stats) RenderTable(platform platforms.Platform) {
func pastTime(duration time.Duration) time.Time {
return timestamp.NowTime().Add(-duration)
}
+
+// calculatePausedDays calculates the number of days that fall within pause periods
+// between startTime and endTime
+func calculatePausedDays(startTime, endTime time.Time, cfg config.Config) float64 {
+ if cfg.PauseStart == "" || cfg.PauseEnd == "" {
+ return 0
+ }
+
+ pauseStart, err := time.Parse("2006-01-02", cfg.PauseStart)
+ if err != nil {
+ return 0 // If parse fails, assume no pause
+ }
+
+ pauseEnd, err := time.Parse("2006-01-02", cfg.PauseEnd)
+ if err != nil {
+ return 0 // If parse fails, assume no pause
+ }
+
+ // Set to start and end of day
+ pauseStart = time.Date(pauseStart.Year(), pauseStart.Month(), pauseStart.Day(), 0, 0, 0, 0, startTime.Location())
+ pauseEnd = time.Date(pauseEnd.Year(), pauseEnd.Month(), pauseEnd.Day(), 23, 59, 59, 999999999, endTime.Location())
+
+ // Find intersection of [startTime, endTime] with [pauseStart, pauseEnd]
+ intersectionStart := maxTime(startTime, pauseStart)
+ intersectionEnd := minTime(endTime, pauseEnd)
+
+ if intersectionStart.Before(intersectionEnd) || intersectionStart.Equal(intersectionEnd) {
+ return intersectionEnd.Sub(intersectionStart).Hours() / 24.0
+ }
+
+ return 0
+}
+
+func maxTime(a, b time.Time) time.Time {
+ if a.After(b) {
+ return a
+ }
+ return b
+}
+
+func minTime(a, b time.Time) time.Time {
+ if a.Before(b) {
+ return a
+ }
+ return b
+}