diff --git a/SAS/TMSS/services/scheduling/lib/constraints/template_constraints_v1.py b/SAS/TMSS/services/scheduling/lib/constraints/template_constraints_v1.py
index 700556966058fb2fb0046e8409b65f5f85b1d131..b9b7bfe1a72bfe00c5a42f21318289e66a3ef418 100644
--- a/SAS/TMSS/services/scheduling/lib/constraints/template_constraints_v1.py
+++ b/SAS/TMSS/services/scheduling/lib/constraints/template_constraints_v1.py
@@ -76,6 +76,19 @@ def has_manual_scheduler_constraint(scheduling_unit: models.SchedulingUnitBluepr
 
 
 def can_run_within_timewindow_with_daily_constraints(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime, upper_bound: datetime) -> bool:
+    """
+    Checks whether it is possible to run the scheduling unit /somewhere/ in the given time window, considering the duration of the involved observation.
+    :return: True if there is at least one possibility to place the scheduling unit in a way that all daily constraints are met over the runtime of the observation, else False.
+    """
+    # todo: use moving window lower_bound to lower_bound + obs duration, return true once window returned true
+    return can_run_anywhere_within_timewindow_with_daily_constraints(scheduling_unit, lower_bound, upper_bound)
+
+
+def can_run_anywhere_within_timewindow_with_daily_constraints(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime, upper_bound: datetime) -> bool:
+    """
+    Checks whether it is possible to place the scheduling unit arbitrarily in the given time window, i.e. the daily constraints must be met over the full time window.
+    :return: True if all daily constraints are met over the entire time window, else False.
+    """
     '''evaluate the daily contraint'''
     constraints = scheduling_unit.draft.scheduling_constraints_doc
     if constraints['daily']['require_day'] or constraints['daily']['require_night'] or constraints['daily']['avoid_twilight']:
@@ -92,7 +105,7 @@ def can_run_within_timewindow_with_daily_constraints(scheduling_unit: models.Sch
         # check contraint and return false on first failure
         for station in stations:
             # get day/night times for bounds
-            # we could sample in between bounds, but will instead do some checks
+            # we could sample in between bounds, but will instead do some checks so that bounds are sufficient
             if constraints['daily']['require_day'] and lower_bound.date() != upper_bound.date():
                 logger.info("### SchedulingUnitBlueprint id=%s cannot meet require_day constraint when starting and ending on different days." % scheduling_unit.id)
                 return False
@@ -101,11 +114,8 @@ def can_run_within_timewindow_with_daily_constraints(scheduling_unit: models.Sch
             if constraints['daily']['require_day']:
                 for i in range(len(timestamps)):
                     if timestamps[i] < sun_events['day'][i]['start'] or timestamps[i] > sun_events['day'][i]['end']:
-                        logger.info("### %s not between %s and %s" % (timestamps[i], sun_events['day'][i]['start'], sun_events['day'][i]['end']))
                         logger.info("### SchedulingUnitBlueprint id=%s does not meet require_day constraint at timestamp=%s" % (scheduling_unit.id, timestamps[i]))
                         return False
-                    else:
-                        logger.info("### %s between %s and %s" % (timestamps[i], sun_events['day'][i]['start'], sun_events['day'][i]['end'] ))
 
             if constraints['daily']['require_night']:
                 if sun_events['night'][0]['start'].date() != sun_events['night'][1]['start'].date():
@@ -125,12 +135,23 @@ def can_run_within_timewindow_with_daily_constraints(scheduling_unit: models.Sch
                     logger.info("### SchedulingUnitBlueprint id=%s does not meet avoid_twilight constraint." % scheduling_unit.id)
                     return False
 
-
-    logger.info('### SchedulingUnitBlueprint id=%s meets all daily constraints. Returning True.')
     return True
 
 
 def can_run_within_timewindow_with_time_constraints(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime, upper_bound: datetime) -> bool:
+    """
+    Checks whether it is possible to run the scheduling unit /somewhere/ in the given time window, considering the duration of the involved observation.
+    :return: True if there is at least one possibility to place the scheduling unit in a way that all time constraints are met over the runtime of the observation, else False.
+    """
+    # todo: use moving window lower_bound to lower_bound + obs duration, return true once window returned true
+    return can_run_anywhere_within_timewindow_with_time_constraints(scheduling_unit, lower_bound, upper_bound)
+
+
+def can_run_anywhere_within_timewindow_with_time_constraints(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime, upper_bound: datetime) -> bool:
+    """
+    Checks whether it is possible to place the scheduling unit arbitrarily in the given time window, i.e. the time constraints must be met over the full time window.
+    :return: True if all time constraints are met over the entire time window, else False.
+    """
     '''evaluate the time contraint(s)'''
     constraints = scheduling_unit.draft.scheduling_constraints_doc
     # TODO: TMSS-244 (and more?), evaluate the constraints in constraints['time']
@@ -200,7 +221,7 @@ def get_earliest_possible_start_time(scheduling_unit: models.SchedulingUnitBluep
                 next_day = sun_events['day'][1]
                 next_night = sun_events['night'][1]
                 if constraints['daily']['require_day']:
-                    # TODO: Do we need to check for observations that are too long and can e.g. only be run in summer?
+                    # TODO: Do we need to check for observations that are too long and can e.g. only be run in summer? -> recursively traverse through days or sth?
                     if lower_bound + duration > day['end']:
                         start_time_per_station[station] = next_day['start']
                         continue
@@ -221,19 +242,20 @@ def get_earliest_possible_start_time(scheduling_unit: models.SchedulingUnitBluep
                     continue
 
                 if constraints['daily']['avoid_twilight']:
-                    if lower_bound + duration < day['end']:
-                        if lower_bound >= day['start']:
-                            start_time_per_station[station] = lower_bound
-                            continue
-                        start_time_per_station[station] = day['start']
+                    if lower_bound >= day['start'] and lower_bound + duration < day['end']:
+                        # starts and ends in daytime
+                        start_time_per_station[station] = lower_bound
                         continue
-                    if lower_bound + duration < night['end']:
-                        if lower_bound >= night['start']:
-                            start_time_per_station[station] = lower_bound
-                            continue
-                        start_time_per_station[station] = night['start']
+                    if lower_bound >= night['start'] and lower_bound + duration < night['end']:
+                        # starts and ends in nighttime
+                        start_time_per_station[station] = lower_bound
                         continue
-                    start_time_per_station[station] = next_day['start']
+                    if lower_bound < day['start'] and lower_bound + duration >= night['end']:
+                        # ends in morning twilight
+                        start_time_per_station[station] = day['start']
+                        continue
+                    # ends in evening twilight
+                    start_time_per_station[station] = night['start']
                     continue
             return max(start_time_per_station.values())
     except Exception as e:
diff --git a/SAS/TMSS/services/scheduling/test/t_dynamic_scheduling.py b/SAS/TMSS/services/scheduling/test/t_dynamic_scheduling.py
index 799f40bfe73c33fdfbf52fede5effd4d2bed92ab..1a391f7b125cff80f7e9581b3359999b30558f8c 100755
--- a/SAS/TMSS/services/scheduling/test/t_dynamic_scheduling.py
+++ b/SAS/TMSS/services/scheduling/test/t_dynamic_scheduling.py
@@ -302,7 +302,11 @@ class TestDailyConstraints(unittest.TestCase):
             'CS001': {"sunrise": [{"start": datetime(2020, 1, 1, 7, 30, 0), "end": datetime(2020, 1, 1, 9, 30, 0)}, {"start": datetime(2020, 1, 2, 7, 30, 0), "end": datetime(2020, 1, 2, 9, 30, 0)}],
                       "day": [{"start": datetime(2020, 1, 1, 9, 30, 0), "end": datetime(2020, 1, 1, 15, 30, 0)}, {"start": datetime(2020, 1, 2, 9, 30, 0), "end": datetime(2020, 1, 2, 15, 30, 0)}],
                       "sunset": [{"start": datetime(2020, 1, 1, 15, 30, 0), "end": datetime(2020, 1, 1, 17, 30, 0)},{"start": datetime(2020, 1, 2, 15, 30, 0), "end": datetime(2020, 1, 2, 17, 30, 0)}],
-                      "night": [{"start": datetime(2019, 12, 31, 17, 30, 0), "end": datetime(2020, 1, 1, 7, 30, 0)}, {"start": datetime(2020, 1, 1, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}]}}
+                      "night": [{"start": datetime(2019, 12, 31, 17, 30, 0), "end": datetime(2020, 1, 1, 7, 30, 0)}, {"start": datetime(2020, 1, 1, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}]},
+            'DE601': {"sunrise": [{"start": datetime(2020, 1, 1, 7, 45, 0), "end": datetime(2020, 1, 1, 9, 45, 0)}, {"start": datetime(2020, 1, 2, 7, 45, 0), "end": datetime(2020, 1, 2, 9, 45, 0)}],
+                      "day": [{"start": datetime(2020, 1, 1, 9, 45, 0), "end": datetime(2020, 1, 1, 15, 45, 0)}, {"start": datetime(2020, 1, 2, 9, 45, 0), "end": datetime(2020, 1, 2, 15, 45, 0)}],
+                      "sunset": [{"start": datetime(2020, 1, 1, 15, 45, 0), "end": datetime(2020, 1, 1, 17, 45, 0)},{"start": datetime(2020, 1, 2, 15, 45, 0), "end": datetime(2020, 1, 2, 17, 45, 0)}],
+                      "night": [{"start": datetime(2019, 12, 31, 17, 45, 0), "end": datetime(2020, 1, 1, 7, 45, 0)}, {"start": datetime(2020, 1, 1, 17, 45, 0), "end": datetime(2020, 1, 2, 7, 45, 0)}]}}
 
 
         # constraint checker requests lower and upper bound, so we need some variants for various cases
@@ -347,6 +351,7 @@ class TestDailyConstraints(unittest.TestCase):
     def test_get_earliest_possible_start_time_with_daytime_constraint_returns_day_start(self):
         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
         self.scheduling_unit_blueprint.save()
+        self.sunrise_mock.return_value = self.sunrise_data_early_night
         timestamp = datetime(2020, 1, 1, 4, 0, 0)
         returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
         self.assertEqual(returned_time, self.sunrise_data['CS001']['day'][0]['start'])
@@ -355,6 +360,7 @@ class TestDailyConstraints(unittest.TestCase):
         self.scheduling_unit_blueprint.requirements_doc['tasks']['Observation']['specifications_doc']['stations'] = ['CS001', 'DE601']
         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
         self.scheduling_unit_blueprint.save()
+        self.sunrise_mock.return_value = self.sunrise_data_early_night
         timestamp = datetime(2020, 1, 1, 4, 0, 0)
         returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
         self.assertEqual(returned_time, self.sunrise_data['DE601']['day'][0]['start'])
@@ -531,7 +537,116 @@ class TestDailyConstraints(unittest.TestCase):
         upper_bound = datetime(2020, 1, 1, 23, 0, 0)
         self.assertFalse(can_run_within_timewindow(self.scheduling_unit_blueprint, lower_bound, upper_bound))
 
-    # todo: avoid_twilight checks / TMSS-256
+    # avoid_twilight
+
+    def test_get_earliest_possible_start_time_with_twilight_constraint_returns_day_start(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.save()
+
+        self.sunrise_mock.return_value = self.sunrise_data_early_night
+        timestamp = datetime(2020, 1, 1, 9, 0, 0)
+        returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
+        self.assertEqual(returned_time, self.sunrise_data['CS001']['day'][0]['start'])
+
+    def test_get_earliest_possible_start_time_with_twilight_constraint_returns_day_start_of_latest_station(self):
+        self.scheduling_unit_blueprint.requirements_doc['tasks']['Observation']['specifications_doc']['stations'] = ['CS001', 'DE601']
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.save()
+
+        self.sunrise_mock.return_value = self.sunrise_data_early_night
+        timestamp = datetime(2020, 1, 1, 9, 0, 0)
+        returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
+        self.assertEqual(returned_time, self.sunrise_data['DE601']['day'][0]['start'])
+
+    def test_get_earliest_possible_start_time_with_twilight_constraint_returns_night_start(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.save()
+
+        self.sunrise_mock.return_value = self.sunrise_data
+        timestamp = datetime(2020, 1, 1, 17, 0, 0)
+        returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
+        self.assertEqual(returned_time, self.sunrise_data['CS001']['night'][0]['start'])
+
+    def test_get_earliest_possible_start_time_with_twilight_constraint_returns_night_start_of_latest_station(self):
+        self.scheduling_unit_blueprint.requirements_doc['tasks']['Observation']['specifications_doc']['stations'] = ['CS001', 'DE601']
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.save()
+
+        self.sunrise_mock.return_value = self.sunrise_data
+        timestamp = datetime(2020, 1, 1, 17, 0, 0)
+        returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
+        self.assertEqual(returned_time, self.sunrise_data['DE601']['night'][0]['start'])
+
+    def test_get_earliest_possible_start_time_with_twilight_constraint_returns_timestamp(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.save()
+
+        # daytime
+        timestamp = datetime(2020, 1, 1, 10, 0, 0)
+        returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
+        self.assertEqual(returned_time, timestamp)
+
+        # late time
+        timestamp = datetime(2020, 1, 1, 20, 0, 0)
+        returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
+        self.assertEqual(returned_time, timestamp)
+
+        # early night
+        self.sunrise_mock.return_value = self.sunrise_data_early_night
+        timestamp = datetime(2020, 1, 1, 3, 0, 0)
+        returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
+        self.assertEqual(returned_time, timestamp)
+
+    def test_get_earliest_possible_start_time_with_twilight_constraint_returns_day_or_night_start_when_obs_does_not_fit(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.save()
+
+        timestamp = datetime(2020, 1, 1, 15, 0, 0)
+        returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
+        self.assertEqual(returned_time, self.sunrise_data['CS001']['night'][0]['start'])
+
+        self.sunrise_mock.return_value = self.sunrise_data_early_night
+        timestamp = datetime(2020, 1, 1, 7, 0, 0)
+        returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
+        self.assertEqual(returned_time, self.sunrise_data['CS001']['day'][0]['start'])
+
+    def test_can_run_within_timewindow_with_twilight_constraint_returns_true(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'][
+            'min_distance'] = {}  # remove sky constraint
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.save()
+
+        self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 10, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 15, 0, 0)
+        self.assertTrue(can_run_within_timewindow(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+    def test_can_run_within_timewindow_with_twilight_constraint_returns_false_when_in_twilight(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'][
+            'min_distance'] = {}  # remove sky constraint
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.save()
+
+        self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 20, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 23, 0, 0)
+        self.assertFalse(can_run_within_timewindow(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+    def test_can_run_within_timewindow_with_twilight_constraint_returns_false_when_partially_in_twilight(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'][
+            'min_distance'] = {}  # remove sky constraint
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.save()
+
+        self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 10, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 18, 0, 0)
+        self.assertFalse(can_run_within_timewindow(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+        self.sunrise_mock.return_value = self.sunrise_data_early_night_late_night
+        lower_bound = datetime(2020, 1, 1, 8, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 10, 0, 0)
+        self.assertFalse(can_run_within_timewindow(self.scheduling_unit_blueprint, lower_bound, upper_bound))
 
 
 class TestSkyConstraints(unittest.TestCase):