diff options
| author | Paul Buetow <paul@buetow.org> | 2025-06-12 20:54:13 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-06-12 20:54:13 +0300 |
| commit | 09ad1901e93158ccbbfd64033849e1835fb3ecb8 (patch) | |
| tree | 8bc13caeefd0e231531265ae2973121ed9a16a0a /internal/schedule/stats.go | |
| parent | c9ae38674e91eeddf9f26fc64d4ddd3a3a3fbbfe (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.go | 71 |
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 +} |
