diff --git a/custom_components/adaptive_lighting/color_and_brightness.py b/custom_components/adaptive_lighting/color_and_brightness.py index e62beb0c..4645f994 100644 --- a/custom_components/adaptive_lighting/color_and_brightness.py +++ b/custom_components/adaptive_lighting/color_and_brightness.py @@ -193,10 +193,12 @@ class SunEvents: middle = abs(sunset - sunrise) / 2 if sunset > sunrise: noon = sunrise + middle - midnight = noon + timedelta(hours=12) * (1 if noon.hour < 12 else -1) + next_sunrise = self.sunrise(dt + timedelta(days=1)) + midnight = sunset + (next_sunrise - sunset) / 2 else: midnight = sunset + middle - noon = midnight + timedelta(hours=12) * (1 if midnight.hour < 12 else -1) + next_sunset = self.sunset(dt + timedelta(days=1)) + noon = sunrise + (next_sunset - sunrise) / 2 return noon, midnight def sun_events(self, dt: datetime.datetime) -> list[tuple[SunEvent, float]]: diff --git a/tests/test_color_and_brightness.py b/tests/test_color_and_brightness.py index e7f0a21a..8598b121 100644 --- a/tests/test_color_and_brightness.py +++ b/tests/test_color_and_brightness.py @@ -153,6 +153,41 @@ def test_noon_and_midnight(tzinfo_and_location): assert midnight == location.midnight(date) +@pytest.mark.parametrize("day", [dt.date(2026, 4, 17), dt.date(2026, 8, 30)]) +def test_midnight_falls_in_the_night_it_belongs_to(day): + """Derived midnight must lie between sunset and the next sunrise (#1599).""" + location = Location( + LocationInfo( + name="name", + region="region", + timezone="UTC", + latitude=51.5, + longitude=0.0, # on the prime meridian + ), + ) + sun_events = SunEvents( + name="test", + astral_observer=location.observer, + sunrise_time=None, + min_sunrise_time=None, + max_sunrise_time=dt.time(8, 0), + sunset_time=None, + min_sunset_time=dt.time(17, 0), + max_sunset_time=dt.time(20, 0), + timezone=zoneinfo.ZoneInfo("UTC"), + ) + date = dt.datetime.combine(day, dt.time(12), tzinfo=dt.UTC) + sunset = sun_events.sunset(date) + next_sunrise = sun_events.sunrise(date + dt.timedelta(days=1)) + _, midnight = sun_events.noon_and_midnight(date) + assert sunset < midnight < next_sunrise + + just_after_sunset = sunset + dt.timedelta(minutes=40) + events = sun_events.prev_and_next_events(just_after_sunset) + assert [event for event, _ in events] == [SunEvent.SUNSET, SunEvent.MIDNIGHT] + assert sun_events.sun_position(just_after_sunset) > -0.5 + + def test_sun_events(tzinfo_and_location): tzinfo, location = tzinfo_and_location sun_events = SunEvents(