diff --git a/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py b/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py
index 30c4809383f17f2ba047f49e3964a21daf608920..aab4ab7b6d15f9622d6c5f1e4014ca9711a33a4d 100755
--- a/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py
+++ b/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py
@@ -207,643 +207,643 @@ class TestDynamicScheduling(TestCase):  # Note: we use django.test.TestCase inst
         self.assertEqual(scheduled_scheduling_unit.status, 'scheduled')
         self.assertEqual(scheduled_scheduling_unit.start_time, at)
 
-#     @unittest.skip("FIX TEST, skipping it for now, see TODO comment in assign_start_stop_times_to_schedulable_scheduling_units")
-#     def test_three_simple_observations_no_constraints_different_project_priority(self):
-#         scheduling_unit_draft_low = self.create_simple_observation_scheduling_unit("scheduling unit low", scheduling_set=self.scheduling_set_low)
-#         scheduling_unit_blueprint_low = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_low)
-#
-#         scheduling_unit_draft_medium = self.create_simple_observation_scheduling_unit("scheduling unit medium", scheduling_set=self.scheduling_set_medium)
-#         scheduling_unit_blueprint_medium = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_medium)
-#
-#         scheduling_unit_draft_high = self.create_simple_observation_scheduling_unit("scheduling unit high", scheduling_set=self.scheduling_set_high)
-#         scheduling_unit_blueprint_high = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_high)
-#
-#         # call the method-under-test.
-#         scheduled_scheduling_unit = do_dynamic_schedule()
-#
-#         # we expect the scheduling_unit with the highest project rank to be scheduled first
-#         self.assertIsNotNone(scheduled_scheduling_unit)
-#         self.assertEqual(scheduling_unit_blueprint_high.id, scheduled_scheduling_unit.id)
-#
-#         # check the results
-#         # we expect the sub_high to be scheduled
-#         scheduling_unit_blueprint_low.refresh_from_db()
-#         scheduling_unit_blueprint_medium.refresh_from_db()
-#         scheduling_unit_blueprint_high.refresh_from_db()
-#         self.assertEqual(scheduling_unit_blueprint_low.status, 'schedulable')
-#         self.assertEqual(scheduling_unit_blueprint_medium.status, 'schedulable')
-#         self.assertEqual(scheduling_unit_blueprint_high.status, 'scheduled')
-#
-#         # check the scheduled subtask
-#         upcoming_scheduled_subtasks = models.Subtask.objects.filter(state__value='scheduled',
-#                                                                     task_blueprint__scheduling_unit_blueprint__in=(scheduling_unit_blueprint_low,
-#                                                                                                                    scheduling_unit_blueprint_medium,
-#                                                                                                                    scheduling_unit_blueprint_high)).all()
-#         self.assertEqual(1, upcoming_scheduled_subtasks.count())
-#         self.assertEqual(scheduling_unit_blueprint_high.id, upcoming_scheduled_subtasks[0].task_blueprint.scheduling_unit_blueprint.id)
-#
-#         # check scheduling_unit_blueprint_low starts after the scheduled scheduling_unit_blueprint_high
-#         self.assertGreater(scheduling_unit_blueprint_low.start_time, scheduling_unit_blueprint_medium.start_time)
-#         self.assertGreater(scheduling_unit_blueprint_medium.start_time, scheduling_unit_blueprint_high.start_time)
-#
-#         # ensure DEFAULT_INTER_OBSERVATION_GAP between them
-#         self.assertGreaterEqual(scheduling_unit_blueprint_medium.start_time - scheduling_unit_blueprint_high.stop_time, DEFAULT_INTER_OBSERVATION_GAP)
-#         self.assertGreaterEqual(scheduling_unit_blueprint_low.start_time - scheduling_unit_blueprint_medium.stop_time, DEFAULT_INTER_OBSERVATION_GAP)
-#
-#     def test_time_bound_unit_wins_even_at_lower_priority(self):
-#         # create two schedule units, one with high one with low prio.
-#         # first create them without any further constraints, and check if high prio wins.
-#         scheduling_unit_draft_low = self.create_simple_observation_scheduling_unit("scheduling unit low", scheduling_set=self.scheduling_set_low)
-#         scheduling_unit_blueprint_low = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_low)
-#
-#         scheduling_unit_draft_high = self.create_simple_observation_scheduling_unit("scheduling unit high", scheduling_set=self.scheduling_set_high)
-#         scheduling_unit_blueprint_high = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_high)
-#
-#         now = datetime.utcnow()
-#         tomorrow = now+timedelta(days=1)
-#
-#         # call the method-under-test.
-#         best_scored_scheduling_unit = find_best_next_schedulable_unit([scheduling_unit_blueprint_low, scheduling_unit_blueprint_high], now, tomorrow)
-#
-#         # we expect the scheduling_unit with the highest project rank to be scheduled first
-#         self.assertEqual(scheduling_unit_blueprint_high.id, best_scored_scheduling_unit.scheduling_unit.id)
-#
-#         #now update the low prio unit with a time constraint, "forcing" it to be run in a very thight upcoming time window.
-#         scheduling_unit_draft_low.scheduling_constraints_doc['time'] = { 'before': (now+scheduling_unit_draft_low.duration).isoformat()+'Z' }
-#         scheduling_unit_draft_low.save()
-#         scheduling_unit_blueprint_low.refresh_from_db()
-#
-#         # call the method-under-test.
-#         best_scored_scheduling_unit = find_best_next_schedulable_unit([scheduling_unit_blueprint_low, scheduling_unit_blueprint_high], now, tomorrow)
-#
-#         # now we expect the scheduling_unit with the lowest project rank to be scheduled first because it can only run within this limited timewindow
-#         self.assertEqual(scheduling_unit_draft_low.id, best_scored_scheduling_unit.scheduling_unit.id)
-#
-#
-#         #  update the low prio unit. enlarge the time window constraint a bit, so both low and high prio units can fit
-#         # this should result that the high prio goes first, and the low prio (which now fits as well) goes second
-#         scheduling_unit_draft_low.scheduling_constraints_doc['time'] = \
-#             { 'before': (now+scheduling_unit_draft_low.duration+scheduling_unit_draft_high.duration).isoformat()+'Z' }
-#         scheduling_unit_draft_low.save()
-#         scheduling_unit_blueprint_low.refresh_from_db()
-#
-#         # call the method-under-test.
-#         best_scored_scheduling_unit = find_best_next_schedulable_unit([scheduling_unit_blueprint_low, scheduling_unit_blueprint_high], now, tomorrow)
-#
-#         # now we expect the scheduling_unit with the lowest project rank to be scheduled first because it can only
-#         # run within this limited timewindow
-#         self.assertEqual(scheduling_unit_blueprint_low.id, best_scored_scheduling_unit.scheduling_unit.id)
-#
-#         # call the method-under-test again but search after first unit (should return low prio unit)
-#         stop_time_of_first =  best_scored_scheduling_unit.start_time + best_scored_scheduling_unit.scheduling_unit.duration
-#         best_scored_scheduling_unit = find_best_next_schedulable_unit([scheduling_unit_blueprint_low, scheduling_unit_blueprint_high], stop_time_of_first, tomorrow)
-#         self.assertEqual(scheduling_unit_blueprint_low.id, best_scored_scheduling_unit.scheduling_unit.id)
-#
-#     def test_manual_constraint_is_preventing_scheduling_unit_from_being_scheduled_dynamically(self):
-#         scheduling_unit_draft_manual = self.create_simple_observation_scheduling_unit("scheduling unit manual low", scheduling_set=self.scheduling_set_low,
-#                                                                                       constraints={'scheduler': 'manual'})
-#         scheduling_unit_blueprint_manual = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_manual)
-#         self.assertEqual(scheduling_unit_blueprint_manual.status, "schedulable")
-#
-#         # call the method-under-test.
-#         scheduled_scheduling_unit = do_dynamic_schedule()
-#
-#         # we expect no scheduling_unit to be scheduled, because the only one is set to 'manual' constraint
-#         self.assertIsNone(scheduled_scheduling_unit)
-#
-#         # check the results
-#         scheduling_unit_blueprint_manual.refresh_from_db()
-#         self.assertEqual(scheduling_unit_blueprint_manual.status, 'schedulable')
-#
-#     @unittest.skip("FIX TEST, skipping it for now,...something with manual scheduler ?")
-#     def test_manually_scheduled_blocking_dynamically_scheduled(self):
-#         scheduling_unit_draft_manual = self.create_simple_observation_scheduling_unit("scheduling unit manual low", scheduling_set=self.scheduling_set_low,
-#                                                                                       constraints={'scheduler': 'manual'})
-#         scheduling_unit_blueprint_manual = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_manual)
-#         self.assertEqual(scheduling_unit_blueprint_manual.status, "schedulable")
-#
-#         schedule_independent_subtasks_in_scheduling_unit_blueprint(scheduling_unit_blueprint_manual, datetime.utcnow())
-#         self.assertEqual(scheduling_unit_blueprint_manual.status, "scheduled")
-#
-#         scheduling_unit_draft_high = self.create_simple_observation_scheduling_unit("scheduling unit online high", scheduling_set=self.scheduling_set_high)
-#         scheduling_unit_blueprint_high = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_high)
-#
-#         # call the method-under-test.
-#         scheduled_scheduling_unit = do_dynamic_schedule()
-#
-#         # we expect the no scheduling_unit to be scheduled, because the manual is in the way -> Fix it
-#         self.assertIsNone(scheduled_scheduling_unit)
-#
-#         # check the results
-#         # we expect the sub_high to be scheduled
-#         scheduling_unit_blueprint_high.refresh_from_db()
-#         self.assertEqual(scheduling_unit_blueprint_high.status, 'schedulable')
-#
-#         # check scheduling_unit_blueprint_low starts after the scheduled scheduling_unit_blueprint_high
-#         self.assertGreater(scheduling_unit_blueprint_high.start_time, scheduling_unit_blueprint_manual.start_time)
-#
-#         # ensure DEFAULT_INTER_OBSERVATION_GAP between them
-#         self.assertGreaterEqual(scheduling_unit_blueprint_high.start_time - scheduling_unit_blueprint_manual.stop_time, DEFAULT_INTER_OBSERVATION_GAP)
-#
-#
-# class TestDailyConstraints(TestCase):
-#     '''
-#     Tests for the constraint checkers used in dynamic scheduling
-#     '''
-#
-#     def setUp(self) -> None:
-#         # scheduling unit
-#         self.obs_duration = 120 * 60
-#         scheduling_set = models.SchedulingSet.objects.create(**SchedulingSet_test_data())
-#         scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit("scheduling unit for ...%s" % self._testMethodName[30:],
-#                                                                                                 scheduling_set=scheduling_set,
-#                                                                                                 obs_duration=self.obs_duration)
-#         self.scheduling_unit_blueprint = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft)
-#
-#         # mock out conversions for speedup and assertable timestamps
-#         # earliest_start_time requests timestamp and timestamp+1day
-#         self.sunrise_data = {
-#             '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(2020, 1, 1, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}, {"start": datetime(2020, 1, 2, 17, 30, 0), "end": datetime(2020, 1, 3, 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(2020, 1, 1, 17, 45, 0), "end": datetime(2020, 1, 2, 7, 45, 0)}, {"start": datetime(2020, 1, 2, 17, 45, 0), "end": datetime(2020, 1, 3, 7, 45, 0)}]}}
-#
-#         # variant for timestamp before sunrise, which returns the previous night
-#         self.sunrise_data_early_night = {
-#             '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)}]},
-#             '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
-#         self.sunrise_data_early_night_early_night = {
-#             'CS001': {"sunrise": [{"start": datetime(2020, 1, 1, 7, 30, 0), "end": datetime(2020, 1, 1, 9, 30, 0)}, {"start": datetime(2020, 1, 1, 7, 30, 0), "end": datetime(2020, 1, 1, 9, 30, 0)}],
-#                       "day": [{"start": datetime(2020, 1, 1, 9, 30, 0), "end": datetime(2020, 1, 1, 15, 30, 0)}, {"start": datetime(2020, 1, 1, 9, 30, 0), "end": datetime(2020, 1, 1, 15, 30, 0)}],
-#                       "sunset": [{"start": datetime(2020, 1, 1, 15, 30, 0), "end": datetime(2020, 1, 1, 17, 30, 0)},{"start": datetime(2020, 1, 1, 15, 30, 0), "end": datetime(2020, 1, 1, 17, 30, 0)}],
-#                       "night": [{"start": datetime(2019, 12, 31, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}, {"start": datetime(2019, 12, 31, 17, 30, 0), "end": datetime(2020, 1, 1, 7, 30, 0)}]}}
-#
-#         self.sunrise_data_early_night_late_night = {
-#             'CS001': {"sunrise": [{"start": datetime(2020, 1, 1, 7, 30, 0), "end": datetime(2020, 1, 1, 9, 30, 0)}, {"start": datetime(2020, 1, 1, 7, 30, 0), "end": datetime(2020, 1, 1, 9, 30, 0)}],
-#                       "day": [{"start": datetime(2020, 1, 1, 9, 30, 0), "end": datetime(2020, 1, 1, 15, 30, 0)}, {"start": datetime(2020, 1, 1, 9, 30, 0), "end": datetime(2020, 1, 1, 15, 30, 0)}],
-#                       "sunset": [{"start": datetime(2020, 1, 1, 15, 30, 0), "end": datetime(2020, 1, 1, 17, 30, 0)},{"start": datetime(2020, 1, 1, 15, 30, 0), "end": datetime(2020, 1, 1, 17, 30, 0)}],
-#                       "night": [{"start": datetime(2019, 12, 31, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}, {"start": datetime(2020, 1, 1, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}]}}
-#
-#         self.sunrise_data_late_night_late_night = {
-#             'CS001': {"sunrise": [{"start": datetime(2020, 1, 1, 7, 30, 0), "end": datetime(2020, 1, 1, 9, 30, 0)}, {"start": datetime(2020, 1, 1, 7, 30, 0), "end": datetime(2020, 1, 1, 9, 30, 0)}],
-#                       "day": [{"start": datetime(2020, 1, 1, 9, 30, 0), "end": datetime(2020, 1, 1, 15, 30, 0)}, {"start": datetime(2020, 1, 1, 9, 30, 0), "end": datetime(2020, 1, 1, 15, 30, 0)}],
-#                       "sunset": [{"start": datetime(2020, 1, 1, 15, 30, 0), "end": datetime(2020, 1, 1, 17, 30, 0)},{"start": datetime(2020, 1, 1, 15, 30, 0), "end": datetime(2020, 1, 1, 17, 30, 0)}],
-#                       "night": [{"start": datetime(2020, 1, 1, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}, {"start": datetime(2020, 1, 1, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}]}}
-#
-#         self.sunrise_data_late_night_early_night_next_day = {
-#             '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(2020, 1, 1, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}, {"start": datetime(2020, 1, 1, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}]}}
-#
-#         self.sunrise_data_late_night_late_night_next_day = {
-#             '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(2020, 1, 1, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}, {"start": datetime(2020, 1, 2, 17, 30, 0), "end": datetime(2020, 1, 3, 7, 30, 0)}]}}
-#
-#
-#         self.sunrise_patcher = mock.patch('lofar.sas.tmss.services.scheduling.constraints.template_constraints_v1.timestamps_and_stations_to_sun_rise_and_set')
-#         self.sunrise_mock = self.sunrise_patcher.start()
-#         self.sunrise_mock.return_value = self.sunrise_data
-#         self.addCleanup(self.sunrise_patcher.stop)
-#
-#     # require_day
-#
-#     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'])
-#
-#     def test_get_earliest_possible_start_time_with_daytime_constraint_returns_day_start_of_latest_station(self):
-#         self.scheduling_unit_blueprint.requirements_doc['tasks']['Observation']['specifications_doc']['station_groups'] = [{'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'])
-#
-#     def test_get_earliest_possible_start_time_with_daytime_constraint_returns_timestamp(self):
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
-#         self.scheduling_unit_blueprint.save()
-#         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)
-#
-#     def test_get_earliest_possible_start_time_with_daytime_constraint_returns_next_day_start(self):
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
-#         self.scheduling_unit_blueprint.save()
-#         timestamp = datetime(2020, 1, 1, 20, 0, 0)
-#         returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
-#         self.assertEqual(returned_time, self.sunrise_data['CS001']['day'][1]['start'])
-#
-#     def test_get_earliest_possible_start_time_with_daytime_constraint_returns_next_day_start_when_obs_does_not_fit(self):
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
-#         self.scheduling_unit_blueprint.save()
-#         timestamp = datetime(2020, 1, 1, 14, 0, 0)
-#         returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
-#         self.assertEqual(returned_time, self.sunrise_data['CS001']['day'][1]['start'])
-#
-#     def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_daytime_constraint_returns_true(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_late_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 10, 0, 0)
-#         upper_bound = datetime(2020, 1, 1, 15, 0, 0)
-#         self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#     def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_daytime_constraint_returns_false_when_not_daytime(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_late_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 20, 0, 0)
-#         upper_bound = datetime(2020, 1, 1, 23, 0, 0)
-#         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#     def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_daytime_constraint_returns_false_when_partially_not_daytime(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_late_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 14, 0, 0)
-#         upper_bound = datetime(2020, 1, 1, 18, 0, 0)
-#         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 8, 0, 0)
-#         upper_bound = datetime(2020, 1, 1, 12, 0, 0)
-#         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#     def test_can_run_within_timewindow_with_daytime_constraint_returns_correct_value(self):
-#         # todo: for time ranges across dates, consider removing the mock for this because the moving window cannot be easily mocked
-#         # remove other constraints:
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {}
-#
-#         # set constraint to test
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
-#         self.scheduling_unit_blueprint.save()
-#
-#         # can run in day
-#         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 8, 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))
-#
-#         # cannot run at night
-#         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 15, 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))
-#
-#     # require_night
-#
-#     def test_get_earliest_possible_start_time_with_nighttime_constraint_returns_night_start(self):
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
-#         self.scheduling_unit_blueprint.save()
-#         timestamp = datetime(2020, 1, 1, 14, 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_nighttime_constraint_returns_night_start_of_latest_station(self):
-#         self.scheduling_unit_blueprint.requirements_doc['tasks']['Observation']['specifications_doc']['station_groups'] = [{'stations': ['CS001', 'DE601']}]
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
-#         self.scheduling_unit_blueprint.save()
-#         timestamp = datetime(2020, 1, 1, 14, 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_nighttime_constraint_returns_timestamp(self):
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
-#         self.scheduling_unit_blueprint.save()
-#
-#         # late night
-#         timestamp = datetime(2020, 1, 1, 23, 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_nighttime_constraint_returns_next_night_start_when_obs_does_not_fit(self):
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
-#         self.scheduling_unit_blueprint.save()
-#
-#         # early night
-#         self.sunrise_mock.return_value = self.sunrise_data_early_night
-#         timestamp = datetime(2020, 1, 1, 6, 0, 0)
-#         returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
-#         self.assertEqual(returned_time, self.sunrise_data_early_night['CS001']['night'][1]['start'])
-#
-#     def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_nighttime_constraint_returns_true(self):
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
-#         self.scheduling_unit_blueprint.save()
-#
-#         # early night
-#         self.sunrise_mock.return_value = self.sunrise_data_early_night_early_night
-#         lower_bound = datetime(2020, 1, 1, 1, 0, 0)
-#         upper_bound = datetime(2020, 1, 1, 3, 0, 0)
-#         self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#         # late night
-#         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.assertTrue(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#         # night-night next day
-#         self.sunrise_mock.return_value = self.sunrise_data_late_night_early_night_next_day
-#         lower_bound = datetime(2020, 1, 1, 23, 0, 0)
-#         upper_bound = datetime(2020, 1, 2, 3, 0, 0)
-#         self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#     def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_nighttime_constraint_returns_false_when_not_nighttime(self):
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = 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, 14, 0, 0)
-#         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#     def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_nighttime_constraint_returns_false_when_partially_not_nighttime(self):
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
-#         self.scheduling_unit_blueprint.save()
-#
-#         # night-day next day
-#         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night_next_day
-#         lower_bound = datetime(2020, 1, 1, 23, 0, 0)
-#         upper_bound = datetime(2020, 1, 2, 10, 0, 0)
-#         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#         # day-night next day
-#         self.sunrise_mock.return_value = self.sunrise_data_late_night_early_night_next_day
-#         lower_bound = datetime(2020, 1, 1, 14, 0, 0)
-#         upper_bound = datetime(2020, 1, 2, 3, 0, 0)
-#         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#         # day-night same day
-#         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 14, 0, 0)
-#         upper_bound = datetime(2020, 1, 1, 20, 0, 0)
-#         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#         # night-day same day
-#         self.sunrise_mock.return_value = self.sunrise_data_early_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 3, 0, 0)
-#         upper_bound = datetime(2020, 1, 1, 10, 0, 0)
-#         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#         # day-night-day
-#         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night_next_day
-#         lower_bound = datetime(2020, 1, 1, 14, 0, 0)
-#         upper_bound = datetime(2020, 1, 2, 10, 0, 0)
-#         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#         # night-day-night
-#         self.sunrise_mock.return_value = self.sunrise_data_early_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 3, 0, 0)
-#         upper_bound = datetime(2020, 1, 1, 23, 0, 0)
-#         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#     def test_can_run_within_timewindow_with_nighttime_constraint_returns_correct_value(self):
-#         # todo: for time ranges across dates, consider removing the mock for this because the moving window cannot be easily mocked
-#         # remove other constraints:
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {}
-#
-#         # set constraint to test
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
-#         self.scheduling_unit_blueprint.save()
-#
-#         # cannot run in day
-#         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 8, 0, 0)
-#         upper_bound = datetime(2020, 1, 1, 15, 0, 0)
-#         self.assertFalse(can_run_within_timewindow(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#         # can run at night
-#         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 15, 0, 0)
-#         upper_bound = datetime(2020, 1, 1, 23, 0, 0)
-#         self.assertTrue(can_run_within_timewindow(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#
-#     # 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']['station_groups'] = [{'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']['station_groups'] = [{'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_anywhere_within_timewindow_with_daily_constraints_with_twilight_constraint_returns_true(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_late_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 10, 0, 0)
-#         upper_bound = datetime(2020, 1, 1, 15, 0, 0)
-#         self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#     def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_twilight_constraint_returns_false_when_in_twilight(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_late_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 8, 0, 0)
-#         upper_bound = datetime(2020, 1, 1, 9, 0, 0)
-#         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 16, 0, 0)
-#         upper_bound = datetime(2020, 1, 1, 17, 0, 0)
-#         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#     def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_twilight_constraint_returns_false_when_partially_in_twilight(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_late_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 10, 0, 0)
-#         upper_bound = datetime(2020, 1, 1, 18, 0, 0)
-#         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 8, 0, 0)
-#         upper_bound = datetime(2020, 1, 1, 10, 0, 0)
-#         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#     def test_can_run_within_timewindow_with_twilight_constraint_returns_correct_value(self):
-#         # todo: for time ranges across dates, consider removing the mock for this because the moving window cannot be easily mocked
-#         # remove other constraints:
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {}
-#
-#         # set constraint to test
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
-#         self.scheduling_unit_blueprint.save()
-#
-#         # can run in day
-#         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 8, 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))
-#
-#         # can run at night
-#         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
-#         lower_bound = datetime(2020, 1, 1, 15, 0, 0)
-#         upper_bound = datetime(2020, 1, 1, 23, 0, 0)
-#         self.assertTrue(can_run_within_timewindow(self.scheduling_unit_blueprint, lower_bound, upper_bound))
-#
-#
-# class TestSkyConstraints(unittest.TestCase):
-#     '''
-#     Tests for the constraint checkers used in dynamic scheduling
-#     '''
-#
-#     def setUp(self) -> None:
-#         # scheduling unit
-#         self.obs_duration = 120 * 60
-#         scheduling_set = models.SchedulingSet.objects.create(**SchedulingSet_test_data())
-#         scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit("scheduling unit for ...%s" % self._testMethodName[30:],
-#                                                                                                 scheduling_set=scheduling_set,
-#                                                                                                 obs_duration=self.obs_duration)
-#         self.scheduling_unit_blueprint = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft)
-#
-#         # mock out conversions for speedup and assertable timestamps
-#         self.distance_data = {
-#            "sun": {datetime(2020, 1, 1, 10, 0, 0): Angle("0.3rad"), datetime(2020, 1, 1, 12, 0, 0): Angle("0.35rad")},
-#            "moon": {datetime(2020, 1, 1, 10, 0, 0): Angle("0.2rad"), datetime(2020, 1, 1, 12, 0, 0): Angle("0.25rad")},
-#            "jupiter": {datetime(2020, 1, 1, 10, 0, 0): Angle("0.1rad"), datetime(2020, 1, 1, 12, 0, 0): Angle("0.15rad")}
-#         }
-#         self.distance_patcher = mock.patch('lofar.sas.tmss.services.scheduling.constraints.template_constraints_v1.coordinates_and_timestamps_to_separation_from_bodies')
-#         self.distance_mock = self.distance_patcher.start()
-#         self.distance_mock.return_value = self.distance_data
-#         self.addCleanup(self.distance_patcher.stop)
-#
-#         self.target_rise_and_set_data = {"CS002": [{"rise": datetime(2020, 1, 1, 8, 0, 0), "set": datetime(2020, 1, 1, 12, 30, 0)},
-#                                                    {"rise": datetime(2020, 1, 1, 8, 0, 0), "set": datetime(2020, 1, 1, 12, 30, 0)}]}
-#         self.target_rise_and_set_patcher = mock.patch('lofar.sas.tmss.services.scheduling.constraints.template_constraints_v1.coordinates_timestamps_and_stations_to_target_rise_and_set')
-#         self.target_rise_and_set_mock = self.target_rise_and_set_patcher.start()
-#         self.target_rise_and_set_mock.return_value = self.target_rise_and_set_data
-#         self.addCleanup(self.target_rise_and_set_patcher.stop)
-#
-#     # min_distance
-#
-#     def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_distance_constraint_returns_true_when_met(self):
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'min_distance': {'sun': 0.1, 'moon': 0.1, 'jupiter': 0.1}}
-#         self.scheduling_unit_blueprint.save()
-#         timestamp = datetime(2020, 1, 1, 10, 0, 0)
-#         returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
-#         self.assertTrue(returned_value)
-#
-#     def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_distance_constraint_returns_false_when_not_met(self):
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'min_distance': {'sun': 0.2, 'moon': 0.2, 'jupiter': 0.2}}
-#         self.scheduling_unit_blueprint.save()
-#         timestamp = datetime(2020, 1, 1, 10, 0, 0)
-#         returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
-#         self.assertFalse(returned_value)
-#
-#     # min_target_elevation
-#
-#     def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_target_elevation_constraint_returns_true_when_met(self):
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'min_target_elevation': 0.1}
-#         self.scheduling_unit_blueprint.save()
-#         timestamp = datetime(2020, 1, 1, 10, 0, 0)
-#         returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
-#         self.assertTrue(returned_value)
-#
-#     def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_target_elevation_constraint_returns_false_when_not_met(self):
-#         self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'min_target_elevation': 0.2}
-#         self.scheduling_unit_blueprint.save()
-#         timestamp = datetime(2020, 1, 1, 11, 0, 0)
-#         returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
-#         self.assertFalse(returned_value)
+    @unittest.skip("FIX TEST, skipping it for now, see TODO comment in assign_start_stop_times_to_schedulable_scheduling_units")
+    def test_three_simple_observations_no_constraints_different_project_priority(self):
+        scheduling_unit_draft_low = self.create_simple_observation_scheduling_unit("scheduling unit low", scheduling_set=self.scheduling_set_low)
+        scheduling_unit_blueprint_low = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_low)
+
+        scheduling_unit_draft_medium = self.create_simple_observation_scheduling_unit("scheduling unit medium", scheduling_set=self.scheduling_set_medium)
+        scheduling_unit_blueprint_medium = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_medium)
+
+        scheduling_unit_draft_high = self.create_simple_observation_scheduling_unit("scheduling unit high", scheduling_set=self.scheduling_set_high)
+        scheduling_unit_blueprint_high = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_high)
+
+        # call the method-under-test.
+        scheduled_scheduling_unit = do_dynamic_schedule()
+
+        # we expect the scheduling_unit with the highest project rank to be scheduled first
+        self.assertIsNotNone(scheduled_scheduling_unit)
+        self.assertEqual(scheduling_unit_blueprint_high.id, scheduled_scheduling_unit.id)
+
+        # check the results
+        # we expect the sub_high to be scheduled
+        scheduling_unit_blueprint_low.refresh_from_db()
+        scheduling_unit_blueprint_medium.refresh_from_db()
+        scheduling_unit_blueprint_high.refresh_from_db()
+        self.assertEqual(scheduling_unit_blueprint_low.status, 'schedulable')
+        self.assertEqual(scheduling_unit_blueprint_medium.status, 'schedulable')
+        self.assertEqual(scheduling_unit_blueprint_high.status, 'scheduled')
+
+        # check the scheduled subtask
+        upcoming_scheduled_subtasks = models.Subtask.objects.filter(state__value='scheduled',
+                                                                    task_blueprint__scheduling_unit_blueprint__in=(scheduling_unit_blueprint_low,
+                                                                                                                   scheduling_unit_blueprint_medium,
+                                                                                                                   scheduling_unit_blueprint_high)).all()
+        self.assertEqual(1, upcoming_scheduled_subtasks.count())
+        self.assertEqual(scheduling_unit_blueprint_high.id, upcoming_scheduled_subtasks[0].task_blueprint.scheduling_unit_blueprint.id)
+
+        # check scheduling_unit_blueprint_low starts after the scheduled scheduling_unit_blueprint_high
+        self.assertGreater(scheduling_unit_blueprint_low.start_time, scheduling_unit_blueprint_medium.start_time)
+        self.assertGreater(scheduling_unit_blueprint_medium.start_time, scheduling_unit_blueprint_high.start_time)
+
+        # ensure DEFAULT_INTER_OBSERVATION_GAP between them
+        self.assertGreaterEqual(scheduling_unit_blueprint_medium.start_time - scheduling_unit_blueprint_high.stop_time, DEFAULT_INTER_OBSERVATION_GAP)
+        self.assertGreaterEqual(scheduling_unit_blueprint_low.start_time - scheduling_unit_blueprint_medium.stop_time, DEFAULT_INTER_OBSERVATION_GAP)
+
+    def test_time_bound_unit_wins_even_at_lower_priority(self):
+        # create two schedule units, one with high one with low prio.
+        # first create them without any further constraints, and check if high prio wins.
+        scheduling_unit_draft_low = self.create_simple_observation_scheduling_unit("scheduling unit low", scheduling_set=self.scheduling_set_low)
+        scheduling_unit_blueprint_low = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_low)
+
+        scheduling_unit_draft_high = self.create_simple_observation_scheduling_unit("scheduling unit high", scheduling_set=self.scheduling_set_high)
+        scheduling_unit_blueprint_high = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_high)
+
+        now = datetime.utcnow()
+        tomorrow = now+timedelta(days=1)
+
+        # call the method-under-test.
+        best_scored_scheduling_unit = find_best_next_schedulable_unit([scheduling_unit_blueprint_low, scheduling_unit_blueprint_high], now, tomorrow)
+
+        # we expect the scheduling_unit with the highest project rank to be scheduled first
+        self.assertEqual(scheduling_unit_blueprint_high.id, best_scored_scheduling_unit.scheduling_unit.id)
+
+        #now update the low prio unit with a time constraint, "forcing" it to be run in a very thight upcoming time window.
+        scheduling_unit_draft_low.scheduling_constraints_doc['time'] = { 'before': (now+scheduling_unit_draft_low.duration).isoformat()+'Z' }
+        scheduling_unit_draft_low.save()
+        scheduling_unit_blueprint_low.refresh_from_db()
+
+        # call the method-under-test.
+        best_scored_scheduling_unit = find_best_next_schedulable_unit([scheduling_unit_blueprint_low, scheduling_unit_blueprint_high], now, tomorrow)
+
+        # now we expect the scheduling_unit with the lowest project rank to be scheduled first because it can only run within this limited timewindow
+        self.assertEqual(scheduling_unit_draft_low.id, best_scored_scheduling_unit.scheduling_unit.id)
+
+
+        #  update the low prio unit. enlarge the time window constraint a bit, so both low and high prio units can fit
+        # this should result that the high prio goes first, and the low prio (which now fits as well) goes second
+        scheduling_unit_draft_low.scheduling_constraints_doc['time'] = \
+            { 'before': (now+scheduling_unit_draft_low.duration+scheduling_unit_draft_high.duration).isoformat()+'Z' }
+        scheduling_unit_draft_low.save()
+        scheduling_unit_blueprint_low.refresh_from_db()
+
+        # call the method-under-test.
+        best_scored_scheduling_unit = find_best_next_schedulable_unit([scheduling_unit_blueprint_low, scheduling_unit_blueprint_high], now, tomorrow)
+
+        # now we expect the scheduling_unit with the lowest project rank to be scheduled first because it can only
+        # run within this limited timewindow
+        self.assertEqual(scheduling_unit_blueprint_low.id, best_scored_scheduling_unit.scheduling_unit.id)
+
+        # call the method-under-test again but search after first unit (should return low prio unit)
+        stop_time_of_first =  best_scored_scheduling_unit.start_time + best_scored_scheduling_unit.scheduling_unit.duration
+        best_scored_scheduling_unit = find_best_next_schedulable_unit([scheduling_unit_blueprint_low, scheduling_unit_blueprint_high], stop_time_of_first, tomorrow)
+        self.assertEqual(scheduling_unit_blueprint_low.id, best_scored_scheduling_unit.scheduling_unit.id)
+
+    def test_manual_constraint_is_preventing_scheduling_unit_from_being_scheduled_dynamically(self):
+        scheduling_unit_draft_manual = self.create_simple_observation_scheduling_unit("scheduling unit manual low", scheduling_set=self.scheduling_set_low,
+                                                                                      constraints={'scheduler': 'manual'})
+        scheduling_unit_blueprint_manual = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_manual)
+        self.assertEqual(scheduling_unit_blueprint_manual.status, "schedulable")
+
+        # call the method-under-test.
+        scheduled_scheduling_unit = do_dynamic_schedule()
+
+        # we expect no scheduling_unit to be scheduled, because the only one is set to 'manual' constraint
+        self.assertIsNone(scheduled_scheduling_unit)
+
+        # check the results
+        scheduling_unit_blueprint_manual.refresh_from_db()
+        self.assertEqual(scheduling_unit_blueprint_manual.status, 'schedulable')
+
+    @unittest.skip("FIX TEST, skipping it for now,...something with manual scheduler ?")
+    def test_manually_scheduled_blocking_dynamically_scheduled(self):
+        scheduling_unit_draft_manual = self.create_simple_observation_scheduling_unit("scheduling unit manual low", scheduling_set=self.scheduling_set_low,
+                                                                                      constraints={'scheduler': 'manual'})
+        scheduling_unit_blueprint_manual = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_manual)
+        self.assertEqual(scheduling_unit_blueprint_manual.status, "schedulable")
+
+        schedule_independent_subtasks_in_scheduling_unit_blueprint(scheduling_unit_blueprint_manual, datetime.utcnow())
+        self.assertEqual(scheduling_unit_blueprint_manual.status, "scheduled")
+
+        scheduling_unit_draft_high = self.create_simple_observation_scheduling_unit("scheduling unit online high", scheduling_set=self.scheduling_set_high)
+        scheduling_unit_blueprint_high = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_high)
+
+        # call the method-under-test.
+        scheduled_scheduling_unit = do_dynamic_schedule()
+
+        # we expect the no scheduling_unit to be scheduled, because the manual is in the way -> Fix it
+        self.assertIsNone(scheduled_scheduling_unit)
+
+        # check the results
+        # we expect the sub_high to be scheduled
+        scheduling_unit_blueprint_high.refresh_from_db()
+        self.assertEqual(scheduling_unit_blueprint_high.status, 'schedulable')
+
+        # check scheduling_unit_blueprint_low starts after the scheduled scheduling_unit_blueprint_high
+        self.assertGreater(scheduling_unit_blueprint_high.start_time, scheduling_unit_blueprint_manual.start_time)
+
+        # ensure DEFAULT_INTER_OBSERVATION_GAP between them
+        self.assertGreaterEqual(scheduling_unit_blueprint_high.start_time - scheduling_unit_blueprint_manual.stop_time, DEFAULT_INTER_OBSERVATION_GAP)
+
+
+class TestDailyConstraints(TestCase):
+    '''
+    Tests for the constraint checkers used in dynamic scheduling
+    '''
+
+    def setUp(self) -> None:
+        # scheduling unit
+        self.obs_duration = 120 * 60
+        scheduling_set = models.SchedulingSet.objects.create(**SchedulingSet_test_data())
+        scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit("scheduling unit for ...%s" % self._testMethodName[30:],
+                                                                                                scheduling_set=scheduling_set,
+                                                                                                obs_duration=self.obs_duration)
+        self.scheduling_unit_blueprint = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft)
+
+        # mock out conversions for speedup and assertable timestamps
+        # earliest_start_time requests timestamp and timestamp+1day
+        self.sunrise_data = {
+            '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(2020, 1, 1, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}, {"start": datetime(2020, 1, 2, 17, 30, 0), "end": datetime(2020, 1, 3, 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(2020, 1, 1, 17, 45, 0), "end": datetime(2020, 1, 2, 7, 45, 0)}, {"start": datetime(2020, 1, 2, 17, 45, 0), "end": datetime(2020, 1, 3, 7, 45, 0)}]}}
+
+        # variant for timestamp before sunrise, which returns the previous night
+        self.sunrise_data_early_night = {
+            '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)}]},
+            '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
+        self.sunrise_data_early_night_early_night = {
+            'CS001': {"sunrise": [{"start": datetime(2020, 1, 1, 7, 30, 0), "end": datetime(2020, 1, 1, 9, 30, 0)}, {"start": datetime(2020, 1, 1, 7, 30, 0), "end": datetime(2020, 1, 1, 9, 30, 0)}],
+                      "day": [{"start": datetime(2020, 1, 1, 9, 30, 0), "end": datetime(2020, 1, 1, 15, 30, 0)}, {"start": datetime(2020, 1, 1, 9, 30, 0), "end": datetime(2020, 1, 1, 15, 30, 0)}],
+                      "sunset": [{"start": datetime(2020, 1, 1, 15, 30, 0), "end": datetime(2020, 1, 1, 17, 30, 0)},{"start": datetime(2020, 1, 1, 15, 30, 0), "end": datetime(2020, 1, 1, 17, 30, 0)}],
+                      "night": [{"start": datetime(2019, 12, 31, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}, {"start": datetime(2019, 12, 31, 17, 30, 0), "end": datetime(2020, 1, 1, 7, 30, 0)}]}}
+
+        self.sunrise_data_early_night_late_night = {
+            'CS001': {"sunrise": [{"start": datetime(2020, 1, 1, 7, 30, 0), "end": datetime(2020, 1, 1, 9, 30, 0)}, {"start": datetime(2020, 1, 1, 7, 30, 0), "end": datetime(2020, 1, 1, 9, 30, 0)}],
+                      "day": [{"start": datetime(2020, 1, 1, 9, 30, 0), "end": datetime(2020, 1, 1, 15, 30, 0)}, {"start": datetime(2020, 1, 1, 9, 30, 0), "end": datetime(2020, 1, 1, 15, 30, 0)}],
+                      "sunset": [{"start": datetime(2020, 1, 1, 15, 30, 0), "end": datetime(2020, 1, 1, 17, 30, 0)},{"start": datetime(2020, 1, 1, 15, 30, 0), "end": datetime(2020, 1, 1, 17, 30, 0)}],
+                      "night": [{"start": datetime(2019, 12, 31, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}, {"start": datetime(2020, 1, 1, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}]}}
+
+        self.sunrise_data_late_night_late_night = {
+            'CS001': {"sunrise": [{"start": datetime(2020, 1, 1, 7, 30, 0), "end": datetime(2020, 1, 1, 9, 30, 0)}, {"start": datetime(2020, 1, 1, 7, 30, 0), "end": datetime(2020, 1, 1, 9, 30, 0)}],
+                      "day": [{"start": datetime(2020, 1, 1, 9, 30, 0), "end": datetime(2020, 1, 1, 15, 30, 0)}, {"start": datetime(2020, 1, 1, 9, 30, 0), "end": datetime(2020, 1, 1, 15, 30, 0)}],
+                      "sunset": [{"start": datetime(2020, 1, 1, 15, 30, 0), "end": datetime(2020, 1, 1, 17, 30, 0)},{"start": datetime(2020, 1, 1, 15, 30, 0), "end": datetime(2020, 1, 1, 17, 30, 0)}],
+                      "night": [{"start": datetime(2020, 1, 1, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}, {"start": datetime(2020, 1, 1, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}]}}
+
+        self.sunrise_data_late_night_early_night_next_day = {
+            '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(2020, 1, 1, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}, {"start": datetime(2020, 1, 1, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}]}}
+
+        self.sunrise_data_late_night_late_night_next_day = {
+            '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(2020, 1, 1, 17, 30, 0), "end": datetime(2020, 1, 2, 7, 30, 0)}, {"start": datetime(2020, 1, 2, 17, 30, 0), "end": datetime(2020, 1, 3, 7, 30, 0)}]}}
+
+
+        self.sunrise_patcher = mock.patch('lofar.sas.tmss.services.scheduling.constraints.template_constraints_v1.timestamps_and_stations_to_sun_rise_and_set')
+        self.sunrise_mock = self.sunrise_patcher.start()
+        self.sunrise_mock.return_value = self.sunrise_data
+        self.addCleanup(self.sunrise_patcher.stop)
+
+    # require_day
+
+    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'])
+
+    def test_get_earliest_possible_start_time_with_daytime_constraint_returns_day_start_of_latest_station(self):
+        self.scheduling_unit_blueprint.requirements_doc['tasks']['Observation']['specifications_doc']['station_groups'] = [{'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'])
+
+    def test_get_earliest_possible_start_time_with_daytime_constraint_returns_timestamp(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
+        self.scheduling_unit_blueprint.save()
+        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)
+
+    def test_get_earliest_possible_start_time_with_daytime_constraint_returns_next_day_start(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
+        self.scheduling_unit_blueprint.save()
+        timestamp = datetime(2020, 1, 1, 20, 0, 0)
+        returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
+        self.assertEqual(returned_time, self.sunrise_data['CS001']['day'][1]['start'])
+
+    def test_get_earliest_possible_start_time_with_daytime_constraint_returns_next_day_start_when_obs_does_not_fit(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
+        self.scheduling_unit_blueprint.save()
+        timestamp = datetime(2020, 1, 1, 14, 0, 0)
+        returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
+        self.assertEqual(returned_time, self.sunrise_data['CS001']['day'][1]['start'])
+
+    def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_daytime_constraint_returns_true(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_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 10, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 15, 0, 0)
+        self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+    def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_daytime_constraint_returns_false_when_not_daytime(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_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 20, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 23, 0, 0)
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+    def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_daytime_constraint_returns_false_when_partially_not_daytime(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_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 14, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 18, 0, 0)
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+        self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 8, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 12, 0, 0)
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+    def test_can_run_within_timewindow_with_daytime_constraint_returns_correct_value(self):
+        # todo: for time ranges across dates, consider removing the mock for this because the moving window cannot be easily mocked
+        # remove other constraints:
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {}
+
+        # set constraint to test
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
+        self.scheduling_unit_blueprint.save()
+
+        # can run in day
+        self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 8, 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))
+
+        # cannot run at night
+        self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 15, 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))
+
+    # require_night
+
+    def test_get_earliest_possible_start_time_with_nighttime_constraint_returns_night_start(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
+        self.scheduling_unit_blueprint.save()
+        timestamp = datetime(2020, 1, 1, 14, 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_nighttime_constraint_returns_night_start_of_latest_station(self):
+        self.scheduling_unit_blueprint.requirements_doc['tasks']['Observation']['specifications_doc']['station_groups'] = [{'stations': ['CS001', 'DE601']}]
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
+        self.scheduling_unit_blueprint.save()
+        timestamp = datetime(2020, 1, 1, 14, 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_nighttime_constraint_returns_timestamp(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
+        self.scheduling_unit_blueprint.save()
+
+        # late night
+        timestamp = datetime(2020, 1, 1, 23, 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_nighttime_constraint_returns_next_night_start_when_obs_does_not_fit(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
+        self.scheduling_unit_blueprint.save()
+
+        # early night
+        self.sunrise_mock.return_value = self.sunrise_data_early_night
+        timestamp = datetime(2020, 1, 1, 6, 0, 0)
+        returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
+        self.assertEqual(returned_time, self.sunrise_data_early_night['CS001']['night'][1]['start'])
+
+    def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_nighttime_constraint_returns_true(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
+        self.scheduling_unit_blueprint.save()
+
+        # early night
+        self.sunrise_mock.return_value = self.sunrise_data_early_night_early_night
+        lower_bound = datetime(2020, 1, 1, 1, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 3, 0, 0)
+        self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+        # late night
+        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.assertTrue(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+        # night-night next day
+        self.sunrise_mock.return_value = self.sunrise_data_late_night_early_night_next_day
+        lower_bound = datetime(2020, 1, 1, 23, 0, 0)
+        upper_bound = datetime(2020, 1, 2, 3, 0, 0)
+        self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+    def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_nighttime_constraint_returns_false_when_not_nighttime(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = 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, 14, 0, 0)
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+    def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_nighttime_constraint_returns_false_when_partially_not_nighttime(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
+        self.scheduling_unit_blueprint.save()
+
+        # night-day next day
+        self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night_next_day
+        lower_bound = datetime(2020, 1, 1, 23, 0, 0)
+        upper_bound = datetime(2020, 1, 2, 10, 0, 0)
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+        # day-night next day
+        self.sunrise_mock.return_value = self.sunrise_data_late_night_early_night_next_day
+        lower_bound = datetime(2020, 1, 1, 14, 0, 0)
+        upper_bound = datetime(2020, 1, 2, 3, 0, 0)
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+        # day-night same day
+        self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 14, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 20, 0, 0)
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+        # night-day same day
+        self.sunrise_mock.return_value = self.sunrise_data_early_night_late_night
+        lower_bound = datetime(2020, 1, 1, 3, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 10, 0, 0)
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+        # day-night-day
+        self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night_next_day
+        lower_bound = datetime(2020, 1, 1, 14, 0, 0)
+        upper_bound = datetime(2020, 1, 2, 10, 0, 0)
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+        # night-day-night
+        self.sunrise_mock.return_value = self.sunrise_data_early_night_late_night
+        lower_bound = datetime(2020, 1, 1, 3, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 23, 0, 0)
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+    def test_can_run_within_timewindow_with_nighttime_constraint_returns_correct_value(self):
+        # todo: for time ranges across dates, consider removing the mock for this because the moving window cannot be easily mocked
+        # remove other constraints:
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {}
+
+        # set constraint to test
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
+        self.scheduling_unit_blueprint.save()
+
+        # cannot run in day
+        self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 8, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 15, 0, 0)
+        self.assertFalse(can_run_within_timewindow(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+        # can run at night
+        self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 15, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 23, 0, 0)
+        self.assertTrue(can_run_within_timewindow(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+
+    # 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']['station_groups'] = [{'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']['station_groups'] = [{'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_anywhere_within_timewindow_with_daily_constraints_with_twilight_constraint_returns_true(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_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 10, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 15, 0, 0)
+        self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+    def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_twilight_constraint_returns_false_when_in_twilight(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_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 8, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 9, 0, 0)
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+        self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 16, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 17, 0, 0)
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+    def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_twilight_constraint_returns_false_when_partially_in_twilight(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_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 10, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 18, 0, 0)
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+        self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 8, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 10, 0, 0)
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+    def test_can_run_within_timewindow_with_twilight_constraint_returns_correct_value(self):
+        # todo: for time ranges across dates, consider removing the mock for this because the moving window cannot be easily mocked
+        # remove other constraints:
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {}
+
+        # set constraint to test
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.save()
+
+        # can run in day
+        self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 8, 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))
+
+        # can run at night
+        self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
+        lower_bound = datetime(2020, 1, 1, 15, 0, 0)
+        upper_bound = datetime(2020, 1, 1, 23, 0, 0)
+        self.assertTrue(can_run_within_timewindow(self.scheduling_unit_blueprint, lower_bound, upper_bound))
+
+
+class TestSkyConstraints(unittest.TestCase):
+    '''
+    Tests for the constraint checkers used in dynamic scheduling
+    '''
+
+    def setUp(self) -> None:
+        # scheduling unit
+        self.obs_duration = 120 * 60
+        scheduling_set = models.SchedulingSet.objects.create(**SchedulingSet_test_data())
+        scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit("scheduling unit for ...%s" % self._testMethodName[30:],
+                                                                                                scheduling_set=scheduling_set,
+                                                                                                obs_duration=self.obs_duration)
+        self.scheduling_unit_blueprint = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft)
+
+        # mock out conversions for speedup and assertable timestamps
+        self.distance_data = {
+           "sun": {datetime(2020, 1, 1, 10, 0, 0): Angle("0.3rad"), datetime(2020, 1, 1, 12, 0, 0): Angle("0.35rad")},
+           "moon": {datetime(2020, 1, 1, 10, 0, 0): Angle("0.2rad"), datetime(2020, 1, 1, 12, 0, 0): Angle("0.25rad")},
+           "jupiter": {datetime(2020, 1, 1, 10, 0, 0): Angle("0.1rad"), datetime(2020, 1, 1, 12, 0, 0): Angle("0.15rad")}
+        }
+        self.distance_patcher = mock.patch('lofar.sas.tmss.services.scheduling.constraints.template_constraints_v1.coordinates_and_timestamps_to_separation_from_bodies')
+        self.distance_mock = self.distance_patcher.start()
+        self.distance_mock.return_value = self.distance_data
+        self.addCleanup(self.distance_patcher.stop)
+
+        self.target_rise_and_set_data = {"CS002": [{"rise": datetime(2020, 1, 1, 8, 0, 0), "set": datetime(2020, 1, 1, 12, 30, 0)},
+                                                   {"rise": datetime(2020, 1, 1, 8, 0, 0), "set": datetime(2020, 1, 1, 12, 30, 0)}]}
+        self.target_rise_and_set_patcher = mock.patch('lofar.sas.tmss.services.scheduling.constraints.template_constraints_v1.coordinates_timestamps_and_stations_to_target_rise_and_set')
+        self.target_rise_and_set_mock = self.target_rise_and_set_patcher.start()
+        self.target_rise_and_set_mock.return_value = self.target_rise_and_set_data
+        self.addCleanup(self.target_rise_and_set_patcher.stop)
+
+    # min_distance
+
+    def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_distance_constraint_returns_true_when_met(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'min_distance': {'sun': 0.1, 'moon': 0.1, 'jupiter': 0.1}}
+        self.scheduling_unit_blueprint.save()
+        timestamp = datetime(2020, 1, 1, 10, 0, 0)
+        returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
+        self.assertTrue(returned_value)
+
+    def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_distance_constraint_returns_false_when_not_met(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'min_distance': {'sun': 0.2, 'moon': 0.2, 'jupiter': 0.2}}
+        self.scheduling_unit_blueprint.save()
+        timestamp = datetime(2020, 1, 1, 10, 0, 0)
+        returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
+        self.assertFalse(returned_value)
+
+    # min_target_elevation
+
+    def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_target_elevation_constraint_returns_true_when_met(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'min_target_elevation': 0.1}
+        self.scheduling_unit_blueprint.save()
+        timestamp = datetime(2020, 1, 1, 10, 0, 0)
+        returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
+        self.assertTrue(returned_value)
+
+    def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_target_elevation_constraint_returns_false_when_not_met(self):
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'min_target_elevation': 0.2}
+        self.scheduling_unit_blueprint.save()
+        timestamp = datetime(2020, 1, 1, 11, 0, 0)
+        returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
+        self.assertFalse(returned_value)
 
 
 class TestTimeConstraints(TestCase):