diff --git a/SAS/TMSS/backend/services/scheduling/lib/constraints/template_constraints_v1.py b/SAS/TMSS/backend/services/scheduling/lib/constraints/template_constraints_v1.py
index 9de1309082ee8e2d8d9150460480fc8ae1e05fe7..2b68de96458c95d1cd2e068f7916dc9851ff3a45 100644
--- a/SAS/TMSS/backend/services/scheduling/lib/constraints/template_constraints_v1.py
+++ b/SAS/TMSS/backend/services/scheduling/lib/constraints/template_constraints_v1.py
@@ -151,26 +151,76 @@ def can_run_anywhere_within_timewindow_with_daily_constraints(scheduling_unit: m
 
 
 def can_run_within_timewindow_with_time_constraints(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime, upper_bound: datetime) -> bool:
-    '''evaluate the time contraint(s)'''
+    """
+    Checks whether it is possible to run the scheduling unit /somewhere/ in the given time window,
+    considering the duration of the involved observation.
+    :return: True if there is at least one possibility to place the scheduling unit in a way that all time
+             constraints are met over the runtime of the observation, else False.
+    """
+    main_observation_task_name = get_target_observation_task_name_from_requirements_doc(scheduling_unit)
+    duration = timedelta(
+        seconds=scheduling_unit.requirements_doc['tasks'][main_observation_task_name]['specifications_doc']['duration'])
+    window_lower_bound = lower_bound
+    while window_lower_bound + duration < upper_bound:
+        window_upper_bound = window_lower_bound + duration
+        if can_run_anywhere_within_timewindow_with_time_constraints(scheduling_unit, window_lower_bound, window_upper_bound):
+            return True
+        window_lower_bound += min(timedelta(hours=1), upper_bound - window_lower_bound)
+
+    return False
+
+
+def can_run_anywhere_within_timewindow_with_time_constraints(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime, upper_bound: datetime) -> bool:
+    """
+    Checks whether it is possible to place the scheduling unit arbitrarily in the given time window,
+    i.e. the time constraints must be met over the full time window.
+    :return: True if all time constraints are met over the entire time window, else False.
+    """
+    can_run_at = True
+    can_run_before = True
+    can_run_with_after = True
+    can_run_between = True
+    can_run_not_between = True
     constraints = scheduling_unit.draft.scheduling_constraints_doc
-    # TODO: TMSS-244 (and more?), evaluate the constraints in constraints['time']
+
+    # TODO TMSS-672 Move to can_run_within and make logic correct
     if has_manual_scheduler_constraint(scheduling_unit):
         at = parser.parse(constraints['time']['at'], ignoretz=True)
-        return at >= lower_bound and at+scheduling_unit.duration <= upper_bound # todo: suggestion: use scheduling_unit.requirements_doc['tasks']['Observation']['specifications_doc']['duration']
+        can_run_at = (at >= lower_bound and at+scheduling_unit.duration <= upper_bound) # todo: suggestion: use scheduling_unit.requirements_doc['tasks']['Observation']['specifications_doc']['duration']
 
     if 'before' in constraints['time']:
         before = parser.parse(constraints['time']['before'], ignoretz=True)
-        return before <= upper_bound-scheduling_unit.duration   # todo: suggestion: use scheduling_unit.requirements_doc['tasks']['Observation']['specifications_doc']['duration']
+        can_run_before = (before <= upper_bound-scheduling_unit.duration)   # todo: suggestion: use scheduling_unit.requirements_doc['tasks']['Observation']['specifications_doc']['duration']
 
     if 'after' in constraints['time']:
         after = parser.parse(constraints['time']['after'], ignoretz=True)
-        return lower_bound >= after
-
-    # if 'between' in constraints['time']:
-    #     betweens = [ dateutil.parser.parse(constraints['time']['between'])
-    #     return lower_bound >= after
-
-    return True # for now, ignore time contraints.
+        can_run_with_after = (lower_bound >= after)
+
+    # Run within one of these time windows
+    if 'between' in constraints['time']:
+        can_run_between = True  # empty list is no constraint
+        for between in constraints['time']['between']:
+            time_from = parser.parse(between["from"], ignoretz=True)
+            time_to = parser.parse(between["to"], ignoretz=True)
+            if time_from >= lower_bound and time_to <= upper_bound:
+                can_run_between = True
+                break  # something inside the boundary so True and don't look any further
+            else:
+                can_run_between = False
+
+    # Do NOT run within any of these time windows
+    if 'not_between' in constraints['time']:
+        can_run_not_between = True  # empty list is no constraint
+        for not_between in constraints['time']['not_between']:
+            time_from = parser.parse(not_between["from"], ignoretz=True)
+            time_to = parser.parse(not_between["to"], ignoretz=True)
+            if time_from <= upper_bound and time_to >= lower_bound:
+                can_run_not_between = False
+                break  # something outside the boundary so False and don't look any further
+            else:
+                can_run_not_between = True
+
+    return can_run_at & can_run_before & can_run_with_after & can_run_between & can_run_not_between
 
 
 def can_run_within_timewindow_with_sky_constraints(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime, upper_bound: datetime) -> bool:
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 9525e9abba9d40fc006ea3c427854b92b4443df0..45efbf8ae32a51b02d26139010d6f5c125fc2334 100755
--- a/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py
+++ b/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py
@@ -775,6 +775,250 @@ class TestSkyConstraints(unittest.TestCase):
         self.assertFalse(returned_value)
 
 
+class TestTimeConstraints(TestCase):
+    """
+    Tests for the time constraint checkers used in dynamic scheduling with different boundaries
+    Possible time constraints are
+    - after
+    - before
+    - between (one or more 'from-to')
+    - not between (one or more 'from-to')
+    """
+
+    def add_time_between_constraint(self, from_timestamp, to_timestamp):
+        lst_between_constraints = self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["between"]
+        time_constraint_dict = {"from": from_timestamp.isoformat(), "to": to_timestamp.isoformat()}
+        lst_between_constraints.append(time_constraint_dict)
+        self.scheduling_unit_blueprint.save()
+
+    def add_time_not_between_constraint(self, from_timestamp, to_timestamp):
+        lst_between_constraints = self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["not_between"]
+        time_constraint_dict = {"from": from_timestamp.isoformat(), "to": to_timestamp.isoformat()}
+        lst_between_constraints.append(time_constraint_dict)
+        self.scheduling_unit_blueprint.save()
+
+    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,
+                                    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)
+
+    def test_can_run_anywhere_after_returns_false(self):
+        # Set datetime constraints after lower_bound
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                             datetime(2020, 1, 1, 12, 0, 0),
+                                                                             datetime(2020, 1, 2, 12, 0, 0)))
+
+        # Set datetime constraints to upper_bound
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 2, 12, 0, 0).isoformat()
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                             datetime(2020, 1, 1, 12, 0, 0),
+                                                                             datetime(2020, 1, 2, 12, 0, 0)))
+
+    def test_can_run_anywhere_after_returns_true(self):
+        # Set datetime constraints before lower_bound
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 11, 0, 0).isoformat()
+        self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                            datetime(2020, 1, 1, 12, 0, 0),
+                                                                            datetime(2020, 1, 2, 12, 0, 0)))
+        # Set datetime constraints equal to lower_bound
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 12, 0, 0).isoformat()
+        self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                            datetime(2020, 1, 1, 12, 0, 0),
+                                                                            datetime(2020, 1, 2, 12, 0, 0)))
+
+    def test_can_run_anywhere_before_returns_false(self):
+        # Set datetime constraints after upper_bound
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 13, 0, 0).isoformat()
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                             datetime(2020, 1, 1, 12, 0, 0),
+                                                                             datetime(2020, 1, 2, 12, 0, 0)))
+        # Set datetime constraints equal to upper_bound
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 12, 0, 0).isoformat()
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                             datetime(2020, 1, 1, 12, 0, 0),
+                                                                             datetime(2020, 1, 2, 12, 0, 0)))
+        # Set datetime constraints equal to upper_bound - duration + 1 sec
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = \
+            (datetime(2020, 1, 2, 12, 0, 0) - self.scheduling_unit_blueprint.duration + timedelta(seconds=1)).isoformat()
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                            datetime(2020, 1, 1, 12, 0, 0),
+                                                                            datetime(2020, 1, 2, 12, 0, 0)))
+
+    def test_can_run_anywhere_before_returns_true(self):
+        # Set datetime constraints far before upper_bound (lower_bound)
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 12, 0, 0).isoformat()
+        self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                            datetime(2020, 1, 1, 12, 0, 0),
+                                                                            datetime(2020, 1, 2, 12, 0, 0)))
+        # Set datetime constraints equal to upper_bound - duration
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = \
+            (datetime(2020, 1, 2, 12, 0, 0) - self.scheduling_unit_blueprint.duration).isoformat()
+        self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                                                            datetime(2020, 1, 1, 12, 0, 0),
+                                                                            datetime(2020, 1, 2, 12, 0, 0)))
+
+    def test_can_run_anywhere_between_returns_false(self):
+        """
+        Test 'between' constraint with start/stop datetime constraints 'outside' upper_bound or lower_bound
+        """
+        # Set datetime constraints start > lower_bound and stop > upper_bound
+        self.add_time_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 2, 15, 0, 0))
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                         datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
+        # Set datetime constraints start < lower_bound and stop < upper_bound
+        self.add_time_between_constraint(datetime(2020, 1, 1, 8, 0, 0), datetime(2020, 1, 2, 8, 0, 0))
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                         datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
+        # Set datetime constraints start > lower_bound and stop > upper_bound (1 second only)
+        self.add_time_between_constraint(datetime(2020, 1, 1, 12, 0, 1), datetime(2020, 1, 2, 12, 0, 1))
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                         datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
+
+    def test_can_run_anywhere_between_returns_true(self):
+        """
+        Test 'between' constraint with start/stop datetime constraints 'inside' upper_bound and lower_bound
+        """
+        # Set datetime constraints start > lower_bound and stop < upper_bound -duration
+        self.add_time_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 1, 15, 0, 0))
+        self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                         datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 20, 0, 0)))
+
+        # Set datetime constraints start = lower_bound and stop = upper_bound - duration
+        self.add_time_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 1, 15, 0, 0))
+        self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                         datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 1, 17, 10, 0)))
+
+    def test_can_run_anywhere_not_between_returns_false(self):
+        """
+        Test 'not_between' constraint with start/stop datetime constraints 'inside' upper_bound or lower_bound
+        """
+        # Set datetime constraints start > lower_bound and stop > upper_bound
+        self.add_time_not_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 2, 15, 0, 0))
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                             datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
+
+        # Set datetime constraints start < lower_bound and stop > lower_bound and < upper_bound
+        self.add_time_not_between_constraint(datetime(2020, 1, 1, 8, 0, 0), datetime(2020, 1, 2, 8, 0, 0))
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                             datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
+
+        # Set datetime constraints start > lower_bound and stop < upper_bound
+        self.add_time_not_between_constraint(datetime(2020, 1, 1, 16, 0, 0), datetime(2020, 1, 2, 8, 0, 0))
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                             datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
+
+        # Set datetime constraints start < lower_bound and stop > upper_bound
+        self.add_time_not_between_constraint(datetime(2020, 1, 1, 8, 0, 0), datetime(2020, 1, 2, 14, 0, 0))
+        self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                            datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
+
+    def test_can_run_anywhere_not_between_returns_true(self):
+        """
+        Test 'not_between' constraint with start/stop datetime constraints 'outside' upper_bound and lower_bound
+        """
+        # Set datetime constraints start < lower_bound and stop < lower_bound
+        self.add_time_not_between_constraint(datetime(2020, 1, 1, 3, 0, 0), datetime(2020, 1, 1, 11, 0, 0))
+        self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                             datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 16, 0, 0)))
+
+        # Set datetime constraints start > upper_bound and stop > upper_bound
+        self.add_time_not_between_constraint(datetime(2020, 1, 1, 16, 0, 0), datetime(2020, 1, 1, 20, 0, 0))
+        self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
+                                             datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 1, 15, 0, 0)))
+
+    def execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary(self):
+        """
+        Just a simple wrapper to call 'can_run_anywhere_within_timewindow_with_time_constraints' function
+        with a 24 hours boundary 2020-01-01 12:00 - 2020-01-02 12:00
+        """
+        return (tc1.can_run_within_timewindow_with_time_constraints(
+                    self.scheduling_unit_blueprint, datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)))
+
+    def test_can_run_within_between_constraints(self):
+        """
+        Test multiple 'between' constraints within 24 boundary and check overall result of
+        'can_run_within_timewindow_with_time_constraints'
+        This function will iterate between the boundary with boundary shift of 1hr and boundary length of
+        the observation duration, which is in this testcase two hour
+        i.e. 12-14, 13-15, 14-16,..etc.., 9-11
+        """
+        # no constraints defined so should be OK
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # Add constraints of 1hr, we still 'can_run'
+        self.add_time_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 1, 14, 0, 0))
+        self.add_time_between_constraint(datetime(2020, 1, 1, 16, 0, 0), datetime(2020, 1, 1, 17, 0, 0))
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # Add constraints of 2hr, we still 'can_run'
+        self.add_time_between_constraint(datetime(2020, 1, 2, 11, 0, 0), datetime(2020, 1, 2, 13, 0, 0))
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # Add constraint of 24hr constraint, we still 'can_run'
+        self.add_time_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # Add constraint of 2hr, to fill the 'last gap', we 'can run'
+        self.add_time_between_constraint(datetime(2020, 1, 2, 10, 0, 0), datetime(2020, 1, 2, 12, 0, 0))
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # Clear all between constraints
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["between"] = []
+
+        # Add constraints 'outside' the 24hr, now we 'can not run'
+        self.add_time_between_constraint(datetime(2020, 1, 2, 13, 0, 0), datetime(2020, 1, 2, 14, 0, 0))
+        self.add_time_between_constraint(datetime(2020, 1, 2, 16, 0, 0), datetime(2020, 1, 2, 17, 0, 0))
+        self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # Add constraint 'outside' the 24hr, we 'still can not run'
+        self.add_time_between_constraint(datetime(2020, 1, 1, 9, 0, 0), datetime(2020, 1, 1, 12, 0, 0))
+        self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # add one 'inside' constraint, 1 hour within block of 2 hour so overall must be ok
+        self.add_time_between_constraint(datetime(2020, 1, 1, 13, 30, 0), datetime(2020, 1, 1, 14, 30, 0))
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+    def test_can_run_within_not_between_constraints(self):
+        """
+        Test multiple 'not_between' constraints within 24 boundary and check overall result of
+        'can_run_within_timewindow_with_time_constraints'
+        This function will iterate between the boundary with boundary shift of 1hr and boundary length of
+        the observation duration, which is in this testcase two hour
+        i.e. 12-14, 13-15, 14-16,..etc.., 9-11
+        """
+        # no constraints defined so should be OK
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # Add constraints of 1hr, we still 'can_run'
+        self.add_time_not_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 1, 14, 0, 0))
+        self.add_time_not_between_constraint(datetime(2020, 1, 1, 16, 0, 0), datetime(2020, 1, 1, 17, 0, 0))
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # Add constraints of 2hr, we still 'can_run'
+        self.add_time_not_between_constraint(datetime(2020, 1, 1, 18, 0, 0), datetime(2020, 1, 1, 20, 0, 0))
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # Add constraint of 20hr constraint, we still 'can_run'
+        self.add_time_not_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 8, 0, 0))
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # Add constraint of 2hr, to fill the 'last gap', now we can not run
+        self.add_time_not_between_constraint(datetime(2020, 1, 2, 10, 0, 0), datetime(2020, 1, 2, 12, 0, 0))
+        self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+        # Clear all not_between constraints
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["not_between"] = []
+        # Add 4 hr constraints within 24 hours boundary, we can run
+        self.add_time_not_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 16, 0, 0))
+        self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
+
+
 class TestReservedStations(unittest.TestCase):
     """
     Tests for the reserved stations used in dynamic scheduling