diff --git a/aleksis/apps/alsijil/forms.py b/aleksis/apps/alsijil/forms.py
index 445f4a2055948ecd4b73a2c27586bc20838af6e6..ca1e2e5bffa70497f3522cde05cbb264b81be51b 100644
--- a/aleksis/apps/alsijil/forms.py
+++ b/aleksis/apps/alsijil/forms.py
@@ -7,9 +7,10 @@ from django.utils.translation import gettext_lazy as _
 
 from django_select2.forms import Select2Widget
 from guardian.shortcuts import get_objects_for_user
-from material import Layout, Row
+from material import Fieldset, Layout, Row
 
 from aleksis.apps.chronos.managers import TimetableType
+from aleksis.apps.chronos.models import TimePeriod
 from aleksis.core.models import Group, Person
 from aleksis.core.util.predicates import check_global_permission
 
@@ -99,23 +100,29 @@ PersonalNoteFormSet = forms.modelformset_factory(
 
 class RegisterAbsenceForm(forms.Form):
     layout = Layout(
-        Row("date_start", "date_end"),
-        Row("from_period"),
-        Row("absent", "excused"),
-        Row("person"),
-        Row("remarks"),
+        Fieldset("", "person"),
+        Fieldset("", Row("date_start", "date_end"), Row("from_period", "to_period")),
+        Fieldset("", Row("absent", "excused"), Row("excuse_type"), Row("remarks")),
     )
     date_start = forms.DateField(label=_("Start date"), initial=datetime.today)
     date_end = forms.DateField(label=_("End date"), initial=datetime.today)
-    from_period = forms.IntegerField(label=_("From period"), initial=0, min_value=0)
     person = forms.ModelChoiceField(label=_("Person"), queryset=None, widget=Select2Widget)
+    from_period = forms.ChoiceField(label=_("Start period"))
+    to_period = forms.ChoiceField(label=_("End period"))
     absent = forms.BooleanField(label=_("Absent"), initial=True, required=False)
     excused = forms.BooleanField(label=_("Excused"), initial=True, required=False)
+    excuse_type = forms.ModelChoiceField(
+        label=_("Excuse type"),
+        queryset=ExcuseType.objects.all(),
+        widget=Select2Widget,
+        required=False,
+    )
     remarks = forms.CharField(label=_("Remarks"), max_length=30, required=False)
 
     def __init__(self, *args, **kwargs):
         self.request = kwargs.pop("request")
         super().__init__(*args, **kwargs)
+        period_choices = TimePeriod.period_choices
         if check_global_permission(self.request.user, "alsijil.register_absence"):
             self.fields["person"].queryset = Person.objects.all()
         else:
@@ -130,6 +137,10 @@ class RegisterAbsenceForm(forms.Form):
                     )
                 )
             )
+        self.fields["from_period"].choices = period_choices
+        self.fields["to_period"].choices = period_choices
+        self.fields["from_period"].initial = TimePeriod.period_min
+        self.fields["to_period"].initial = TimePeriod.period_max
 
 
 class ExtraMarkForm(forms.ModelForm):
diff --git a/aleksis/apps/alsijil/model_extensions.py b/aleksis/apps/alsijil/model_extensions.py
index d840b273b6cc3ddd8b8cbc682219836247fffc03..ce997f31a12e056bf72aad7abe21242941e850fe 100644
--- a/aleksis/apps/alsijil/model_extensions.py
+++ b/aleksis/apps/alsijil/model_extensions.py
@@ -21,6 +21,7 @@ def mark_absent(
     excused: bool = False,
     excuse_type: Optional[ExcuseType] = None,
     remarks: str = "",
+    to_period: Optional[int] = None,
 ):
     """Mark a person absent for all lessons in a day, optionally starting with a selected period number.
 
@@ -40,6 +41,9 @@ def mark_absent(
         period__period__gte=from_period
     )
 
+    if to_period:
+        lesson_periods = lesson_periods.filter(period__period__lte=to_period)
+
     # Create and update all personal notes for the discovered lesson periods
     for lesson_period in lesson_periods:
         personal_note, created = PersonalNote.objects.update_or_create(
@@ -104,7 +108,10 @@ def get_personal_notes(self, persons: QuerySet, wanted_week: CalendarWeek):
         personal_note.groups_of_person.set(personal_note.person.member_of.all())
 
     return PersonalNote.objects.select_related("person").filter(
-        lesson_period=self, week=wanted_week.week, year=wanted_week.year
+        lesson_period=self,
+        week=wanted_week.week,
+        year=wanted_week.year,
+        person__in=persons,
     )
 
 
diff --git a/aleksis/apps/alsijil/rules.py b/aleksis/apps/alsijil/rules.py
index 79ea32519c451f158100da1f67d6ea6ffb3a1ec6..73d8879cf26c1f6e8281c41deaecced0d33a5547 100644
--- a/aleksis/apps/alsijil/rules.py
+++ b/aleksis/apps/alsijil/rules.py
@@ -10,17 +10,17 @@ from aleksis.core.util.predicates import (
 from .util.predicates import (
     has_any_object_absence,
     has_lesson_group_object_perm,
-    has_personal_note_group_perm,
     has_person_group_object_perm,
+    has_personal_note_group_perm,
     is_group_member,
     is_group_owner,
     is_lesson_parent_group_owner,
     is_lesson_participant,
     is_lesson_teacher,
     is_own_personal_note,
+    is_person_group_owner,
     is_personal_note_lesson_parent_group_owner,
     is_personal_note_lesson_teacher,
-    is_person_group_owner,
 )
 
 # View lesson
@@ -36,6 +36,15 @@ add_perm("alsijil.view_lesson", view_lesson_predicate)
 # View lesson in menu
 add_perm("alsijil.view_lesson_menu", has_person)
 
+# View lesson personal notes
+view_lesson_personal_notes_predicate = has_person & (
+    has_global_perm("alsijil.view_personalnote")
+    | has_lesson_group_object_perm("core.view_personalnote_group")
+    | is_lesson_teacher
+    | is_lesson_parent_group_owner
+)
+add_perm("alsijil.view_lesson_personalnote", view_lesson_personal_notes_predicate)
+
 # View personal note
 view_personal_note_predicate = has_person & (
     has_global_perm("alsijil.view_personalnote")
@@ -95,8 +104,7 @@ add_perm("alsijil.view_week_personalnote", view_week_personal_notes_predicate)
 
 # View register absence page
 view_register_absence_predicate = has_person & (
-    has_global_perm("alsijil.register_absence")
-    | has_any_object_absence
+    has_global_perm("alsijil.register_absence") | has_any_object_absence
 )
 add_perm("alsijil.view_register_absence", view_register_absence_predicate)
 
diff --git a/aleksis/apps/alsijil/templates/alsijil/absences/register.html b/aleksis/apps/alsijil/templates/alsijil/absences/register.html
index 908f3b32194889eb206244a30bf3b843a8193309..b14890e21438a6e452c4fa3e6c595f99d5b856dd 100644
--- a/aleksis/apps/alsijil/templates/alsijil/absences/register.html
+++ b/aleksis/apps/alsijil/templates/alsijil/absences/register.html
@@ -2,8 +2,8 @@
 {% extends "core/base.html" %}
 {% load material_form i18n static %}
 
-{% block browser_title %}{% blocktrans %}Manage absence{% endblocktrans %}{% endblock %}
-{% block page_title %}{% blocktrans %}Manage absence{% endblocktrans %}{% endblock %}
+{% block browser_title %}{% blocktrans %}Register absence{% endblocktrans %}{% endblock %}
+{% block page_title %}{% blocktrans %}Register absence{% endblocktrans %}{% endblock %}
 
 {% block content %}
 
@@ -13,4 +13,12 @@
     {% include "core/partials/save_button.html" %}
   </form>
 
+  <script>
+    $(document).ready(function () {
+      $("#id_date_start").change(function () {
+        $("#id_date_end").val($("#id_date_start").val());
+        $("#id_date_end").change();
+      });
+    });
+  </script>
 {% endblock %}
diff --git a/aleksis/apps/alsijil/util/predicates.py b/aleksis/apps/alsijil/util/predicates.py
index 6540aeb5dffd1368058a087da92c2d3bbf303f33..3e62d17a2a3f338fa7c8f3a94dd8eb6c2a8fa821 100644
--- a/aleksis/apps/alsijil/util/predicates.py
+++ b/aleksis/apps/alsijil/util/predicates.py
@@ -7,8 +7,8 @@ from rules import predicate
 
 from aleksis.apps.chronos.models import LessonPeriod
 from aleksis.core.models import Group, Person
-from aleksis.core.util.predicates import check_object_permission
 from aleksis.core.util.core_helpers import get_site_preferences
+from aleksis.core.util.predicates import check_object_permission
 
 from ..models import PersonalNote
 
@@ -21,10 +21,10 @@ def is_lesson_teacher(user: User, obj: LessonPeriod) -> bool:
     in the lesson or the substitution linked to the given LessonPeriod.
     """
     if obj:
-        return (
-            user.person in obj.lesson.teachers.all()
-            or user.person in Person.objects.filter(lesson_substitutions=obj.get_substitution())
-        )
+        sub = obj.get_substitution()
+        if sub and sub in user.person.lesson_substitutions.all():
+            return True
+        return user.person in obj.lesson.teachers.all()
     return True
 
 
@@ -154,7 +154,10 @@ def is_own_personal_note(user: User, obj: PersonalNote) -> bool:
     Is configurable via dynamic preferences.
     """
     if hasattr(obj, "person"):
-        if get_site_preferences()["alsijil__view_own_personal_notes"] and obj.person is user.person:
+        if (
+            get_site_preferences()["alsijil__view_own_personal_notes"]
+            and obj.person is user.person
+        ):
             return True
         return False
 
@@ -168,9 +171,8 @@ def is_personal_note_lesson_teacher(user: User, obj: PersonalNote) -> bool:
     """
     if hasattr(obj, "lesson_period"):
         if hasattr(obj.lesson_period, "lesson"):
-            return (
-                user.person in obj.lesson_period.lesson.teachers.all()
-                or user.person in Person.objects.filter(lesson_substitutions=obj.lesson_period.get_substitution())
+            return user.person in obj.lesson_period.lesson.teachers.all() or user.person in Person.objects.filter(
+                lesson_substitutions=obj.lesson_period.get_substitution()
             )
         return False
     return False
@@ -186,7 +188,9 @@ def is_personal_note_lesson_parent_group_owner(user: User, obj: PersonalNote) ->
     """
     if hasattr(obj, "lesson_period"):
         if hasattr(obj.lesson_period, "lesson"):
-            return obj.lesson_period.lesson.groups.filter(parent_groups__owners=user.person).exists()
+            return obj.lesson_period.lesson.groups.filter(
+                parent_groups__owners=user.person
+            ).exists()
         return False
     return False
 
@@ -200,5 +204,7 @@ def has_any_object_absence(user: User) -> bool:
         return True
     if Person.objects.filter(member_of__owners=user.person).exists():
         return True
-    if Person.objects.filter(member_of__in=get_objects_for_user(user, "core.register_absence_group", Group)).exists():
+    if Person.objects.filter(
+        member_of__in=get_objects_for_user(user, "core.register_absence_group", Group)
+    ).exists():
         return True
diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py
index 34ace3a0b599f7585c6723fa0529353509b6cb32..c9b1877cf55e767777263142e60ae51101ce7a34 100644
--- a/aleksis/apps/alsijil/views.py
+++ b/aleksis/apps/alsijil/views.py
@@ -14,7 +14,7 @@ from reversion.views import RevisionMixin
 from rules.contrib.views import PermissionRequiredMixin, permission_required
 
 from aleksis.apps.chronos.managers import TimetableType
-from aleksis.apps.chronos.models import LessonPeriod
+from aleksis.apps.chronos.models import LessonPeriod, TimePeriod
 from aleksis.apps.chronos.util.chronos_helpers import get_el_by_pk
 from aleksis.apps.chronos.util.date import get_weeks_for_year, week_weekday_to_date
 from aleksis.core.mixins import AdvancedCreateView, AdvancedDeleteView, AdvancedEditView
@@ -107,9 +107,9 @@ def lesson(
     )
 
     # Create a formset that holds all personal notes for all persons in this lesson
-    persons = Person.objects
+    persons = Person.objects.all()
     if not request.user.has_perm("alsijil.view_lesson_personalnote", lesson_period):
-        persons = persons.filter(pk=request.user.pk)
+        persons = persons.filter(pk=request.user.person.pk)
     persons_qs = lesson_period.get_personal_notes(persons, wanted_week)
     personal_note_formset = PersonalNoteFormSet(
         request.POST or None, queryset=persons_qs, prefix="personal_notes"
@@ -485,19 +485,33 @@ def register_absence(request: HttpRequest) -> HttpResponse:
             start_date = register_absence_form.cleaned_data["date_start"]
             end_date = register_absence_form.cleaned_data["date_end"]
             from_period = register_absence_form.cleaned_data["from_period"]
+            to_period = register_absence_form.cleaned_data["to_period"]
             absent = register_absence_form.cleaned_data["absent"]
             excused = register_absence_form.cleaned_data["excused"]
+            excuse_type = register_absence_form.cleaned_data["excuse_type"]
             remarks = register_absence_form.cleaned_data["remarks"]
 
             # Mark person as absent
             delta = end_date - start_date
             for i in range(delta.days + 1):
-                from_period = from_period if i == 0 else 0
+                from_period_on_day = from_period if i == 0 else TimePeriod.period_min
+                to_period_on_day = (
+                    to_period if i == delta.days else TimePeriod.period_max
+                )
                 day = start_date + timedelta(days=i)
-                person.mark_absent(day, from_period, absent, excused, remarks)
+
+                person.mark_absent(
+                    day,
+                    from_period_on_day,
+                    absent,
+                    excused,
+                    excuse_type,
+                    remarks,
+                    to_period_on_day,
+                )
 
             messages.success(request, _("The absence has been saved."))
-            return redirect("index")
+            return redirect("register_absence")
 
     context["register_absence_form"] = register_absence_form