diff --git a/program/services.py b/program/services.py
index d1a17fe27b4ac2c50f536dc62013c5615b893d1e..77e57bb3e4d0027105d376648ddc0a0ec6781ef6 100644
--- a/program/services.py
+++ b/program/services.py
@@ -765,12 +765,25 @@ def generate_program_entries(
     # show. We can only create these program entries if a fallback show has been specified.
     fallback_show = get_fallback_show(raise_exceptions=True)
 
-    entry_start = start
+    # Shift the range start/end to the closest scheduled timeslots around the specified range.
+    # This ensures that we generate stable ids for entries.
+    # We first check if the timeslots in our queryset might already start/end before/after the
+    # specified range, because we potentially include them according to the filter above.
+    first_ts_before_start = timeslots.first()
+    if not first_ts_before_start or first_ts_before_start.start > start:
+        first_ts_before_start = queryset.filter(end__lte=start).last()
+    first_ts_after_end = timeslots.last()
+    if not first_ts_after_end or first_ts_after_end.end < end:
+        first_ts_after_end = queryset.filter(start__gte=end).first()
+    range_start = first_ts_before_start.end if first_ts_before_start else start
+    range_end = first_ts_after_end.start if first_ts_after_end else end
+
+    entry_start = range_start
     timeslot: TimeSlot
     for timeslot in timeslots:
         if timeslot.start > entry_start:
             yield create_entry(entry_start, timeslot.start, fallback_show)
         yield create_timeslot_entry(timeslot)
         entry_start = timeslot.end
-    if entry_start < end:
-        yield create_entry(entry_start, end, fallback_show)
+    if entry_start < range_end:
+        yield create_entry(entry_start, range_end, fallback_show)