diff --git a/aleksis/apps/chronos/models.py b/aleksis/apps/chronos/models.py
index 9f3c2fcb17b32d9c915610bd6aaa8b948752ee44..ed4caa85b485d4496603f8c92d2a73598c8f130c 100644
--- a/aleksis/apps/chronos/models.py
+++ b/aleksis/apps/chronos/models.py
@@ -9,6 +9,8 @@ from django.db import models
 from django.db.models import F, Max, Min, Q
 from django.db.models.functions import Coalesce
 from django.http.request import QueryDict
+from django.urls import reverse
+from django.utils import timezone
 from django.utils.decorators import classproperty
 from django.utils.translation import ugettext_lazy as _
 
@@ -205,6 +207,21 @@ class LessonSubstitutionQuerySet(LessonDataQuerySet):
     _period_path = "lesson_period__"
     _subst_path = ""
 
+    def affected_lessons(self):
+        """ Return all lessons which are affected by selected substitutions """
+
+        return Lesson.objects.filter(lesson_periods__substitutions__in=self)
+
+    def affected_teachers(self):
+        """ Return all teachers which are affected by selected substitutions (as substituted or substituting) """
+
+        return Person.objects.filter(Q(lessons_as_teacher__in=self.affected_lessons()) | Q(lesson_substitutions__in=self))
+
+    def affected_groups(self):
+        """ Return all groups which are affected by selected substitutions """
+
+        return Group.objects.filter(lessons__in=self.affected_lessons())
+
 
 class TimePeriod(models.Model):
     WEEKDAY_CHOICES = list(enumerate(i18n_day_names_lazy()))
@@ -246,6 +263,46 @@ class TimePeriod(models.Model):
 
         return wanted_week[self.weekday]
 
+    @classmethod
+    def get_next_relevant_day(cls, day: Optional[date] = None, time: Optional[time] = None, prev: bool = False) -> date:
+        """ Returns next (previous) day with lessons depending on date and time """
+
+        if day is None:
+            day = timezone.now().date()
+
+        if time is not None and not prev:
+            if time > cls.time_max:
+                day += timedelta(days=1)
+
+        cw = CalendarWeek.from_date(day)
+
+        if day.weekday() > cls.weekday_max:
+            if prev:
+                day = cw[cls.weekday_max]
+            else:
+                cw += 1
+                day = cw[cls.weekday_min]
+        elif day.weekday() < TimePeriod.weekday_min:
+            if prev:
+                cw -= 1
+                day = cw[cls.weekday_max]
+            else:
+                day = cw[cls.weekday_min]
+
+        return day
+
+    @classmethod
+    def get_prev_next_by_day(cls, day: date, url: str) -> Tuple[str, str]:
+        """ Build URLs for previous/next day """
+
+        day_prev = cls.get_next_relevant_day(day - timedelta(days=1), prev=True)
+        day_next = cls.get_next_relevant_day(day + timedelta(days=1))
+
+        url_prev = reverse(url, args=[day_prev.year, day_prev.month, day_prev.day])
+        url_next = reverse(url, args=[day_next.year, day_next.month, day_next.day])
+
+        return url_prev, url_next
+
     @classproperty
     def period_min(cls) -> int:
         return cls.objects.aggregate(period__min=Coalesce(Min("period"), 1)).get("period__min")
diff --git a/aleksis/apps/chronos/settings.py b/aleksis/apps/chronos/settings.py
index 1ae08d71d21171078752c8f2d80b719b2668e4cc..2c861857f006770095861fdfdd249195a3477c16 100644
--- a/aleksis/apps/chronos/settings.py
+++ b/aleksis/apps/chronos/settings.py
@@ -1,8 +1,18 @@
 from django.utils.translation import gettext_lazy as _
 
 CONSTANCE_CONFIG = {
-    "CHRONOS_SUBSTITUTIONS_PRINT_DAY_NUMBER": (2, _("Number of days shown on substitutions print view")),
+    "CHRONOS_SUBSTITUTIONS_PRINT_DAY_NUMBER": (
+        2,
+        _("Number of days shown on substitutions print view"),
+    ),
+    "CHRONOS_SUBSTITUTIONS_SHOW_HEADER_BOX": (
+        True,
+        _("The header box shows affected teachers/groups."),
+    ),
 }
 CONSTANCE_CONFIG_FIELDSETS = {
-    "Chronos settings": ("CHRONOS_SUBSTITUTIONS_PRINT_DAY_NUMBER",),
+    "Chronos settings": (
+        "CHRONOS_SUBSTITUTIONS_PRINT_DAY_NUMBER",
+        "CHRONOS_SUBSTITUTIONS_SHOW_HEADER_BOX",
+    ),
 }
diff --git a/aleksis/apps/chronos/static/css/chronos/timetable.css b/aleksis/apps/chronos/static/css/chronos/timetable.css
index 324272585c7a0447c8f2e901fafbfb7be94dfa7a..16846c6059e92d49a8ba89258a7b259793c427b0 100644
--- a/aleksis/apps/chronos/static/css/chronos/timetable.css
+++ b/aleksis/apps/chronos/static/css/chronos/timetable.css
@@ -108,3 +108,7 @@ table.substitutions td, table.substitutions th {
     margin: 2px;
     letter-spacing: 0.3pt;
 }
+
+.black-text-a a {
+    color: black;
+}
diff --git a/aleksis/apps/chronos/templates/chronos/partials/headerbox.html b/aleksis/apps/chronos/templates/chronos/partials/headerbox.html
new file mode 100644
index 0000000000000000000000000000000000000000..bc5bd0f34891d644fbaf4f5e2c065f2be450dec9
--- /dev/null
+++ b/aleksis/apps/chronos/templates/chronos/partials/headerbox.html
@@ -0,0 +1,33 @@
+{% load i18n %}
+
+{% if affected_teachers and affected_groups %}
+  <div class="{% if not print %}card{% endif %}">
+    <div class="{% if not print %}card-content{% endif %}">
+      {% if affected_teachers %}
+        <div class="row no-margin">
+          <div class="col s12 m3">
+            <strong class="truncate">
+              {% trans "Affected teachers" %}
+            </strong>
+          </div>
+          <div class="col s12 m9 black-text-a">
+            {% include "chronos/partials/teachers.html" with teachers=affected_teachers %}
+          </div>
+        </div>
+      {% endif %}
+      {% if affected_groups %}
+        <div class="row no-margin">
+          <div class="col s12 m3">
+            <strong class="truncate">
+              {% trans "Affected groups" %}
+            </strong>
+          </div>
+          <div class="col s12 m9 black-text-a">
+            {% include "chronos/partials/groups.html" with groups=affected_groups %}
+          </div>
+        </div>
+      {% endif %}
+    </div>
+  </div>
+  {% if print %}<br/>{% endif %}
+{% endif %}
diff --git a/aleksis/apps/chronos/templates/chronos/substitutions.html b/aleksis/apps/chronos/templates/chronos/substitutions.html
index 32e98c56d705fc815f709a7cbcc063c5206cb191..0dc5e242852375b05ff6f48e2b35430d61510727 100644
--- a/aleksis/apps/chronos/templates/chronos/substitutions.html
+++ b/aleksis/apps/chronos/templates/chronos/substitutions.html
@@ -26,22 +26,7 @@
 
   <div class="row no-print">
     <div class="col s12 m6 l8">
-      {% if header_info.is_box_needed %}
-        <div class="card">
-          <div class="card-content">
-            {% for row in header_info.rows %}
-              <div class="row no-margin">
-                <div class="col s3">
-                  <strong class="truncate">{{ row.0 }}</strong>
-                </div>
-                <div class="col s9">
-                  {{ row.1 }}
-                </div>
-              </div>
-            {% endfor %}
-          </div>
-        </div>
-      {% endif %}
+      {% include "chronos/partials/headerbox.html" %}
 
       {#            {% include "chronos/hintsinsub.html" %}#}
     </div>
diff --git a/aleksis/apps/chronos/templates/chronos/substitutions_print.html b/aleksis/apps/chronos/templates/chronos/substitutions_print.html
index 2a4e474bb2fc407f1297efb754d984140fc30fd0..bc041f24c2c366b6ae2764afde621a2e8802a291 100644
--- a/aleksis/apps/chronos/templates/chronos/substitutions_print.html
+++ b/aleksis/apps/chronos/templates/chronos/substitutions_print.html
@@ -18,20 +18,7 @@
 
     {#    {% include "timetable/hintsinsubprint.html" %}#}
 
-    {#    <div style="margin-bottom: 20px">#}
-    {#        {% if c.header_info.is_box_needed %}#}
-    {#            {% for row in c.header_info.rows %}#}
-    {#                <div class="row no-margin">#}
-    {#                    <div class="col s3 no-padding">#}
-    {#                        <strong>{{ row.0 }}</strong>#}
-    {#                    </div>#}
-    {#                    <div class="col s9 no-padding">#}
-    {#                        {{ row.1 }}#}
-    {#                    </div>#}
-    {#                </div>#}
-    {#            {% endfor %}#}
-    {#        {% endif %}#}
-    {#    </div>#}
+    {% include "chronos/partials/headerbox.html" with affected_teachers=c.affected_teachers affected_groups=c.affected_groups print=1 %}
 
     <table class="substitutions">
       <thead>
diff --git a/aleksis/apps/chronos/util/prev_next.py b/aleksis/apps/chronos/util/prev_next.py
deleted file mode 100644
index 4f954c3082eb69e5c18afb12896c975ed07135b0..0000000000000000000000000000000000000000
--- a/aleksis/apps/chronos/util/prev_next.py
+++ /dev/null
@@ -1,48 +0,0 @@
-from datetime import timedelta, date, time
-from typing import Optional, Tuple
-
-from calendarweek import CalendarWeek
-from django.urls import reverse
-from django.utils import timezone
-
-from ..models import TimePeriod
-
-
-def get_next_relevant_day(day: Optional[date] = None, time: Optional[time] = None, prev: bool = False) -> date:
-    """ Returns next (previous) day with lessons depending on date and time """
-
-    if day is None:
-        day = timezone.now().date()
-
-    if time is not None and not prev:
-        if time > TimePeriod.time_max:
-            day += timedelta(days=1)
-
-    cw = CalendarWeek.from_date(day)
-
-    if day.weekday() > TimePeriod.weekday_max:
-        if prev:
-            day = cw[TimePeriod.weekday_max]
-        else:
-            cw += 1
-            day = cw[TimePeriod.weekday_min]
-    elif day.weekday() < TimePeriod.weekday_min:
-        if prev:
-            cw -= 1
-            day = cw[TimePeriod.weekday_max]
-        else:
-            day = cw[TimePeriod.weekday_min]
-
-    return day
-
-
-def get_prev_next_by_day(day: date, url: str) -> Tuple[str, str]:
-    """ Build URLs for previous/next day """
-
-    day_prev = get_next_relevant_day(day - timedelta(days=1), prev=True)
-    day_next = get_next_relevant_day(day + timedelta(days=1))
-
-    url_prev = reverse(url, args=[day_prev.year, day_prev.month, day_prev.day])
-    url_next = reverse(url, args=[day_next.year, day_next.month, day_next.day])
-
-    return url_prev, url_next
diff --git a/aleksis/apps/chronos/views.py b/aleksis/apps/chronos/views.py
index b3dedd30fc75c63be1600a76e851fc418b42468e..22ab295fd14e89b30ff288e15b337e771b9e5d84 100644
--- a/aleksis/apps/chronos/views.py
+++ b/aleksis/apps/chronos/views.py
@@ -19,7 +19,6 @@ from .forms import LessonSubstitutionForm
 from .models import LessonPeriod, LessonSubstitution, TimePeriod, Room
 from .tables import LessonsTable
 from .util.js import date_unix
-from .util.prev_next import get_next_relevant_day, get_prev_next_by_day
 from .util.date import CalendarWeek, get_weeks_for_year
 from aleksis.core.util.core_helpers import has_person
 
@@ -56,9 +55,9 @@ def my_timetable(
 
     if day:
         wanted_day = timezone.datetime(year=year, month=month, day=day).date()
-        wanted_day = get_next_relevant_day(wanted_day)
+        wanted_day = TimePeriod.get_next_relevant_day(wanted_day)
     else:
-        wanted_day = get_next_relevant_day(timezone.now().date(), datetime.now().time())
+        wanted_day = TimePeriod.get_next_relevant_day(timezone.now().date(), datetime.now().time())
 
     if has_person(request.user):
         person = request.user.person
@@ -98,7 +97,7 @@ def my_timetable(
     context["periods"] = TimePeriod.get_times_dict()
     context["smart"] = True
 
-    context["url_prev"], context["url_next"] = get_prev_next_by_day(
+    context["url_prev"], context["url_next"] = TimePeriod.get_prev_next_by_day(
         wanted_day, "my_timetable_by_date"
     )
 
@@ -209,9 +208,9 @@ def lessons_day(
 
     if day:
         wanted_day = timezone.datetime(year=year, month=month, day=day).date()
-        wanted_day = get_next_relevant_day(wanted_day)
+        wanted_day = TimePeriod.get_next_relevant_day(wanted_day)
     else:
-        wanted_day = get_next_relevant_day(timezone.now().date(), datetime.now().time())
+        wanted_day = TimePeriod.get_next_relevant_day(timezone.now().date(), datetime.now().time())
 
     # Get lessons
     lesson_periods = LessonPeriod.objects.on_day(wanted_day)
@@ -229,7 +228,7 @@ def lessons_day(
         "dest": reverse("lessons_day")
     }
 
-    context["url_prev"], context["url_next"] = get_prev_next_by_day(
+    context["url_prev"], context["url_next"] = TimePeriod.get_prev_next_by_day(
         wanted_day, "lessons_day_by_date"
     )
 
@@ -305,9 +304,9 @@ def substitutions(
 
     if day:
         wanted_day = timezone.datetime(year=year, month=month, day=day).date()
-        wanted_day = get_next_relevant_day(wanted_day)
+        wanted_day = TimePeriod.get_next_relevant_day(wanted_day)
     else:
-        wanted_day = get_next_relevant_day(timezone.now().date(), datetime.now().time())
+        wanted_day = TimePeriod.get_next_relevant_day(timezone.now().date(), datetime.now().time())
 
     day_number = config.CHRONOS_SUBSTITUTIONS_PRINT_DAY_NUMBER
     day_contexts = {}
@@ -316,14 +315,17 @@ def substitutions(
         next_day = wanted_day
         for i in range(day_number):
             day_contexts[next_day] = {"day": next_day}
-            next_day = get_next_relevant_day(next_day + timedelta(days=1))
+            next_day = TimePeriod.get_next_relevant_day(next_day + timedelta(days=1))
     else:
         day_contexts = {wanted_day: {"day": wanted_day}}
 
     for day in day_contexts:
-        day_contexts[day]["substitutions"] = LessonSubstitution.objects.on_day(
-            day
-        ).order_by("lesson_period__lesson__groups", "lesson_period__period")
+        subs = LessonSubstitution.objects.on_day(day).order_by("lesson_period__lesson__groups", "lesson_period__period")
+        day_contexts[day]["substitutions"] = subs
+
+        if config.CHRONOS_SUBSTITUTIONS_SHOW_HEADER_BOX:
+            day_contexts[day]["affected_teachers"] = subs.affected_teachers()
+            day_contexts[day]["affected_groups"] = subs.affected_groups()
 
     if not is_print:
         context = day_contexts[wanted_day]
@@ -332,7 +334,7 @@ def substitutions(
             "dest": reverse("substitutions"),
         }
 
-        context["url_prev"], context["url_next"] = get_prev_next_by_day(
+        context["url_prev"], context["url_next"] = TimePeriod.get_prev_next_by_day(
             wanted_day, "substitutions_by_date"
         )