diff --git a/app/controllers/admin/courseplanning.php b/app/controllers/admin/courseplanning.php
index 2271acfdbac096aafd6fd642d9b129f705365532..9e508a57d4f1f23749814c1146a951dfa35e96cc 100644
--- a/app/controllers/admin/courseplanning.php
+++ b/app/controllers/admin/courseplanning.php
@@ -345,12 +345,11 @@ class Admin_CourseplanningController extends AuthenticatedController
             $end_date->setTimezone(new DateTimeZone('UTC'));
 
             $course = Course::find($course_id);
-            $this->seminar = new Seminar($course);
-            if ($course->isOpenEnded() || count($course->semesters) > 1) { // course over more than one semester
-                $start_weeks = $this->seminar->end_semester->getStartWeeks();
 
-                $sem_duration = $this->semester->ende - $this->semester->beginn;
-                $sem_weeks        = $this->semester->getStartWeeks($sem_duration);
+            if (count($course->semesters) > 1) { // course over more than one semester
+                $start_weeks = $course->start_semester->getStartWeeks($course->end_semester);
+
+                $sem_weeks        = $this->semester->getStartWeeks();
                 $sem_weeks_start = explode(' Semesterwoche ', $sem_weeks[0]);
                 $sem_weeks_end = explode(' Semesterwoche ', end($sem_weeks));
 
diff --git a/app/controllers/admin/user.php b/app/controllers/admin/user.php
index c8683040723f1a94ad47b8086219272bd4461035..331722624ba7fd3a99192307ca187ec5f3d4f883 100644
--- a/app/controllers/admin/user.php
+++ b/app/controllers/admin/user.php
@@ -1239,7 +1239,9 @@ class Admin_UserController extends AuthenticatedController
         $memberships = DBManager::get()->fetchAll("SELECT seminar_user.*, seminare.Name as course_name
                              FROM seminar_user
                              LEFT JOIN seminare USING (seminar_id)
-                             WHERE user_id = ? ORDER BY seminare.start_time DESC, seminare.Name",
+                             LEFT JOIN semester_courses ON (seminare.Seminar_id = semester_courses.course_id)
+                             LEFT JOIN semester_data ON (semester_data.semester_id = semester_courses.semester_id)
+                             WHERE user_id = ? GROUP BY seminare.Seminar_id ORDER BY MAX(semester_data.beginn) DESC, seminare.Name",
             [$user_id],
             'CourseMember::buildExisting');
 
@@ -1249,6 +1251,7 @@ class Admin_UserController extends AuthenticatedController
         $this->sections = [];
 
         foreach ($memberships as $membership) {
+            $semester_name = $membership->course->isOpenEnded() ? _('unbegrenzt') : $membership->course->start_semester->name;
             if (!Request::get('view') || Request::get('view') === 'files') {
                 // count files for course
 
@@ -1259,9 +1262,9 @@ class Admin_UserController extends AuthenticatedController
 
                 if ($count) {
                     if (!isset($course_files[$membership->seminar_id])) {
-                        $course_files[(string) $membership->course->start_semester->name][$membership->course->id]['course'] = $membership->course;
+                        $course_files[$semester_name][$membership->course->id]['course'] = $membership->course;
                     }
-                    $course_files[(string) $membership->course->start_semester->name][$membership->course->id]['files'] = $count;
+                    $course_files[$semester_name][$membership->course->id]['files'] = $count;
                 }
             }
             if (in_array(Request::get('view'), words('courses closed_courses'))) {
@@ -1272,9 +1275,9 @@ class Admin_UserController extends AuthenticatedController
                   WHERE sc.seminar_id =?', [$membership->seminar_id]);
 
                 if ((int)$closed_course) {
-                    $closed_courses[(string) $membership->course->start_semester->name][$membership->course->id] = $membership;
+                    $closed_courses[$semester_name][$membership->course->id] = $membership;
                 } else {
-                    $courses[(string) $membership->course->start_semester->name][$membership->course->id] = $membership;
+                    $courses[$semester_name][$membership->course->id] = $membership;
                 }
             }
         }
diff --git a/app/controllers/admission/restricted_courses.php b/app/controllers/admission/restricted_courses.php
index ccf89aaaa7d444b862addaf0806024e61e30b2c8..5ae3a38add7fe9409ce87192b718d2e6728c8d88 100644
--- a/app/controllers/admission/restricted_courses.php
+++ b/app/controllers/admission/restricted_courses.php
@@ -56,7 +56,6 @@ class Admission_RestrictedCoursesController extends AuthenticatedController
         }
         $semester = Semester::find($this->current_semester_id);
         $sem_condition .= "
-            AND seminare.start_time <=" . (int)$semester["beginn"]."
             AND (semester_courses.semester_id IS NULL OR semester_courses.semester_id = " . DBManager::get()->quote($semester->getId()) . ")
         ";
         if ($this->sem_name_prefix) {
diff --git a/app/controllers/blubber.php b/app/controllers/blubber.php
index 7f45ea8894d46a43adfbcb0f49eb9c1163627c44..35a8d7e573d2dd3d8467d6642b47bb009649cb80 100644
--- a/app/controllers/blubber.php
+++ b/app/controllers/blubber.php
@@ -406,7 +406,6 @@ class BlubberController extends AuthenticatedController
             $course = new Course();
             $course['name'] = Request::get('name');
             $course['status'] = array_shift($studgroup_sem_types);
-            $course['start_time'] = Semester::findCurrent()->beginn;
             $course->store();
 
             if ($_FILES['avatar'] && $_FILES['avatar']['error'] !== UPLOAD_ERR_NO_FILE) {
diff --git a/app/controllers/course/timesrooms.php b/app/controllers/course/timesrooms.php
index 7cad46c32fd59b633422ae8f79f0f5e1b4bcdc38..9e835ca64bc06c81813177284d20901b1ac96e48 100644
--- a/app/controllers/course/timesrooms.php
+++ b/app/controllers/course/timesrooms.php
@@ -74,10 +74,11 @@ class Course_TimesroomsController extends AuthenticatedController
             $this->course->applyTimeFilter($semester['beginn'], $semester['ende']);
         }
 
-        $selectable_semesters = new SimpleCollection(Semester::getAll());
-        $start                = $this->course->start_time;
-        $end                  = $this->course->getEndSemester()->ende;
-        $selectable_semesters = $selectable_semesters->findBy('beginn', [$start, $end], '>=<=')->toArray();
+        if ($this->course->isOpenEnded()) {
+            $selectable_semesters = Semester::getAll();
+        } else {
+            $selectable_semesters = $this->course->semesters->toArray();
+        }
         if (count($selectable_semesters) > 1 || (count($selectable_semesters) == 1 && $this->course->hasDatesOutOfDuration())) {
             $selectable_semesters[] = ['name' => _('Alle Semester'), 'semester_id' => 'all'];
         }
@@ -247,11 +248,12 @@ class Course_TimesroomsController extends AuthenticatedController
             if ($end_semester != 0 && $end_semester != -1 && $start_semester->beginn >= $end_semester->beginn) {
                 PageLayout::postError(_('Das Startsemester liegt nach dem Endsemester!'));
             } else {
+                $old_start_weeks = !$course->isOpenEnded() ? $course->start_semester->getStartWeeks($course->end_semester) : [];
                 //set the new semester array:
                 if ($end_semester == -1) {
-                    $course->setSemesters([]);
+                    $course->semesters = [];
                 } elseif($end_semester == 0)  {
-                    $course->setSemesters([$start_semester]);
+                    $course->semesters = [$start_semester];
                 } else {
                     $selected_semesters = [];
                     foreach (Semester::getAll() as $sem) {
@@ -259,29 +261,23 @@ class Course_TimesroomsController extends AuthenticatedController
                             $selected_semesters[] = $sem;
                         }
                     }
-                    $course->setSemesters($selected_semesters);
+                    $course->semesters = $selected_semesters;
                 }
 
-                //deprecated: this is the old way
-                $course['start_time'] = $start_semester['beginn'];
-                $course['duration_time'] = $end_semester <= 0
-                    ? $end_semester
-                    : $end_semester['ende'] - $start_semester['beginn'];
-
-                $old_start_weeks = $course->end_semester ? $course->end_semester->getStartWeeks() : [];
                 // set the semester-chooser to the first semester
                 $this->course->setFilter($course->getStartSemester());
                 $this->semester_filter = $start_semester->semester_id;
 
                 $course->store();
-
-                $new_start_weeks = $course->start_semester->getStartWeeks();
-                SeminarCycleDate::removeOutRangedSingleDates($this->course->getStartSemester(), $this->course->getEndSemesterVorlesEnde(), $course->id);
-                $cycles = SeminarCycleDate::findBySeminar_id($course->id);
-                foreach ($cycles as $cycle) {
-                    $cycle->end_offset = $this->getNewEndOffset($cycle, $old_start_weeks, $new_start_weeks);
-                    $cycle->generateNewDates();
-                    $cycle->store();
+                if (!$course->isOpenEnded()) {
+                    $new_start_weeks = $course->start_semester->getStartWeeks($course->end_semester);
+                    SeminarCycleDate::removeOutRangedSingleDates($this->course->getStartSemester(), $this->course->getEndSemesterVorlesEnde(), $course->id);
+                    $cycles = SeminarCycleDate::findBySeminar_id($course->id);
+                    foreach ($cycles as $cycle) {
+                        $cycle->end_offset = $this->getNewEndOffset($cycle, $old_start_weeks, $new_start_weeks);
+                        $cycle->generateNewDates();
+                        $cycle->store();
+                    }
                 }
 
                 $messages = $this->course->getStackedMessages();
@@ -1050,20 +1046,18 @@ class Course_TimesroomsController extends AuthenticatedController
         }
 
         if ($this->course->isOpenEnded()) { // course with endless lifespan
-            $end_semester = Semester::findBySQL("beginn >= ? ORDER BY beginn", [$this->course->start_time]);
-        } else { // course over more than one semester
-            $end_semester = $this->course->semesters;
+            $end_semester = array_values(array_filter(Semester::getAll(), function ($s) {return $s->past === false;}));
+        } else { // course over one or more semester
+            $end_semester = $this->course->semesters->getArrayCopy();
         }
-
-        $this->start_weeks = $end_semester[count($end_semester) - 1]->getStartWeeks();
-
+        $this->start_weeks = [];
+        $this->end_semester_weeks = [];
         if (!empty($end_semester)) {
-            $this->end_semester_weeks = [];
+            $this->start_weeks = $end_semester[0]->getStartWeeks($end_semester[count($end_semester) - 1]);
 
             foreach ($end_semester as $sem) {
 
-                $sem_duration = $sem->ende - $sem->beginn;
-                $weeks        = $sem->getStartWeeks($sem_duration);
+                $weeks = $sem->getStartWeeks();
 
                 foreach ($this->start_weeks as $key => $week) {
                     if (mb_strpos($week, mb_substr($weeks[0], -15)) !== false) {
diff --git a/app/controllers/course/topics.php b/app/controllers/course/topics.php
index 3636c12c3b44bccc554eef7c3e70e2e61681e92a..96a238ab4a4a03f435b0d8e68f9bb56eaa2e4313 100644
--- a/app/controllers/course/topics.php
+++ b/app/controllers/course/topics.php
@@ -156,9 +156,10 @@ class Course_TopicsController extends AuthenticatedController
             PageLayout::postMessage(MessageBox::success(sprintf(_("%s Themen kopiert."), count(Request::getArray("topic")))));
             $this->redirect("course/topics");
         }
+        $semester_sql = " CONCAT('(',IFNULL(GROUP_CONCAT(DISTINCT semester_data.name ORDER BY semester_data.beginn SEPARATOR '-'),'" . _('unbegrenzt') . "'),')')";
         if ($GLOBALS['perm']->have_perm("root")) {
             $this->courseSearch = new SQLSearch("
-                SELECT seminare.Seminar_id, CONCAT_WS(' ', seminare.VeranstaltungsNummer, seminare.name, '(', IF(semester_courses.semester_id IS NULL, GROUP_CONCAT(', ', semester_data.name), 'unbegrenzt'), ') (', COUNT(issue_id), ')')
+                SELECT seminare.Seminar_id, CONCAT_WS(' ', seminare.VeranstaltungsNummer, seminare.name, $semester_sql, '(', COUNT(issue_id), ')')
                 FROM seminare
                 LEFT JOIN semester_courses ON (seminare.Seminar_id = semester_courses.course_id)
                 LEFT JOIN semester_data ON (semester_data.semester_id = semester_courses.semester_id)
@@ -172,7 +173,7 @@ class Course_TopicsController extends AuthenticatedController
             );
         } elseif ($GLOBALS['perm']->have_perm("admin")) {
             $this->courseSearch = new SQLSearch("
-                SELECT seminare.Seminar_id, CONCAT_WS(' ', seminare.VeranstaltungsNummer, seminare.name, '(', CONCAT_WS(' ', seminare.VeranstaltungsNummer, seminare.name, '(', IF(semester_courses.semester_id IS NULL, GROUP_CONCAT(', ', semester_data.name), 'unbegrenzt'), ') (', COUNT(issue_id), ')')
+                SELECT seminare.Seminar_id, CONCAT_WS(' ', seminare.VeranstaltungsNummer, seminare.name, $semester_sql, '(', COUNT(issue_id), ')')
                 FROM seminare
                     INNER JOIN seminar_inst ON (seminare.Seminar_id = seminar_inst.seminar_id)
                     INNER JOIN user_inst ON (user_inst.Institut_id = seminar_inst.institut_id)
@@ -191,7 +192,7 @@ class Course_TopicsController extends AuthenticatedController
             );
         } else {
             $this->courseSearch = new SQLSearch("
-                SELECT seminare.Seminar_id, CONCAT_WS(' ', seminare.VeranstaltungsNummer, seminare.name, '(', IF(semester_courses.semester_id IS NULL, GROUP_CONCAT(', ', semester_data.name), 'unbegrenzt'), ') (', COUNT(issue_id), ')')
+                SELECT seminare.Seminar_id, CONCAT_WS(' ', seminare.VeranstaltungsNummer, seminare.name, $semester_sql, '(', COUNT(issue_id), ')')
                 FROM seminare
                     INNER JOIN seminar_user ON (seminare.Seminar_id = seminar_user.Seminar_id)
                     LEFT JOIN semester_courses ON (seminare.Seminar_id = semester_courses.course_id)
diff --git a/app/controllers/file.php b/app/controllers/file.php
index 47945f312875c42395b9cc3a795b7543f3a87fae..051f05d8195e6990d30e388a3a4b1c9626ecb9d2 100644
--- a/app/controllers/file.php
+++ b/app/controllers/file.php
@@ -739,23 +739,25 @@ class FileController extends AuthenticatedController
 
         $this->plugin = Request::get('from_plugin');
         if (!$GLOBALS['perm']->have_perm("admin")) {
-            $query = "SELECT seminare.*, COUNT(semester_courses.semester_id) AS semesters
+            $query = "SELECT seminare.*, MAX(`beginn`) as sorter
                       FROM seminare
                       INNER JOIN seminar_user ON (seminar_user.Seminar_id = seminare.Seminar_id)
                       LEFT JOIN semester_courses ON (semester_courses.course_id = seminare.Seminar_id)
+                      LEFT JOIN semester_data ON (semester_courses.semester_id = semester_data.semester_id)
                       WHERE seminar_user.user_id = :user_id
                       GROUP BY seminare.Seminar_id
                       ";
             if (Config::get()->DEPUTIES_ENABLE) {
                 $query .= " UNION
-                    SELECT `seminare`.*, COUNT(semester_courses.semester_id) AS semesters
+                    SELECT `seminare`.*, MAX(`beginn`) as sorter
                     FROM `seminare`
                     INNER JOIN `deputies` ON (`deputies`.`range_id` = `seminare`.`Seminar_id`)
                     LEFT JOIN semester_courses ON (semester_courses.course_id = seminare.Seminar_id)
+                    LEFT JOIN semester_data ON (semester_courses.semester_id = semester_data.semester_id)
                     WHERE `deputies`.`user_id` = :user_id
                     GROUP BY seminare.Seminar_id";
             }
-            $query .= " ORDER BY semesters = 0 DESC, start_time DESC, Name ASC";
+            $query .= " ORDER BY sorter DESC, Name ASC";
             $statement = DBManager::get()->prepare($query);
             $statement->execute([':user_id' => $GLOBALS['user']->id]);
             $this->courses = [];
@@ -1255,22 +1257,24 @@ class FileController extends AuthenticatedController
         $this->folder_id = $folder_id;
         $this->plugin = Request::get('to_plugin');
         if (!$GLOBALS['perm']->have_perm('admin')) {
-            $query = "SELECT seminare.*, COUNT(semester_courses.semester_id) AS semesters
+            $query = "SELECT seminare.*, MAX(semester_data.`beginn`) as sorter
                       FROM seminare
                       INNER JOIN seminar_user ON (seminar_user.Seminar_id = seminare.Seminar_id)
                       LEFT JOIN semester_courses ON (semester_courses.course_id = seminare.Seminar_id)
+                      LEFT JOIN semester_data ON (semester_courses.semester_id = semester_data.semester_id)
                       WHERE seminar_user.user_id = :user_id
                       GROUP BY seminare.Seminar_id";
             if (Config::get()->DEPUTIES_ENABLE) {
                 $query .= " UNION
-                    SELECT `seminare`.*, COUNT(semester_courses.semester_id) AS semesters
+                    SELECT `seminare`.*, MAX(semester_data.`beginn`) as sorter
                     FROM `seminare`
                     INNER JOIN `deputies` ON (`deputies`.`range_id` = `seminare`.`Seminar_id`)
                     LEFT JOIN semester_courses ON (semester_courses.course_id = seminare.Seminar_id)
+                    LEFT JOIN semester_data ON (semester_courses.semester_id = semester_data.semester_id)
                     WHERE `deputies`.`user_id` = :user_id
                     GROUP BY seminare.Seminar_id";
             }
-            $query .= " ORDER BY semesters = 0 DESC, start_time DESC, Name ASC";
+            $query .= " ORDER BY sorter DESC, Name ASC";
             $statement = DBManager::get()->prepare($query);
             $statement->execute(['user_id' => $GLOBALS['user']->id]);
 
diff --git a/app/controllers/news.php b/app/controllers/news.php
index e60e174f634fa99c5b76e61c01bee80bdf730e55..81e832edb243ed0c3d69affac57e8db5f5a3de60 100644
--- a/app/controllers/news.php
+++ b/app/controllers/news.php
@@ -709,7 +709,6 @@ class NewsController extends StudipController
                           LEFT JOIN semester_courses ON (semester_courses.course_id = seminar_user.Seminar_id)
                       WHERE seminar_user.user_id = :user_id
                           AND seminar_user.status IN('tutor', 'dozent')
-                          AND seminare.start_time <= :start
                           AND (semester_courses.semester_id = :semester_id OR semester_courses.semester_id IS NULL)
                           ";
             if (Config::get()->DEPUTIES_ENABLE) {
@@ -719,13 +718,11 @@ class NewsController extends StudipController
                                 LEFT JOIN seminare ON (deputies.range_id=seminare.Seminar_id)
                                 LEFT JOIN semester_courses ON (semester_courses.course_id = deputies.range_id)
                             WHERE deputies.user_id = :user_id
-                            AND seminare.start_time <= :start
                             AND (semester_courses.semester_id = :semester_id OR semester_courses.semester_id IS NULL)";
             }
             $query .= " ORDER BY sem_name ASC";
             $statement = DBManager::get()->prepare($query);
             $statement->bindValue(':user_id', $GLOBALS['user']->id);
-            $statement->bindValue(':start', $current_semester->beginn);
             $statement->bindValue(':semester_id', $current_semester->semester_id);
             $statement->execute();
             $seminars = $statement->fetchAll(PDO::FETCH_ASSOC);
@@ -744,7 +741,6 @@ class NewsController extends StudipController
                           LEFT JOIN semester_courses ON (semester_courses.course_id = seminar_user.Seminar_id)
                       WHERE seminar_user.user_id = :user_id
                           AND seminar_user.status IN('tutor', 'dozent')
-                          AND seminare.start_time <= :start
                           AND (semester_courses.semester_id = :semester_id OR semester_courses.semester_id IS NULL)";
             if (Config::get()->DEPUTIES_ENABLE) {
                 $query .= " UNION SELECT CONCAT(seminare.Name, ' ["._("Vertretung")."]') AS sem_name, seminare.Seminar_id,
@@ -753,13 +749,11 @@ class NewsController extends StudipController
                                 LEFT JOIN seminare ON (deputies.range_id=seminare.Seminar_id)
                                 LEFT JOIN semester_courses ON (semester_courses.course_id = deputies.range_id)
                             WHERE deputies.user_id = :user_id
-                                AND seminare.start_time <= :start
                                 AND (semester_courses.semester_id = :semester_id OR semester_courses.semester_id IS NULL)";
             }
             $query .= " ORDER BY sem_name ASC";
             $statement = DBManager::get()->prepare($query);
             $statement->bindValue(':user_id', $GLOBALS['user']->id);
-            $statement->bindValue(':start', $next_semester->beginn);
             $statement->bindValue(':semester_id', $next_semester->semester_id);
             $statement->execute();
             $seminars = $statement->fetchAll(PDO::FETCH_ASSOC);
diff --git a/app/controllers/questionnaire.php b/app/controllers/questionnaire.php
index 895dd16743eb5c5e635cc82ba1e11212874776a6..bab22ab91405eac201617cd07f8e13c3b82a9df5 100644
--- a/app/controllers/questionnaire.php
+++ b/app/controllers/questionnaire.php
@@ -710,9 +710,9 @@ class QuestionnaireController extends AuthenticatedController
 
                 //Search courses matching the search criteria:
 
-                $sql = 'start_time = :semester_begin ';
+                $sql = 'LEFT JOIN semester_courses ON (semester_courses.course_id = seminare.Seminar_id) WHERE (semester_courses.semester_id = :semester_id OR semester_courses.semester_id IS NULL) ';
                 $sql_array = [
-                    'semester_begin' => $this->semester->beginn
+                    'semester_id' => $this->semester->id
                 ];
 
                 if ($this->institute) {
diff --git a/app/controllers/shared/modul.php b/app/controllers/shared/modul.php
index cd2e96be954f8272e29f580db4ec478eb01389bd..55644db11b2fb7cc27f5227661423a51e8e62c4b 100644
--- a/app/controllers/shared/modul.php
+++ b/app/controllers/shared/modul.php
@@ -156,13 +156,13 @@ class Shared_ModulController extends AuthenticatedController
             $stm = DBManager::get()->prepare('SELECT DISTINCT auth_user_md5.username FROM auth_user_md5
                 JOIN seminar_user ON (auth_user_md5.user_id = seminar_user.user_id)
                 JOIN seminare ON (seminare.seminar_id = seminar_user.seminar_id)
-                JOIN semester_data ON (seminare.start_time = semester_data.beginn)
+                LEFT JOIN semester_courses ON (seminare.seminar_id = semester_courses.course_id)
                 JOIN mvv_lvgruppe_seminar ON (mvv_lvgruppe_seminar.seminar_id = seminare.seminar_id)
                 JOIN mvv_lvgruppe_modulteil ON (mvv_lvgruppe_modulteil.lvgruppe_id = mvv_lvgruppe_seminar.lvgruppe_id)
                 JOIN mvv_modulteil ON (mvv_modulteil.modulteil_id = mvv_lvgruppe_modulteil.modulteil_id)
                 WHERE mvv_modulteil.modul_id = :modul_id
                 AND seminar_user.status = :status
-                AND semester_data.semester_id = :semester_id');
+                AND (semester_courses.semester_id = :semester_id OR semester_courses.semester_id IS NULL)');
             $stm->execute(['modul_id' => $modul_id, 'status' => 'autor', ':semester_id' => $semester_id]);
             $_SESSION['sms_data']['p_rec'] = $stm->fetchFirst();
 
diff --git a/app/routes/Course.php b/app/routes/Course.php
index cffdb0b3c9df88a6c18895c41db9933364822719..bb2f32ff3e06dc0178366c6a6ea529b74152fdcb 100644
--- a/app/routes/Course.php
+++ b/app/routes/Course.php
@@ -136,12 +136,8 @@ class Course extends \RESTAPI\RouteMap
         if ($semester) {
 
             $memberships = $memberships->filter(function ($m) use ($semester) {
-                    $course = $m->course;
-                    return
-                        $course->start_time == $semester->beginn
-                        || ($course->start_time <= $semester->beginn
-                            && ($course->isOpenEnded() || $semester->beginn <= $course->end_time));
-                });
+                return $m->course->isInSemester($semester);
+            });
         }
 
         return $memberships;
diff --git a/app/views/file/choose_file_from_course.php b/app/views/file/choose_file_from_course.php
index a0184975114a882c3ed8d6779b8031387c9d595c..ad2ba266ef5115527bb3e1ade7aa7ab76db39b80 100644
--- a/app/views/file/choose_file_from_course.php
+++ b/app/views/file/choose_file_from_course.php
@@ -44,7 +44,7 @@ if (Request::get('range_type')) {
                     </a>
                 </td>
                 <td>
-                    <?= htmlReady($course->start_semester->name) ?>
+                    <?= htmlReady($course->getTextualSemester()) ?>
                 </td>
                 <td class="actions">
                     <a href="<?= $controller->link_for('file/choose_file_from_course/' . $folder_id, array_merge($options, ['course_id' => $course->id])) ?>" data-dialog>
diff --git a/app/views/file/choose_folder_from_course.php b/app/views/file/choose_folder_from_course.php
index 375c2c4c514804e1a541d44ba701ae3bfbb96d21..3496e5b922c782642cc5da6cb0e5658d39e499fd 100644
--- a/app/views/file/choose_folder_from_course.php
+++ b/app/views/file/choose_folder_from_course.php
@@ -53,7 +53,7 @@ jQuery(function ($) {
                     </button>
                 </td>
                 <td>
-                    <?= htmlReady($course->start_semester->name) ?>
+                    <?= htmlReady($course->getTextualSemester()) ?>
                 </td>
             </tr>
         <? endforeach; ?>
diff --git a/lib/classes/AdminCourseFilter.class.php b/lib/classes/AdminCourseFilter.class.php
index ea0de9a32d51c0385d934b0d7dcdfd5f28e8df9b..6fa47242e98fd72777c76ae1375f9046ab3b7f17 100644
--- a/lib/classes/AdminCourseFilter.class.php
+++ b/lib/classes/AdminCourseFilter.class.php
@@ -171,7 +171,7 @@ class AdminCourseFilter
             'join' => "LEFT JOIN",
             'on' => "semester_courses.course_id = seminare.Seminar_id"
         ];
-        $this->settings['query']['where']['semester'] = "(seminare.start_time <= :semester_beginn AND (semester_courses.semester_id IS NULL OR semester_courses.semester_id = :semester_id))";
+        $this->settings['query']['where']['semester'] = "(semester_courses.semester_id IS NULL OR semester_courses.semester_id = :semester_id)";
         $this->settings['parameter']['semester_beginn'] = $semester['beginn'];
         $this->settings['parameter']['semester_id'] = $semester['id'];
         return $this;
diff --git a/lib/classes/MyRealmModel.php b/lib/classes/MyRealmModel.php
index 570338926f3661c2e37e8010cbb166ab8773eb10..a68a0c1ac5ff6b2055fdfe894cff1f606aeab738 100644
--- a/lib/classes/MyRealmModel.php
+++ b/lib/classes/MyRealmModel.php
@@ -347,8 +347,8 @@ class MyRealmModel
             $_course['temp_name']      = $course->name;
             $_course['number']         = $course->veranstaltungsnummer;
             $_course['is_deputy']      = $is_deputy;
-            if ($show_semester_name && count($course->semesters) !== 0 && !$course->getSemClass()['studygroup_mode']) {
-                $_course['name'] .= ' (' . $course->getFullname('sem-duration-name') . ')';
+            if ($show_semester_name && count($course->semesters) !== 1 && !$course->getSemClass()['studygroup_mode']) {
+                $_course['name'] .= ' (' . $course->getTextualSemester() . ')';
             }
             if ($course->parent_course) {
                 $_course['parent_course'] = $course->parent_course;
diff --git a/lib/classes/coursewizardsteps/BasicDataWizardStep.php b/lib/classes/coursewizardsteps/BasicDataWizardStep.php
index f9d3c7f6fe6fc51f90da607f02a99b99999d89dc..0f0a3a91e008ded4c2823e9545d01317e634230e 100644
--- a/lib/classes/coursewizardsteps/BasicDataWizardStep.php
+++ b/lib/classes/coursewizardsteps/BasicDataWizardStep.php
@@ -401,8 +401,6 @@ class BasicDataWizardStep implements CourseWizardStep
         }
 
         $course->status = $values['coursetype'];
-        $course->start_time = $values['start_time'];
-        $course->duration_time = 0;
         $course->name = new I18NString($values['name'], $values['name_i18n'] ?? []);
         $course->veranstaltungsnummer = $values['number'];
         $course->beschreibung = new I18NString($values['description'], $values['description_i18n'] ?? []);
@@ -439,9 +437,7 @@ class BasicDataWizardStep implements CourseWizardStep
                 $institutes = array_merge($institutes, array_keys($values['participating']));
             }
             $seminar->setInstitutes($institutes);
-            $course->setSemesters([
-                Semester::findByTimestamp($values['start_time'])
-            ]);
+            $course->start_semester = Semester::findByTimestamp($values['start_time']);
             if (isset($values['lecturers']) && is_array($values['lecturers'])) {
                 foreach (array_keys($values['lecturers']) as $user_id) {
                     $seminar->addMember($user_id, 'dozent');
diff --git a/lib/classes/searchtypes/StandardSearch.class.php b/lib/classes/searchtypes/StandardSearch.class.php
index 539da99303fdaf404266674650fb6ec57dbe718d..34ae3b246cf119bc253d109bb9f88def3b092e58 100644
--- a/lib/classes/searchtypes/StandardSearch.class.php
+++ b/lib/classes/searchtypes/StandardSearch.class.php
@@ -88,6 +88,7 @@ class StandardSearch extends SQLSearch
      */
     private function getSQL()
     {
+        $semester = " CONCAT('(',IFNULL(GROUP_CONCAT(DISTINCT sem1.name ORDER BY sem1.beginn SEPARATOR '-'),'" . _('unbegrenzt') . "'),')')";
         switch ($this->search) {
             case "username":
                 $this->extendedLayout = true;
@@ -110,14 +111,10 @@ class StandardSearch extends SQLSearch
                             "OR auth_user_md5.username LIKE :input) AND " . get_vis_query('auth_user_md5', 'search') .
                         " ORDER BY Nachname ASC, Vorname ASC";
             case "Seminar_id":
-                $semester = "CONCAT(' (',
-                    IF(semester_courses.semester_id IS NULL, '" . _('unbegrenzt') . "',
-                        IF(COUNT(DISTINCT semester_courses.semester_id) > 1, CONCAT_WS(' - ', (SELECT start_semester.name FROM `semester_data` AS start_semester WHERE start_semester.semester_id = semester_courses.semester_id ORDER BY `beginn` ASC LIMIT 1), (SELECT end_semester.name FROM `semester_data` AS end_semester WHERE end_semester.semester_id = semester_courses.semester_id ORDER BY `beginn` DESC LIMIT 1)), sem1.name)),
-                    ')')";
-                return "SELECT DISTINCT seminare.Seminar_id, CONCAT_WS(' ', seminare.VeranstaltungsNummer, seminare.Name,  ".$semester.") " .
+                return "SELECT seminare.Seminar_id, CONCAT_WS(' ', seminare.VeranstaltungsNummer, seminare.Name,  ".$semester.") " .
                     "FROM seminare " .
                     "LEFT JOIN semester_courses ON (semester_courses.course_id = seminare.Seminar_id) " .
-                    "JOIN `semester_data` sem1 ON (seminare.`start_time` = sem1.`beginn`) " .
+                    "LEFT JOIN `semester_data` sem1 ON  ON (semester_courses.semester_id = sem1.semester_id) " .
                     "LEFT JOIN seminar_user ON (seminar_user.Seminar_id = seminare.Seminar_id AND seminar_user.status = 'dozent') " .
                     "LEFT JOIN auth_user_md5 ON (auth_user_md5.user_id = seminar_user.user_id) " .
                     "WHERE (seminare.Name LIKE :input " .
@@ -129,18 +126,14 @@ class StandardSearch extends SQLSearch
                     "OR seminare.Sonstiges LIKE :input) " .
                     "AND seminare.visible = 1 " .
                     "AND seminare.status NOT IN ('".implode("', '", studygroup_sem_types())."') " .
-                    " ORDER BY sem1.`beginn` DESC, " .
+                    " GROUP BY seminare.seminar_id ORDER BY sem1.`beginn` DESC, " .
                     (Config::get()->IMPORTANT_SEMNUMBER ? "seminare.`VeranstaltungsNummer`, " : "") .
                     "seminare.`Name`";
             case "AnySeminar_id":
-                $semester = "CONCAT(' (',
-                    IF(semester_courses.semester_id IS NULL, '" . _('unbegrenzt') . "',
-                        IF(COUNT(DISTINCT semester_courses.semester_id) > 1, CONCAT_WS(' - ', (SELECT start_semester.name FROM `semester_data` AS start_semester WHERE start_semester.semester_id = semester_courses.semester_id ORDER BY `beginn` ASC LIMIT 1), (SELECT end_semester.name FROM `semester_data` AS end_semester WHERE end_semester.semester_id = semester_courses.semester_id ORDER BY `beginn` DESC LIMIT 1)), sem1.name)),
-                    ')')";
-                return "SELECT DISTINCT seminare.Seminar_id, CONCAT_WS(' ', seminare.VeranstaltungsNummer, seminare.Name,  ".$semester.") " .
+                  return "SELECT seminare.Seminar_id, CONCAT_WS(' ', seminare.VeranstaltungsNummer, seminare.Name,  ".$semester.") " .
                     "FROM seminare " .
                     "LEFT JOIN semester_courses ON (semester_courses.course_id = seminare.Seminar_id) " .
-                    "JOIN `semester_data` sem1 ON (seminare.`start_time` = sem1.`beginn`) " .
+                    "LEFT JOIN `semester_data` sem1 ON (semester_courses.semester_id = sem1.semester_id) " .
                     "LEFT JOIN seminar_user ON (seminar_user.Seminar_id = seminare.Seminar_id AND seminar_user.status = 'dozent') " .
                     "LEFT JOIN auth_user_md5 ON (auth_user_md5.user_id = seminar_user.user_id) " .
                     "WHERE (seminare.Name LIKE :input " .
@@ -152,7 +145,7 @@ class StandardSearch extends SQLSearch
                     "OR seminare.Beschreibung LIKE :input " .
                     "OR seminare.Ort LIKE :input " .
                     "OR seminare.Sonstiges LIKE :input) " .
-                    " ORDER BY sem1.`beginn` DESC, " .
+                    " GROUP BY seminare.seminar_id ORDER BY sem1.`beginn` DESC, " .
                     (Config::get()->IMPORTANT_SEMNUMBER ? "seminare.`VeranstaltungsNummer`, " : "") .
                     "seminare.`Name`";
             case "Arbeitsgruppe_id":
diff --git a/lib/models/Course.class.php b/lib/models/Course.class.php
index b078c0ca2a875ce49cc88741671545095b972198..5a41e02adc524644b247c264598c1df30e02a117 100644
--- a/lib/models/Course.class.php
+++ b/lib/models/Course.class.php
@@ -236,10 +236,12 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe
         $config['additional_fields']['end_time'] = true;
 
         $config['additional_fields']['start_semester'] = [
-            'get' => 'getStartSemester'
+            'get' => 'getStartSemester',
+            'set' => '_set_semester'
         ];
         $config['additional_fields']['end_semester'] = [
-            'get' => 'getEndSemester'
+            'get' => 'getEndSemester',
+            'set' => '_set_semester'
         ];
         $config['additional_fields']['semester_text'] = [
             'get' => 'getTextualSemester'
@@ -264,11 +266,8 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe
         $config['i18n_fields']['leistungsnachweis'] = true;
         $config['i18n_fields']['ort'] = true;
 
-        $config['additional_fields']['config']['get'] = function ($course) {
-            return CourseConfig::get($course->id);
-        };
-
         $config['registered_callbacks']['before_update'][] = 'logStore';
+        $config['registered_callbacks']['before_store'][] = 'cbSetStartAndDurationTime';
         $config['registered_callbacks']['after_create'][] = 'setDefaultTools';
         $config['registered_callbacks']['after_delete'][] = function ($course) {
             CourseAvatar::getAvatar($course->id)->reset();
@@ -285,73 +284,71 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe
 
     public function getEnd_Time()
     {
-        if (!$this->semesters) {
-            return -1;
-        }
-
-        return $this->semesters->last()->ende;
+        return $this->duration_time == -1 ? -1 : $this->start_time + $this->duration_time;
     }
 
     public function setEnd_Time($value)
     {
-        throw new Exception("This function is unavailable.");
+        if ($value == -1) {
+            $this->duration_time = -1;
+        } elseif ($this->start_time > 0 && $value > $this->start_time) {
+            $this->duration_time = $value - $this->start_time;
+        } else {
+            $this->duration_time = 0;
+        }
     }
 
-    /**
-     * Sets the start semester of the course.
-     */
-    public function setStartSemester(Semester $semester)
+    public function _set_semester($field, $value)
     {
-        $this->start_semester = $semester;
+        $method = 'set' . ($field === 'start_semester' ? 'StartSemester' : 'EndSemester');
+        $this->$method($value);
     }
 
     /**
-     * Sets the end semester of the course.
+     * @param Semester $semester
      */
-    public function setEndSemester(Semester $semester)
+    public function setStartSemester(Semester $semester)
     {
-        $this->end_semester = $semester;
+        $end_semester = $this->semesters->last();
+        $start_semester = $this->semesters->first();
+        if ($end_semester) {
+            if (count($this->semesters) > 1 && $end_semester->beginn < $semester->beginn) {
+                throw new InvalidArgumentException('start-semester must start before end-semester');
+            }
+            foreach ($this->semesters as $key => $one_semester) {
+                if ($one_semester->beginn <= $semester->beginn) {
+                    $this->semesters->offsetUnset($key);
+                }
+            }
+        }
+        $this->semesters[] = $semester;
+        $this->semesters->orderBy('beginn asc');
+        //add possibly missing semesters between start_semester and end_semester
+        if (count($this->semesters) > 1 && $semester->beginn < $start_semester->beginn) {
+            $this->setEndSemester($end_semester);
+        }
     }
 
-    public function setSemesters($semesters)
+    /**
+     * @param Semester|null $semester
+     */
+    public function setEndSemester(?Semester $semester)
     {
-        $semester_ids = array_map(function ($s) {
-            return $s->id;
-        }, $semesters);
-
-        if (count($semester_ids) > 0) {
-            $delete = DBManager::get()->prepare("
-                DELETE FROM semester_courses
-                WHERE semester_id NOT IN (:semester_ids)
-                    AND course_id = :course_id
-            ");
-            $delete->execute([
-                'semester_ids' => $semester_ids,
-                'course_id' => $this->id,
-            ]);
+        $start_semester = $this->semesters->first();
+        if ($start_semester) {
+            if ($semester && $start_semester->beginn > $semester->beginn) {
+                throw new InvalidArgumentException('end-semester must start after start-semester');
+            }
+            $this->semesters = [];
+            if ($semester) {
+                $all_semester = SimpleCollection::createFromArray(Semester::getAll());
+                $this->semesters = $all_semester->findBy('beginn', [$start_semester->beginn, $semester->beginn], '>=<=');
+            }
         } else {
-            $delete = DBManager::get()->prepare("
-                DELETE FROM semester_courses
-                WHERE course_id = :course_id
-            ");
-            $delete->execute([
-                'course_id' => $this->id,
-            ]);
-        }
-        $insert = DBManager::get()->prepare("
-            INSERT IGNORE INTO semester_courses
-            SET course_id = :course_id,
-                semester_id = :semester_id,
-                mkdate = UNIX_TIMESTAMP(),
-                chdate = UNIX_TIMESTAMP()
-        ");
-        foreach ($semesters as $semester) {
-            $insert->execute([
-                'course_id' => $this->id,
-                'semester_id' => $semester->id,
-            ]);
-        }
-        $this->resetRelation('semesters');
+            if ($semester) {
+                $this->semesters[] = $semester;
+            }
+        }
     }
 
     /**
@@ -365,7 +362,7 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe
         if (count($this->semesters) > 0) {
             return $this->semesters->first();
         } else {
-            return Semester::findByTimestamp($this['start_time']);
+            return Semester::findCurrent();
         }
     }
 
@@ -380,7 +377,6 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe
         if (count($this->semesters) > 0) {
             return $this->semesters->last();
         }
-        return null;
     }
 
     /**
@@ -394,7 +390,7 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe
         } elseif (count($this->semesters) === 1) {
             return $this->start_semester->name;
         } else {
-            return $this->start_semester->name .' - ' . _('unbegrenzt');
+            return _('unbegrenzt');
         }
     }
 
@@ -422,14 +418,14 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe
             }
             return false;
         } else {
-            return $this->start_time <= $semester->beginn;
+            return true;
         }
     }
 
     public function getFreeSeats()
     {
         $free_seats = $this->admission_turnout - $this->getNumParticipants();
-        return max($free_seats, 0);;
+        return max($free_seats, 0);
     }
 
     public function isWaitlistAvailable()
@@ -551,10 +547,7 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe
         $data[0] = $this->name;
         $data[1] = $sem_type['name'];
         $data[2] = $this->veranstaltungsnummer;
-        $data[3] = $this->start_semester->name;
-        if ($this->start_semester !== $this->end_semester && !$this->isStudygroup()) {
-            $data[3] .= ' - ' .  ($this->end_semester ? $this->end_semester->name : _('unbegrenzt'));
-        }
+        $data[3] = $this->getTextualSemester();
         return trim(vsprintf($template[$format], array_map('trim', $data)));
     }
 
@@ -564,9 +557,9 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe
      * The dates can be filtered by an optional time range. By default,
      * all dates are retrieved.
      *
-     * @param $range_begin The begin timestamp of the time range.
+     * @param int $range_begin The begin timestamp of the time range.
      *
-     * @param $range_end The end timestamp of the time range.
+     * @param int $range_end The end timestamp of the time range.
      *
      * @returns SimpleCollection A collection of all retrieved dates and
      *     cancelled dates.
@@ -595,7 +588,7 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe
     /**
      * Sets this courses study areas to the given values.
      *
-     * @param $ids the new study areas
+     * @param array $ids the new study areas
      * @return bool Changes successfully saved?
      */
     public function setStudyAreas($ids)
@@ -751,9 +744,13 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe
      */
     protected function logStore()
     {
-        if ($this->isFieldDirty('start_semester')) {
+        if ($this->isFieldDirty('start_time')) {
             //Log change of start semester:
-            StudipLog::log('SEM_SET_STARTSEMESTER', $this->id, $this->start_semester->beginn);
+            StudipLog::log('SEM_SET_STARTSEMESTER', $this->id, isset($this->start_semester) ? $this->start_semester->name : _('unbegrenzt'));
+            NotificationCenter::postNotification('CourseDidChangeSchedule', $this);
+        }
+        if ($this->isFieldDirty('duration_time')) {
+            StudipLog::log('SEM_SET_ENDSEMESTER', $this->id, $this->getTextualSemester());
             NotificationCenter::postNotification('CourseDidChangeSchedule', $this);
         }
 
@@ -805,6 +802,27 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe
         }
     }
 
+    /**
+     * Called directly before storing the object to edit the columns start_time and duration_time
+     * which are both deprecated but are still in use for older plugins.
+     */
+    public function cbSetStartAndDurationTime()
+    {
+        if ($this->isFieldDirty('start_time')) {
+            $this->setStartSemester(Semester::findByTimestamp($this->start_time));
+        }
+        if ($this->isFieldDirty('duration_time')) {
+            $this->setEndSemester($this->duration_time == -1 ? null : Semester::findByTimestamp($this->start_time + $this->duration_time));
+        }
+        if ($this->isOpenEnded()) {
+            $this->start_time = $this->start_time ?: Semester::findCurrent()->beginn;
+            $this->duration_time = -1;
+        } else {
+            $this->start_time = $this->getStartSemester()->beginn;
+            $this->duration_time = $this->getEndSemester()->beginn - $this->start_time;
+        }
+    }
+
 
     //StudipItem interface implementation:
 
diff --git a/lib/models/Semester.class.php b/lib/models/Semester.class.php
index b2b7f31a864d22683d39d99045ed32fa5d871641..2652de837840d634b394d407ef6c0046ecd0885e 100644
--- a/lib/models/Semester.class.php
+++ b/lib/models/Semester.class.php
@@ -349,23 +349,15 @@ class Semester extends SimpleORMap
 
     /**
      * Returns the start week dates for this semester (and other
-     * semesters if duration is > 0).
+     * semesters if $end_semester is given).
      *
-     * @param mixed $duration Duration time (false to restrict to current
-     *                        semester, -1 for indefinite duration, otherwise
-     *                        the int value for the duration so that
-     *                        semester start + duration = end)
+     * @param Semester $end_semester end semester, default is $this
      * @return array containing the start weeks
      */
-    public function getStartWeeks($duration = false)
+    public function getStartWeeks(?Semester $end_semester = null)
     {
-        if ($duration === false) {
+        if (!$end_semester) {
             $end_semester = $this;
-        } elseif ($duration == -1) {
-            $semesters = self::getAll();
-            $end_semester = end($semesters);
-        } else {
-            $end_semester = self::findByTimestamp((int)$this->beginn + (int)$duration);
         }
 
         $timestamp = $this->getCorrectedLectureBegin();