diff --git a/Docker/lofar-ci/Dockerfile_ci_sas b/Docker/lofar-ci/Dockerfile_ci_sas
index ffcfb4133ecabcbb5004bef01b945d8251ae9127..b515298af20f9d3a3bd01d36e1628ac2eec8c2c5 100644
--- a/Docker/lofar-ci/Dockerfile_ci_sas
+++ b/Docker/lofar-ci/Dockerfile_ci_sas
@@ -16,7 +16,7 @@ RUN yum erase -y postgresql postgresql-server postgresql-devel && \
     cd /bin && ln -s /usr/pgsql-9.6/bin/initdb && ln -s /usr/pgsql-9.6/bin/postgres
 ENV PATH /usr/pgsql-9.6/bin:$PATH 
 
-RUN pip3 install cython kombu lxml requests pygcn xmljson mysql-connector-python python-dateutil Django==3.0.9 djangorestframework==3.11.1 djangorestframework-xml ldap==1.0.2 flask fabric coverage python-qpid-proton PyGreSQL numpy h5py psycopg2 testing.postgresql Flask-Testing scipy Markdown django-filter python-ldap python-ldap-test ldap3 django-jsonforms django-json-widget django-jsoneditor drf-yasg flex swagger-spec-validator django-auth-ldap mozilla-django-oidc jsonschema comet pyxb==1.2.5 graphviz isodate astropy packaging django-debug-toolbar pymysql
+RUN pip3 install cython kombu lxml requests pygcn xmljson mysql-connector-python python-dateutil Django==3.0.9 djangorestframework==3.11.1 djangorestframework-xml ldap==1.0.2 flask fabric coverage python-qpid-proton PyGreSQL numpy h5py psycopg2 testing.postgresql Flask-Testing scipy Markdown django-filter python-ldap python-ldap-test ldap3 django-jsonforms django-json-widget django-jsoneditor drf-yasg flex swagger-spec-validator django-auth-ldap mozilla-django-oidc jsonschema comet pyxb==1.2.5 graphviz isodate astropy packaging django-debug-toolbar pymysql astroplan
 
 #Viewflow package 
 RUN pip3 install django-material django-viewflow
diff --git a/SAS/TMSS/src/tmss/settings.py b/SAS/TMSS/src/tmss/settings.py
index eecff2fb7eb1b29293adf6b7a867e58203342aba..7f160668b40ac7164efdfaea77f44fb018e32d7d 100644
--- a/SAS/TMSS/src/tmss/settings.py
+++ b/SAS/TMSS/src/tmss/settings.py
@@ -137,7 +137,6 @@ DEBUG_TOOLBAR_CONFIG = {
 
 MIDDLEWARE = [
     'django.middleware.gzip.GZipMiddleware',
-    'debug_toolbar.middleware.DebugToolbarMiddleware',
     'django.middleware.security.SecurityMiddleware',
     'django.contrib.sessions.middleware.SessionMiddleware',
     'django.middleware.common.CommonMiddleware',
diff --git a/SAS/TMSS/src/tmss/tmssapp/conversions.py b/SAS/TMSS/src/tmss/tmssapp/conversions.py
index ee8f35b3770cfba1683ad3a2822949a6f6dabe60..ce112f7b30b8f697baf91d4da9202899703715ba 100644
--- a/SAS/TMSS/src/tmss/tmssapp/conversions.py
+++ b/SAS/TMSS/src/tmss/tmssapp/conversions.py
@@ -3,6 +3,60 @@ import astropy.units
 from lofar.lta.sip import station_coordinates
 from datetime import datetime
 from astropy.coordinates.earth import EarthLocation
+from astropy.coordinates import Angle
+from astroplan.observer import Observer
+
+
+def create_astroplan_observer_for_station(station: str) -> Observer:
+    '''
+    returns an astroplan observer for object for a given station, located in the LBA center of the given station
+    :param station: a station name, e.g. "CS002"
+    :return: astroplan.observer.Observer object
+    '''
+
+    coords = station_coordinates.parse_station_coordinates()["%s_LBA" % station.upper()]
+    location = EarthLocation.from_geocentric(x=coords['x'], y=coords['y'], z=coords['z'],  unit=astropy.units.m)
+    observer = Observer(location, name="LOFAR", timezone="UTC")
+    return observer
+
+# default angle to the horizon at which the sunset/sunrise starts and ends, as per LOFAR definition.
+SUN_SET_RISE_ANGLE_TO_HORIZON = Angle(10, unit=astropy.units.deg)
+
+def timestamps_and_stations_to_sun_rise_and_set(timestamps: [datetime], stations: [str], angle_to_horizon: Angle=SUN_SET_RISE_ANGLE_TO_HORIZON) -> dict:
+    """
+    compute sunrise, sunset, day and night of the given stations at the given timestamps
+    :param timestamps: list of datetimes, e.g. [datetime(2020, 1, 1), datetime(2020, 1, 2)]
+    :param stations: list of station names, e.g. ["CS001"]
+    :return A dict that maps station names to a nested dict that contains lists of start and end times for sunrise, sunset, etc, on each requested date.
+        E.g.
+        {"CS001":
+            {   "sunrise": [{"start": (2020, 1, 1, 6, 0, 0)), "end": (2020, 1, 1, 6, 30, 0)},
+                            {"start": (2020, 1, 2, 6, 0, 0)), "end": (2020, 1, 2, 6, 30, 0)}],
+                "sunset": [{"start": (2020, 1, 1, 18, 0, 0)), "end": (2020, 1, 1, 18, 30, 0)},
+                           {"start": (2020, 1, 2, 18, 0, 0)), "end": (2020, 1, 2, 18, 30, 0)}],
+                "day": [{"start": (2020, 1, 1, 6, 30, 0)), "end": (2020, 1, 1, 18, 00, 0)},
+                        {"start": (2020, 1, 2, 6, 30, 0)), "end": (2020, 1, 2, 18, 00, 0)}],
+                "night": [{"start": (2020, 1, 1, 18, 30, 0)), "end": (2020, 1, 2, 6, 0, 0)},
+                          {"start": (2020, 1, 2, 18,3 0, 0)), "end": (2020, 1, 3, 6, 0, 0)}],
+            }
+        }
+    """
+    return_dict = {}
+    for station in stations:
+        for timestamp in timestamps:
+            observer = create_astroplan_observer_for_station(station)
+            sunrise_start = observer.sun_rise_time(time=Time(timestamp), which='previous')
+            if sunrise_start.to_datetime().date() < timestamp.date():
+                sunrise_start = observer.sun_rise_time(time=Time(timestamp), horizon=-angle_to_horizon, which='next')
+            sunrise_end = observer.sun_rise_time(time=Time(timestamp), horizon=angle_to_horizon, which='next')
+            sunset_start = observer.sun_set_time(time=sunrise_end, horizon=angle_to_horizon, which='next')
+            sunset_end = observer.sun_set_time(time=sunrise_end, horizon=-angle_to_horizon, which='next')
+            sunrise_next_start = observer.sun_rise_time(time=sunset_end, horizon=-angle_to_horizon, which='next')
+            return_dict.setdefault(station, {}).setdefault("sunrise", []).append({"start": sunrise_start.to_datetime(), "end": sunrise_end.to_datetime()})
+            return_dict[station].setdefault("sunset", []).append({"start": sunset_start.to_datetime(), "end": sunset_end.to_datetime()})
+            return_dict[station].setdefault("day", []).append({"start": sunrise_end.to_datetime(), "end": sunset_start.to_datetime()})
+            return_dict[station].setdefault("night", []).append({"start": sunset_end.to_datetime(), "end": sunrise_next_start.to_datetime()})
+    return return_dict
 
 
 def local_sidereal_time_for_utc_and_station(timestamp: datetime = None,
diff --git a/SAS/TMSS/src/tmss/tmssapp/views.py b/SAS/TMSS/src/tmss/tmssapp/views.py
index cf57dc6832f0f7340d7483d8789b2f0b2b2e12b8..851a625197765c401e1cc54db50c4b33d986b2e7 100644
--- a/SAS/TMSS/src/tmss/tmssapp/views.py
+++ b/SAS/TMSS/src/tmss/tmssapp/views.py
@@ -4,15 +4,17 @@ from django.http import HttpResponse, JsonResponse, Http404
 from django.shortcuts import get_object_or_404, render
 from lofar.sas.tmss.tmss.tmssapp import models
 from lofar.common.json_utils import get_default_json_object_for_schema
+from lofar.common.datetimeutils import formatDatetime
 from lofar.sas.tmss.tmss.tmssapp.adapters.parset import convert_to_parset
 from drf_yasg.utils import swagger_auto_schema
+from drf_yasg.openapi import Parameter
 from rest_framework.permissions import AllowAny
 from rest_framework.decorators import authentication_classes, permission_classes
 from django.apps import apps
 
 from datetime import datetime
 import dateutil.parser
-from lofar.sas.tmss.tmss.tmssapp.conversions import local_sidereal_time_for_utc_and_station, local_sidereal_time_for_utc_and_longitude
+from lofar.sas.tmss.tmss.tmssapp.conversions import local_sidereal_time_for_utc_and_station, local_sidereal_time_for_utc_and_longitude, timestamps_and_stations_to_sun_rise_and_set
 
 def subtask_template_default_specification(request, subtask_template_pk:int):
     subtask_template = get_object_or_404(models.SubtaskTemplate, pk=subtask_template_pk)
@@ -84,10 +86,24 @@ def get_stations_in_group(request, template_name:str, template_version:str, stat
                          'stations': stations})
 
 
+@permission_classes([AllowAny])
+@authentication_classes([AllowAny])
+@swagger_auto_schema(responses={200: 'An isoformat timestamp of the current UTC clock of the system'},
+                     operation_description="Get the current system time in UTC")
 def utc(request):
     return HttpResponse(datetime.utcnow().isoformat(), content_type='text/plain')
 
-
+@permission_classes([AllowAny])
+@authentication_classes([AllowAny])
+@swagger_auto_schema(responses={200: 'The LST time in hms format at the given UTC time and station or longitude'},
+                     operation_description="Get LST time for UTC time and station or longitude",
+                     manual_parameters=[Parameter(name='station', required=False, type='string', in_='query',
+                                                  description="A station names (defaults to CS002)"),
+                                        Parameter(name='timestamp', required=False, type='string', in_='query',
+                                                  description="A timestamp in isoformat (defaults to utcnow)"),
+                                        Parameter(name='longitude', required=False, type='float', in_='query',
+                                                  description="A longitude")
+                                        ])
 def lst(request):
     # Handling optional parameters via django paths in urls.py is a pain, we access them on the request directly instead.
     timestamp = request.GET.get('timestamp', None)
@@ -109,4 +125,33 @@ def lst(request):
         lst_lon = local_sidereal_time_for_utc_and_station(timestamp)
 
     # todo: do we want to return a dict, so users can make sure their parameters were parsed correctly instead?
-    return HttpResponse(str(lst_lon), content_type='text/plain')
\ No newline at end of file
+    return HttpResponse(str(lst_lon), content_type='text/plain')
+
+
+@permission_classes([AllowAny])
+@authentication_classes([AllowAny])
+@swagger_auto_schema(responses={200: 'A JSON object with sunrise, sunset, day and night of the given stations at the given timestamps'},
+                     operation_description="Get sunrise, sunset, day and night for stations and timestamps",
+                     manual_parameters=[Parameter(name='stations', required=False, type='string', in_='query',
+                                                  description="comma-separated list of station names"),
+                                        Parameter(name='timestamps', required=False, type='string', in_='query',
+                                                  description="comma-separated list of isoformat timestamps")])
+def get_sun_rise_and_set(request):
+    """
+    returns sunrise and sunset at the given stations and timestamps, or today at LOFAR core if none specified.
+    example request: /api/util/sun_rise_and_set?stations=CS002,CS005&timestamps=2020-05-01,2020-09-09T11-11-00
+    """
+    timestamps = request.GET.get('timestamps', None)
+    stations = request.GET.get('stations', None)
+    if timestamps is None:
+        timestamps = [datetime.utcnow()]
+    else:
+        timestamps = timestamps.split(',')
+        timestamps = [dateutil.parser.parse(timestamp) for timestamp in timestamps]  #  isot to datetime
+    if stations is None:
+        stations = ['CS002']
+    else:
+        stations = stations.split(',')
+
+    return JsonResponse(timestamps_and_stations_to_sun_rise_and_set(timestamps, stations))
+
diff --git a/SAS/TMSS/src/tmss/urls.py b/SAS/TMSS/src/tmss/urls.py
index 376c1c83ba457c81f98901a262b286e8db94c52b..781e6af696a5bc3f0827c84b8c60286fa898112f 100644
--- a/SAS/TMSS/src/tmss/urls.py
+++ b/SAS/TMSS/src/tmss/urls.py
@@ -65,6 +65,7 @@ urlpatterns = [
     path('schemas/<str:template>/<str:name>/<str:version>/', views.get_template_json_schema, name='get_template_json_schema'),
     path('station_groups/<str:template_name>/<str:template_version>/<str:station_group>', views.get_stations_in_group, name='get_stations_in_group'), #TODO: how to make trailing slash optional?
     path('station_groups/<str:template_name>/<str:template_version>/<str:station_group>/', views.get_stations_in_group, name='get_stations_in_group'),
+    path('util/sun_rise_and_set', views.get_sun_rise_and_set, name='get_sun_rise_and_set'),
     path(r'util/utc', views.utc, name="system-utc"),
     path(r'util/lst', views.lst, name="conversion-lst"),
 ]
diff --git a/SAS/TMSS/test/t_conversions.py b/SAS/TMSS/test/t_conversions.py
index ccd4025f6c4c21a43d63f5ccb6a55c3b764f0963..14231c4f091c04b1f3c53b971bbf069555e6000f 100755
--- a/SAS/TMSS/test/t_conversions.py
+++ b/SAS/TMSS/test/t_conversions.py
@@ -26,6 +26,7 @@ import logging
 import requests
 import dateutil.parser
 import astropy.coordinates
+import json
 
 logger = logging.getLogger(__name__)
 logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO)
@@ -127,6 +128,43 @@ class UtilREST(unittest.TestCase):
         lon_str2 = r2.content.decode('utf8')
         self.assertNotEqual(lon_str1, lon_str2)
 
+    def test_util_sun_rise_and_set_returns_json_structure_with_defaults(self):
+        r = requests.get(BASE_URL + '/util/sun_rise_and_set', auth=AUTH)
+        self.assertEqual(r.status_code, 200)
+        r_dict = json.loads(r.content.decode('utf-8'))
+
+        # assert defaults to core and today
+        self.assertIn('CS002', r_dict.keys())
+        sunrise_start = dateutil.parser.parse(r_dict['CS002']['sunrise'][0]['start'])
+        self.assertEqual(datetime.date.today(), sunrise_start.date())
+
+    def test_util_sun_rise_and_set_considers_stations(self):
+        stations = ['CS005', 'RS305', 'DE609']
+        r = requests.get(BASE_URL + '/util/sun_rise_and_set?stations=%s' % ','.join(stations), auth=AUTH)
+        self.assertEqual(r.status_code, 200)
+        r_dict = json.loads(r.content.decode('utf-8'))
+
+        # assert station is included in response and timestamps differ
+        sunset_start_last = None
+        for station in stations:
+            self.assertIn(station, r_dict.keys())
+            sunset_start = dateutil.parser.parse(r_dict[station]['sunset'][0]['start'])
+            if sunset_start_last:
+                self.assertNotEqual(sunset_start, sunset_start_last)
+            sunset_start_last = sunset_start
+
+    def test_util_sun_rise_and_set_considers_timestamps(self):
+        timestamps = ['2020-01-01', '2020-02-22T16-00-00', '2020-3-11', '2020-01-01']
+        r = requests.get(BASE_URL + '/util/sun_rise_and_set?timestamps=%s' % ','.join(timestamps), auth=AUTH)
+        self.assertEqual(r.status_code, 200)
+        r_dict = json.loads(r.content.decode('utf-8'))
+
+        # assert all requested timestamps are included in response (sunrise on same day)
+        for i in range(len(timestamps)):
+            expected_date = dateutil.parser.parse(timestamps[i]).date()
+            response_date = dateutil.parser.parse(r_dict['CS002']['sunrise'][i]['start']).date()
+            self.assertEqual(expected_date, response_date)
+
 
 if __name__ == "__main__":
     os.environ['TZ'] = 'UTC'