diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationForm.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationForm.vue
index 3dc66363684c38a0ae02fbfc3a5a9992b8562e9c..13fcd9ddcdb8872b96330f7a9748a45bcd42e55e 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationForm.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationForm.vue
@@ -22,32 +22,46 @@
         </div>
       </v-row>
       <v-row>
-        <v-col cols="12" :sm="6" class="pl-0">
+        <v-col cols="12" :sm="startPeriods ? 4 : 6" class="pl-0">
           <div aria-required="true">
             <date-time-field
               :label="$t('forms.labels.start')"
-              :max-date="maxStartDate"
-              :max-time="maxStartTime"
-              :limit-selectable-range="false"
               :rules="$rules().required.build()"
-              :value="startDate"
+              :value="start.toISO()"
               @input="handleStartDate"
             />
           </div>
         </v-col>
-        <v-col cols="12" :sm="6" class="pr-0">
+        <v-col cols="12" :sm="2" v-if="startPeriods" align-self="end">
+          <v-select
+            :label="$t('lesrooster.slot.period')"
+            :items="startPeriods"
+            item-text="period"
+            :value="startSlot"
+            @input="handleStartSlot"
+            return-object
+          />
+        </v-col>
+        <v-col cols="12" :sm="endPeriods ? 4 : 6" class="pr-0">
           <div aria-required="true">
             <date-time-field
               :label="$t('forms.labels.end')"
-              :min-date="minEndDate"
-              :min-time="minEndTime"
-              :limit-selectable-range="false"
               :rules="$rules().required.build()"
-              :value="endDate"
+              :value="end.toISO()"
               @input="handleEndDate"
             />
           </div>
         </v-col>
+        <v-col cols="12" :sm="2" v-if="endPeriods" align-self="end">
+          <v-select
+            :label="$t('lesrooster.slot.period')"
+            :items="endPeriods"
+            item-text="period"
+            :value="endSlot"
+            @input="handleEndSlot"
+            return-object
+          />
+        </v-col>
       </v-row>
       <v-row>
         <v-text-field
@@ -76,7 +90,7 @@
 import AbsenceReasonGroupSelect from "aleksis.apps.kolego/components/AbsenceReasonGroupSelect.vue";
 import DateTimeField from "aleksis.core/components/generic/forms/DateTimeField.vue";
 import PersonField from "aleksis.core/components/generic/forms/PersonField.vue";
-import { gqlPersons } from "./absenceCreation.graphql";
+import { gqlPersons, periodsByDay } from "./absenceCreation.graphql";
 import formRulesMixin from "aleksis.core/mixins/formRulesMixin.js";
 import { DateTime } from "luxon";
 
@@ -96,10 +110,14 @@ export default {
     "comment",
     "absence-reason",
   ],
-  data() {
-    return {
-      gqlQuery: gqlPersons,
-    };
+  apollo: {
+    periodsByDay: {
+      query: periodsByDay,
+      result(_) {
+        this.handleStartDate(this.start.toISO());
+        this.handleEndDate(this.end.toISO());
+      },
+    },
   },
   props: {
     persons: {
@@ -127,60 +145,98 @@ export default {
       required: true,
     },
   },
+  data() {
+    return {
+      gqlQuery: gqlPersons,
+      startDT: DateTime.fromISO(this.startDate),
+      endDT: DateTime.fromISO(this.endDate),
+      startPeriods: false,
+      endPeriods: false,
+      startSlot: undefined,
+      endSlot: undefined,
+    };
+  },
   computed: {
-    maxStartTime() {
-      // Only if on the same day
-      const start = DateTime.fromISO(this.startDate);
-      const end = DateTime.fromISO(this.endDate);
-
-      if (start.day !== end.day) return;
-
-      return end.minus({ minutes: 5 }).toFormat("HH:mm");
-    },
-    minEndTime() {
-      // Only if on the same day
-      const start = DateTime.fromISO(this.startDate);
-      const end = DateTime.fromISO(this.endDate);
-
-      if (start.day !== end.day) return;
-
-      return start.plus({ minutes: 5 }).toFormat("HH:mm");
+    start: {
+      get() {
+        return this.startDT;
+      },
+      set(dt) {
+        this.startDT = dt;
+        if (dt >= this.end) {
+          this.end = dt.plus({ minutes: 5 });
+        }
+        this.$emit("start-date", dt.toISO());
+      },
     },
-    maxStartDate() {
-      const end = DateTime.fromISO(this.endDate);
-      return end.toISODate();
-    },
-    minEndDate() {
-      const start = DateTime.fromISO(this.startDate);
-      return start.toISODate();
+    end: {
+      get() {
+        return this.endDT;
+      },
+      set(dt) {
+        this.endDT = dt;
+        if (dt <= this.start) {
+          this.start = dt.minus({ minutes: 5 });
+        }
+        this.$emit("end-date", dt.toISO());
+      },
     },
   },
   methods: {
-    handleStartDate(startDate) {
-      const parsedStart = DateTime.fromISO(startDate);
-      const parsedEnd = DateTime.fromISO(this.endDate);
-      if (parsedStart >= parsedEnd) {
-        this.$emit(
-          "end-date",
-          parsedStart.plus({ minutes: 5 }).toISO({ suppressSeconds: true }),
+    getPeriodsForWeekday(weekday) {
+      // Adapt from python conventions
+      const pythonWeekday = weekday - 1;
+      let periodsForWeekday = this.periodsByDay.find(
+        (period) => period.weekday === pythonWeekday,
+      );
+      if (!periodsForWeekday) return false;
+      return periodsForWeekday.periods;
+    },
+    handleStartDate(date) {
+      this.start = DateTime.fromISO(date);
+
+      if (this.periodsByDay && this.periodsByDay.length > 0) {
+        // Select periods for day
+        this.startPeriods = this.getPeriodsForWeekday(this.start.weekday);
+        if (!this.startPeriods) return;
+        // Sync PeriodSelect
+        const startTime = this.start.toFormat("HH:mm:ss");
+        this.startSlot = this.startPeriods.find(
+          (period) => period.timeStart === startTime,
         );
       }
-      this.$emit("start-date", startDate);
-      this.$refs.form.resetValidation();
-      this.$refs.form.validate();
     },
-    handleEndDate(endDate) {
-      const parsedStart = DateTime.fromISO(this.startDate);
-      const parsedEnd = DateTime.fromISO(endDate);
-      if (parsedEnd <= parsedStart) {
-        this.$emit(
-          "start-date",
-          parsedEnd.minus({ minutes: 5 }).toISO({ suppressSeconds: true }),
+    handleEndDate(date) {
+      this.end = DateTime.fromISO(date);
+
+      if (this.periodsByDay && this.periodsByDay.length > 0) {
+        // Select periods for day
+        this.endPeriods = this.getPeriodsForWeekday(this.end.weekday);
+        if (!this.endPeriods) return;
+        // Sync PeriodSelect
+        const endTime = this.end.toFormat("HH:mm:ss");
+        this.endSlot = this.endPeriods.find(
+          (period) => period.endTime === endTime,
         );
       }
-      this.$emit("end-date", endDate);
-      this.$refs.form.resetValidation();
-      this.$refs.form.validate();
+    },
+    handleStartSlot(slot) {
+      // Sync TimeSelect
+      const startTime = DateTime.fromISO(slot.timeStart);
+      this.start = this.start.set({
+        hour: startTime.hour,
+        minute: startTime.minute,
+        second: startTime.second,
+      });
+    },
+    handleEndSlot(slot) {
+      // Sync TimeSelect
+      const endTime = DateTime.fromISO(slot.timeEnd);
+      this.end = this.end.set({
+        hour: endTime.hour,
+        minute: endTime.minute,
+        second: endTime.second,
+      });
     },
   },
 };
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceCreation.graphql b/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceCreation.graphql
index 9ca58dd7bc5d58b269210d316c47641a952cdcba..34a22cef6431fd15450e48b40d7ce1d94553fb29 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceCreation.graphql
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceCreation.graphql
@@ -7,6 +7,17 @@ query gqlPersons {
   }
 }
 
+query periodsByDay {
+  periodsByDay: periodsByDay {
+    weekday
+    periods {
+      period
+      timeStart
+      timeEnd
+    }
+  }
+}
+
 query lessonsForPersons($persons: [ID]!, $start: DateTime!, $end: DateTime!) {
   items: lessonsForPersons(persons: $persons, start: $start, end: $end) {
     id
diff --git a/aleksis/apps/alsijil/schema/__init__.py b/aleksis/apps/alsijil/schema/__init__.py
index f337be4f836c8f73383e952c88f79e229613e02a..1614cf0f3000c95915a1fdef92d114b443525e03 100644
--- a/aleksis/apps/alsijil/schema/__init__.py
+++ b/aleksis/apps/alsijil/schema/__init__.py
@@ -1,5 +1,7 @@
+from collections import defaultdict
 from datetime import datetime
 
+from django.apps import apps
 from django.db.models import BooleanField, ExpressionWrapper, Q
 
 import graphene
@@ -53,6 +55,17 @@ from .personal_note import (
 from .statistics import StatisticsByPersonType
 
 
+class PeriodType(graphene.ObjectType):
+    period = graphene.Int()
+    time_start = graphene.Time()
+    time_end = graphene.Time()
+
+
+class WeekdayType(graphene.ObjectType):
+    weekday = graphene.Int()
+    periods = graphene.List(PeriodType)
+
+
 class Query(graphene.ObjectType):
     documentations_by_course_id = FilterOrderList(
         DocumentationType, course_id=graphene.ID(required=True)
@@ -100,6 +113,8 @@ class Query(graphene.ObjectType):
         group=graphene.ID(required=True),
     )
 
+    periods_by_day = graphene.List(WeekdayType)
+
     def resolve_documentations_by_course_id(root, info, course_id, **kwargs):
         documentations = Documentation.objects.filter(
             pk__in=Documentation.objects.filter(course_id=course_id)
@@ -347,6 +362,35 @@ class Query(graphene.ObjectType):
             annotate_person_statistics_for_school_term(members, school_term, group=group), info
         )
 
+    @staticmethod
+    def resolve_periods_by_day(root, info):
+        if apps.is_installed("aleksis.apps.lesrooster"):
+            Slot = apps.get_model("lesrooster", "Slot")
+            ValidityRange = apps.get_model("lesrooster", "ValidityRange")
+            slots = (
+                Slot.objects.filter(
+                    time_grid__validity_range=ValidityRange.current, period__isnull=False
+                )
+                .order_by("weekday")
+                .values("weekday", "period", "time_start", "time_end")
+            )
+            # Key by weekday
+            by_weekday = defaultdict(list)
+            for slot in slots:
+                # return nested dicts: {weekday periods { period time_* }}
+                # sort periods by period
+                by_weekday[slot["weekday"]].append(slot)
+            # Nest and sort periods
+            periods = []
+            for weekday, slots in by_weekday.items():
+                periods.append(
+                    {"weekday": weekday, "periods": sorted(slots, key=lambda slot: slot["period"])}
+                )
+
+            return periods
+        else:
+            return []
+
 
 class Mutation(graphene.ObjectType):
     create_or_update_documentations = DocumentationBatchCreateOrUpdateMutation.Field()