diff --git a/aleksis/apps/chronos/managers.py b/aleksis/apps/chronos/managers.py
index 89e0599844e282b9a07c6c80d13abb008f946d89..8955a3f798ce82f1286f68c500905ce37777d540 100644
--- a/aleksis/apps/chronos/managers.py
+++ b/aleksis/apps/chronos/managers.py
@@ -699,4 +699,8 @@ class TeacherPropertiesMixin:
 
     @property
     def teacher_names(self, sep: Optional[str] = ", ") -> str:
-        return sep.join([teacher.full_name for teacher in self.teachers.all()])
+        return sep.join([teacher.full_name for teacher in self.get_teachers().all()])
+
+    @property
+    def teacher_short_names(self, sep: str = ", ") -> str:
+        return sep.join([teacher.short_name for teacher in self.get_teachers().all()])
diff --git a/aleksis/apps/chronos/mixins.py b/aleksis/apps/chronos/mixins.py
index fc07ce29b92600bcd7ad7ac1e564d19db58360ab..5a784579b4ca7a1adbbc32ec2c54f44cc28f18b0 100644
--- a/aleksis/apps/chronos/mixins.py
+++ b/aleksis/apps/chronos/mixins.py
@@ -34,7 +34,8 @@ class ValidityRangeRelatedExtensibleModel(ExtensibleModel):
 class WeekRelatedMixin:
     @property
     def date(self) -> date:
-        return week_weekday_to_date(self.calendar_week, self.lesson_period.period.weekday)
+        period = self.lesson_period.period if hasattr(self, "lesson_period") else self.period
+        return week_weekday_to_date(self.calendar_week, period.weekday)
 
     @property
     def calendar_week(self) -> CalendarWeek:
@@ -42,6 +43,11 @@ class WeekRelatedMixin:
 
 
 class WeekAnnotationMixin:
+    def annotate_week(self, week: CalendarWeek):
+        """Annotate this lesson with the number of the provided calendar week."""
+        self._week = week.week
+        self._year = week.year
+
     @property
     def week(self) -> Union[CalendarWeek, None]:
         """Get annotated week as `CalendarWeek`.
diff --git a/aleksis/apps/chronos/models.py b/aleksis/apps/chronos/models.py
index 03788999f74feb384cb1780f09ebb32a92040d39..65fa31138895ada78af7fcbbd73e9061139a429c 100644
--- a/aleksis/apps/chronos/models.py
+++ b/aleksis/apps/chronos/models.py
@@ -217,6 +217,14 @@ class TimePeriod(ValidityRangeRelatedExtensibleModel):
 
         return url_prev, url_next
 
+    @classmethod
+    def from_period(cls, period: int, day: date) -> "TimePeriod":
+        """Get `TimePeriod` object for a period on a specific date.
+
+        This will respect the relation to validity ranges.
+        """
+        return cls.objects.on_day(day).filter(period=period).first()
+
     @classproperty
     @cache_memoize(3600)
     def period_min(cls) -> int:
@@ -344,6 +352,10 @@ class Lesson(ValidityRangeRelatedExtensibleModel, GroupPropertiesMixin, TeacherP
 
         return CalendarWeek(year=year, week=week)
 
+    def get_teachers(self) -> models.query.QuerySet:
+        """Get teachers relation."""
+        return self.teachers
+
     def __str__(self):
         return f"{format_m2m(self.groups)}, {self.subject.short_name}, {format_m2m(self.teachers)}"
 
@@ -413,7 +425,7 @@ class LessonSubstitution(ExtensibleModel, WeekRelatedMixin):
         verbose_name_plural = _("Lesson substitutions")
 
 
-class LessonPeriod(ExtensibleModel, WeekAnnotationMixin):
+class LessonPeriod(WeekAnnotationMixin, TeacherPropertiesMixin, ExtensibleModel):
     label_ = "lesson_period"
 
     objects = LessonPeriodManager.from_queryset(LessonPeriodQuerySet)()
@@ -458,9 +470,6 @@ class LessonPeriod(ExtensibleModel, WeekAnnotationMixin):
         else:
             return self.room
 
-    def get_teacher_names(self, sep: Optional[str] = ", ") -> str:
-        return sep.join([teacher.full_name for teacher in self.get_teachers().all()])
-
     def get_groups(self) -> models.query.QuerySet:
         return self.lesson.groups
 
@@ -895,20 +904,70 @@ class Event(SchoolTermRelatedExtensibleModel, GroupPropertiesMixin, TeacherPrope
             return _(f"Event {self.pk}")
 
     @property
-    def period_from_on_day(self) -> int:
+    def raw_period_from_on_day(self) -> TimePeriod:
+        """Get start period on the annotated day (as TimePeriod object).
+
+        If there is no date annotated, it will use the current date.
+        """
         day = getattr(self, "_date", timezone.now().date())
         if day != self.date_start:
-            return TimePeriod.period_min
+            return TimePeriod.from_period(TimePeriod.period_min, day)
         else:
-            return self.period_from.period
+            return self.period_from
 
     @property
-    def period_to_on_day(self) -> int:
+    def raw_period_to_on_day(self) -> TimePeriod:
+        """Get end period on the annotated day (as TimePeriod object).
+
+        If there is no date annotated, it will use the current date.
+        """
         day = getattr(self, "_date", timezone.now().date())
         if day != self.date_end:
-            return TimePeriod.period_max
+            return TimePeriod.from_period(TimePeriod.period_max, day)
         else:
-            return self.period_to.period
+            return self.period_to
+
+    @property
+    def period_from_on_day(self) -> int:
+        """Get start period on the annotated day (as period number).
+
+        If there is no date annotated, it will use the current date.
+        """
+        return self.raw_period_from_on_day.period
+
+    @property
+    def period_to_on_day(self) -> int:
+        """Get end period on the annotated day (as period number).
+
+        If there is no date annotated, it will use the current date.
+        """
+        return self.raw_period_to_on_day.period
+
+    def get_start_weekday(self, week: CalendarWeek) -> int:
+        """Get start date of an event in a specific week."""
+        if self.date_start < week[TimePeriod.weekday_min]:
+            return TimePeriod.weekday_min
+        else:
+            return self.date_start.weekday()
+
+    def get_end_weekday(self, week: CalendarWeek) -> int:
+        """Get end date of an event in a specific week."""
+        if self.date_end > week[TimePeriod.weekday_max]:
+            return TimePeriod.weekday_max
+        else:
+            return self.date_end.weekday()
+
+    def annotate_day(self, day: date):
+        """Annotate event with the provided date."""
+        self._date = day
+
+    def get_groups(self) -> models.query.QuerySet:
+        """Get groups relation."""
+        return self.groups
+
+    def get_teachers(self) -> models.query.QuerySet:
+        """Get teachers relation."""
+        return self.teachers
 
     class Meta:
         ordering = ["date_start"]
@@ -917,7 +976,9 @@ class Event(SchoolTermRelatedExtensibleModel, GroupPropertiesMixin, TeacherPrope
         verbose_name_plural = _("Events")
 
 
-class ExtraLesson(SchoolTermRelatedExtensibleModel, GroupPropertiesMixin, WeekRelatedMixin):
+class ExtraLesson(
+    GroupPropertiesMixin, TeacherPropertiesMixin, WeekRelatedMixin, SchoolTermRelatedExtensibleModel
+):
     label_ = "extra_lesson"
 
     objects = ExtraLessonManager.from_queryset(ExtraLessonQuerySet)()
@@ -949,6 +1010,18 @@ class ExtraLesson(SchoolTermRelatedExtensibleModel, GroupPropertiesMixin, WeekRe
     def __str__(self):
         return f"{self.week}, {self.period}, {self.subject}"
 
+    def get_groups(self) -> models.query.QuerySet:
+        """Get groups relation."""
+        return self.groups
+
+    def get_teachers(self) -> models.query.QuerySet:
+        """Get teachers relation."""
+        return self.teachers
+
+    def get_subject(self) -> Subject:
+        """Get subject."""
+        return self.subject
+
     class Meta:
         verbose_name = _("Extra lesson")
         verbose_name_plural = _("Extra lessons")