diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
index 02349f01add8910e22f6cdfdfb16d99ad303ffb5..0fb5b638c873bd3f20b16ea62ab438693c9f6c8a 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/ManageStudentsDialog.vue
@@ -3,16 +3,22 @@ import AbsenceReasonButtons from "aleksis.apps.kolego/components/AbsenceReasonBu
 import AbsenceReasonChip from "aleksis.apps.kolego/components/AbsenceReasonChip.vue";
 import AbsenceReasonGroupSelect from "aleksis.apps.kolego/components/AbsenceReasonGroupSelect.vue";
 import DialogCloseButton from "aleksis.core/components/generic/buttons/DialogCloseButton.vue";
+import SecondaryActionButton from "aleksis.core/components/generic/buttons/SecondaryActionButton.vue";
 import MobileFullscreenDialog from "aleksis.core/components/generic/dialogs/MobileFullscreenDialog.vue";
 import updateParticipationMixin from "./updateParticipationMixin.js";
 import deepSearchMixin from "aleksis.core/mixins/deepSearchMixin.js";
 import LessonInformation from "../documentation/LessonInformation.vue";
+import {
+  extendParticipationStatuses,
+  updateParticipationStatuses,
+} from "./participationStatus.graphql";
 import SlideIterator from "aleksis.core/components/generic/SlideIterator.vue";
 import PersonalNotes from "../personal_notes/PersonalNotes.vue";
 import ExtraMarkChip from "../../extra_marks/ExtraMarkChip.vue";
 import TardinessChip from "./TardinessChip.vue";
 import TardinessField from "./TardinessField.vue";
 import ExtraMarkButtons from "../../extra_marks/ExtraMarkButtons.vue";
+import MessageBox from "aleksis.core/components/generic/MessageBox.vue";
 
 export default {
   name: "ManageStudentsDialog",
@@ -26,7 +32,9 @@ export default {
     AbsenceReasonButtons,
     PersonalNotes,
     LessonInformation,
+    MessageBox,
     MobileFullscreenDialog,
+    SecondaryActionButton,
     SlideIterator,
     TardinessField,
     DialogCloseButton,
@@ -39,6 +47,14 @@ export default {
       loadSelected: false,
       selected: [],
       isExpanded: false,
+      markAsAbsentDay: {
+        showAlert: false,
+        num: 0,
+        reason: "no reason",
+        name: "nobody",
+        participationIDs: [],
+        loading: false,
+      },
     };
   },
   props: {
@@ -69,6 +85,71 @@ export default {
       this.$set(this.selected, []);
       this.$refs.iterator.selected = [];
     },
+    activateFullDayDialog(items) {
+      const itemIds = items.map((item) => item.id);
+      const participations = this.documentation.participations.filter((part) =>
+        itemIds.includes(part.id),
+      );
+
+      if (this.markAsAbsentDay.num === 1) {
+        this.markAsAbsentDay.name = participations[0].person.firstName;
+      }
+
+      this.$set(this.markAsAbsentDay, "participationIDs", itemIds);
+
+      this.markAsAbsentDay.loading = false;
+      this.markAsAbsentDay.showAlert = true;
+    },
+    beforeSendToServer() {
+      this.markAsAbsentDay.showAlert = false;
+      this.markAsAbsentDay.participationIDs = [];
+    },
+    duringUpdateSendToServer(
+      _participations,
+      _field,
+      _value,
+      incomingStatuses,
+    ) {
+      this.markAsAbsentDay.reason = incomingStatuses[0].absenceReason?.name;
+      this.markAsAbsentDay.num = incomingStatuses.length;
+    },
+    afterSendToServer(_participations, field, value) {
+      if (field === "absenceReason" && value !== "present") {
+        this.$once("save", this.activateFullDayDialog);
+      }
+    },
+    markAsAbsentDayClick() {
+      this.markAsAbsentDay.loading = true;
+
+      this.mutate(
+        extendParticipationStatuses,
+        {
+          input: this.markAsAbsentDay.participationIDs,
+        },
+        (storedDocumentations, incomingStatuses) => {
+          const documentation = storedDocumentations.find(
+            (doc) => doc.id === this.documentation.id,
+          );
+
+          incomingStatuses.forEach((newStatus) => {
+            const participationStatus = documentation.participations.find(
+              (part) => part.id === newStatus.id,
+            );
+            participationStatus.baseAbsence = newStatus.baseAbsence;
+            participationStatus.isOptimistic = newStatus.isOptimistic;
+          });
+
+          this.markAsAbsentDay.reason = "no reason";
+          this.markAsAbsentDay.num = 0;
+          this.markAsAbsentDay.participationIDs = [];
+          this.markAsAbsentDay.loading = false;
+
+          this.markAsAbsentDay.showAlert = false;
+
+          return storedDocumentations;
+        },
+      );
+    },
   },
 };
 </script>
@@ -106,6 +187,40 @@ export default {
           class="pt-4 full-width"
         />
       </v-scroll-x-transition>
+      <message-box
+        v-model="markAsAbsentDay.showAlert"
+        color="success"
+        icon="$success"
+        transition="slide-y-transition"
+        dismissible
+        class="mt-4 mb-0 full-width"
+      >
+        <div class="text-subtitle-2">
+          {{
+            $tc(
+              "alsijil.coursebook.mark_as_absent_day.title",
+              markAsAbsentDay.num,
+              markAsAbsentDay,
+            )
+          }}
+        </div>
+        <p class="text-body-2 pa-0 ma-0" style="word-break: break-word">
+          {{
+            $t(
+              "alsijil.coursebook.mark_as_absent_day.description",
+              markAsAbsentDay,
+            )
+          }}
+        </p>
+
+        <secondary-action-button
+          color="success"
+          i18n-key="alsijil.coursebook.mark_as_absent_day.action_button"
+          class="mt-2"
+          :loading="markAsAbsentDay.loading"
+          @click="markAsAbsentDayClick"
+        />
+      </message-box>
     </template>
     <template #content>
       <slide-iterator
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/participationStatus.graphql b/aleksis/apps/alsijil/frontend/components/coursebook/absences/participationStatus.graphql
index ce296d2b684c1f45928e1d94e8e584f7b845bb69..39eb59528c4f876eb2c75c20f187e5ded6fae2bc 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/participationStatus.graphql
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/participationStatus.graphql
@@ -64,3 +64,14 @@ mutation touchDocumentation($documentationId: ID!) {
     }
   }
 }
+
+mutation extendParticipationStatuses($input: [ID]!) {
+  extendParticipationStatuses(input: $input) {
+    items: participations {
+      id
+    }
+    absences {
+      id
+    }
+  }
+}
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/sendToServerMixin.js b/aleksis/apps/alsijil/frontend/components/coursebook/absences/sendToServerMixin.js
index 55cae9e6e8d69b0f4e5d299e9869228ccf9c2702..e269bddee80dbe9056e399d63581212ebfdd36c4 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/sendToServerMixin.js
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/sendToServerMixin.js
@@ -28,6 +28,8 @@ export default {
         return;
       }
 
+      this.beforeSendToServer(participations, field, value);
+
       this.mutate(
         updateParticipationStatuses,
         {
@@ -51,9 +53,18 @@ export default {
             participationStatus.isOptimistic = newStatus.isOptimistic;
           });
 
+          this.duringUpdateSendToServer(
+            participations,
+            field,
+            value,
+            incomingStatuses,
+          );
+
           return storedDocumentations;
         },
       );
+
+      this.afterSendToServer(participations, field, value);
     },
     addExtraMarks(participations, extraMarkId) {
       // Get all participation statuses without this extra mark and get the respective person ids
@@ -91,5 +102,14 @@ export default {
         },
       );
     },
+    beforeSendToServer(_participations, _field, _value) {
+      // Noop hook
+    },
+    duringUpdateSendToServer(_participations, _field, _value, _incoming) {
+      // Noop hook
+    },
+    afterSendToServer(_participations, _field, _value) {
+      // Noop hook
+    },
   },
 };
diff --git a/aleksis/apps/alsijil/frontend/messages/en.json b/aleksis/apps/alsijil/frontend/messages/en.json
index d1a039d4caa7b94b15fdeb36a396b6ec745eef70..0d39f282a34715bfc115554003999f943b9ca547 100644
--- a/aleksis/apps/alsijil/frontend/messages/en.json
+++ b/aleksis/apps/alsijil/frontend/messages/en.json
@@ -111,6 +111,11 @@
         "lessons": "No lessons | 1 lesson | {count} lessons",
         "success": "The absences were registered successfully.",
         "warning": "The following lessons are in the selected time period. Please check that you want to register the absences for these lessons before confirming."
+      },
+      "mark_as_absent_day": {
+        "title": "Error: no person | Successfully marked {name} as {reason} | Successfully marked {n} people as {reason}",
+        "description": "Do you want to mark them as {reason} for the rest of their day?",
+        "action_button": "Extend absence"
       }
     },
     "personal_notes": {
diff --git a/aleksis/apps/alsijil/schema/__init__.py b/aleksis/apps/alsijil/schema/__init__.py
index ab87c4306cd144d4c5f27c00914aceeb865584a7..97ec4f187e036a246772b709c75942018fb1d4d9 100644
--- a/aleksis/apps/alsijil/schema/__init__.py
+++ b/aleksis/apps/alsijil/schema/__init__.py
@@ -32,7 +32,10 @@ from .extra_marks import (
     ExtraMarkBatchPatchMutation,
     ExtraMarkType,
 )
-from .participation_status import ParticipationStatusBatchPatchMutation
+from .participation_status import (
+    ExtendParticipationStatusToAbsenceBatchMutation,
+    ParticipationStatusBatchPatchMutation,
+)
 from .personal_note import (
     PersonalNoteBatchCreateMutation,
     PersonalNoteBatchDeleteMutation,
@@ -233,6 +236,7 @@ class Mutation(graphene.ObjectType):
     touch_documentation = TouchDocumentationMutation.Field()
     update_participation_statuses = ParticipationStatusBatchPatchMutation.Field()
     create_absences_for_persons = AbsencesForPersonsCreateMutation.Field()
+    extend_participation_statuses = ExtendParticipationStatusToAbsenceBatchMutation.Field()
 
     create_extra_marks = ExtraMarkBatchCreateMutation.Field()
     update_extra_marks = ExtraMarkBatchPatchMutation.Field()
diff --git a/aleksis/apps/alsijil/schema/participation_status.py b/aleksis/apps/alsijil/schema/participation_status.py
index 951ab4419341641cc26059a18f04f91890749f1c..2b9ebb25f37fabcc58415da613980d171114996d 100644
--- a/aleksis/apps/alsijil/schema/participation_status.py
+++ b/aleksis/apps/alsijil/schema/participation_status.py
@@ -1,10 +1,16 @@
+import datetime
+
 from django.core.exceptions import PermissionDenied
+from django.utils.translation import gettext_lazy as _
 
 import graphene
 from graphene_django import DjangoObjectType
+from reversion import create_revision, set_comment, set_user
 
 from aleksis.apps.alsijil.models import NewPersonalNote, ParticipationStatus
 from aleksis.apps.alsijil.schema.personal_note import PersonalNoteType
+from aleksis.apps.kolego.models import Absence
+from aleksis.apps.kolego.schema.absence import AbsenceType
 from aleksis.core.schema.base import (
     BaseBatchPatchMutation,
     DjangoFilterMixin,
@@ -70,3 +76,77 @@ class ParticipationStatusBatchPatchMutation(BaseBatchPatchMutation):
             "alsijil.edit_participation_status_for_documentation_rule", obj.related_documentation
         ):
             raise PermissionDenied()
+
+
+class ExtendParticipationStatusToAbsenceBatchMutation(graphene.Mutation):
+    class Arguments:
+        input = graphene.List(graphene.ID, description=_("List of ParticipationStatus IDs"))
+
+    participations = graphene.List(ParticipationStatusType)
+    absences = graphene.List(AbsenceType)
+
+    @classmethod
+    def create_absence(cls, info, participation_id):
+        participation = ParticipationStatus.objects.get(pk=participation_id)
+
+        if participation.date_end:
+            end_date = participation.date_end
+        else:
+            end_date = ParticipationStatus.value_end_datetime(participation).date()
+
+        end_datetime = datetime.datetime.combine(
+            end_date, datetime.time.max, participation.timezone
+        )
+
+        if participation.base_absence:
+            # Update the base absence to increase length if needed
+            absence = participation.base_absence
+
+            if absence.date_end:
+                if absence.date_end < end_date:
+                    absence.date_end = end_date
+                    absence.save()
+
+                return participation, absence
+
+            # Absence uses a datetime
+            if absence.datetime_end.astimezone(absence.timezone) < end_datetime:
+                # The end date ends after the previous absence end
+                absence.datetime_end = end_datetime
+                absence.save()
+
+            return participation, absence
+
+        else:
+            # No base absence, simply create one
+            data = dict(
+                reason_id=participation.absence_reason.id,
+                person=participation.person,
+            )
+
+            if participation.date_start:
+                data["date_start"] = participation.date_start
+                data["date_end"] = end_date
+            else:
+                data["datetime_start"] = ParticipationStatus.value_start_datetime(participation)
+                data["datetime_end"] = end_datetime
+
+            absence, __ = Absence.objects.get_or_create(**data)
+
+            participation.base_absence = absence
+            participation.save()
+
+            return participation, absence
+
+    @classmethod
+    def mutate(cls, root, info, input):  # noqa
+        with create_revision():
+            set_user(info.context.user)
+            set_comment(_("Extended absence reason from coursebook."))
+            participations, absences = zip(
+                *[cls.create_absence(info, participation_id) for participation_id in input]
+            )
+
+        return ExtendParticipationStatusToAbsenceBatchMutation(
+            participations=participations, absences=absences
+        )