package app import ( "time" "gitea.maximumdirect.net/eric/weatherreporter/internal/timeutil" "gitea.maximumdirect.net/eric/weatherreporter/internal/weatherdata" ) func eligibleDailyDates(hourly *weatherdata.ForecastRun, now time.Time, location *time.Location) []time.Time { if hourly == nil || location == nil || hourly.Product != "hourly" || len(hourly.Periods) == 0 { return nil } hourlyStarts := make(map[time.Time]struct{}, len(hourly.Periods)) var maxLocalDate time.Time for _, period := range hourly.Periods { if !isHourlyPeriod(period) { continue } start := period.StartTime hourlyStarts[instantKey(start)] = struct{}{} localDate := localDateStart(start, location) if maxLocalDate.IsZero() || localDate.After(maxLocalDate) { maxLocalDate = localDate } } if len(hourlyStarts) == 0 || maxLocalDate.IsZero() { return nil } startDate := localDateStart(now.In(location).AddDate(0, 0, 2), location) var dates []time.Time for candidate := startDate; !candidate.After(maxLocalDate); candidate = candidate.AddDate(0, 0, 1) { if hasFullHourlyCoverage(candidate, location, hourlyStarts) { dates = append(dates, candidate) } } return dates } func isHourlyPeriod(period weatherdata.ForecastPeriod) bool { if period.StartTime.IsZero() || period.EndTime.IsZero() { return false } return period.EndTime.Equal(period.StartTime.Add(time.Hour)) } func hasFullHourlyCoverage(date time.Time, location *time.Location, hourlyStarts map[time.Time]struct{}) bool { day := timeutil.CivilDay(date, location) for required := day.Start; required.Before(day.End); required = required.Add(time.Hour) { if _, ok := hourlyStarts[instantKey(required)]; !ok { return false } } return true } func instantKey(value time.Time) time.Time { return value.UTC() } func localDateStart(value time.Time, location *time.Location) time.Time { local := value.In(location) return time.Date(local.Year(), local.Month(), local.Day(), 0, 0, 0, 0, location) }