diff --git a/.gitignore b/.gitignore
index 5f846bdc44dc42490d2b3c88d19b3dc0f50533e3..9eca034d61d74660f3cb2fe12292148b84f5e15c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,10 @@ smash/~/
 
 # Disable python bytecode
 *.pyc
+#vim swap files
+*.swp
+#vim backup files
+*~
 
 # Disable local developer settings
 local_settings.py
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7cf83b16820ded2b91b06faef75aad4f0645f8c5..8cfd55f3ec6c0d9daf2a9017bd6295d33d66b10d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -19,4 +19,4 @@ test:
          - cd smash
          - python manage.py makemigrations web && python manage.py migrate
          - coverage run --source web manage.py test
-         - coverage report -m
+         - coverage report -m --omit="*/test*,*/migrations*"
diff --git a/requirements.txt b/requirements.txt
index fa5a7c14be038ab020a18cf2c7e4201737d76b11..67644e195dd3578eaeba9c357afff56d394170f0 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -8,4 +8,8 @@ python-docx==0.8.6
 django-cleanup==0.4.2
 django_cron==0.5.0
 django-two-factor-auth==1.6.1
-nexmo
\ No newline at end of file
+nexmo
+django-excel==0.0.9
+pyexcel-xls==0.5.0
+pyexcel==0.5.3
+
diff --git a/smash/web/api_views/appointment.py b/smash/web/api_views/appointment.py
index 8945d166e824ceb7e8bf40396273b77194ac04c3..db8122ed6b31d7e0fb2438b0988e1c3af7c9af63 100644
--- a/smash/web/api_views/appointment.py
+++ b/smash/web/api_views/appointment.py
@@ -1,8 +1,10 @@
 import traceback
+from datetime import datetime
 
 from django.contrib.auth.decorators import login_required
 from django.http import JsonResponse
 from django.urls import reverse
+from django.utils import timezone
 
 from web.models import Appointment
 from web.views import e500_error
@@ -29,9 +31,11 @@ def get_appointments(request, type, min_date, max_date):
         raise TypeError("Unknown query type: " + type)
 
     if min_date is not None:
+        min_date = datetime.strptime(min_date, "%Y-%m-%d").replace(tzinfo=timezone.now().tzinfo)
         result = result.filter(datetime_when__gt=min_date)
 
     if max_date is not None:
+        max_date = datetime.strptime(max_date, "%Y-%m-%d").replace(tzinfo=timezone.now().tzinfo)
         result = result.filter(datetime_when__lt=max_date)
     return result.order_by("datetime_when")
 
@@ -57,12 +61,12 @@ def appointments(request, type):
 
         sliced_subjects = all_appointments[start:(start + length)]
 
-        appointments = sliced_subjects
+        result_appointments = sliced_subjects
 
         count_filtered = all_appointments.count()
 
         data = []
-        for appointment in appointments:
+        for appointment in result_appointments:
             data.append(serialize_appointment(appointment))
 
         return JsonResponse({
diff --git a/smash/web/api_views/subject.py b/smash/web/api_views/subject.py
index 8f0161dd65b4aba72e97662896659431a4e0029a..df1aa3535a35b36a152bafdd782964ae0698c911 100644
--- a/smash/web/api_views/subject.py
+++ b/smash/web/api_views/subject.py
@@ -10,25 +10,25 @@ from web.views.subject import SUBJECT_LIST_GENERIC, SUBJECT_LIST_NO_VISIT, SUBJE
 
 @login_required
 def cities(request):
-    subjects = Subject.objects.filter(city__isnull=False).values_list('city').distinct()
+    result_subjects = Subject.objects.filter(city__isnull=False).values_list('city').distinct()
     return JsonResponse({
-        "cities": [x[0] for x in subjects]
+        "cities": [x[0] for x in result_subjects]
     })
 
 
 @login_required
 def countries(request):
-    subjects = Subject.objects.filter(country__isnull=False).values_list('country').distinct()
+    result_subjects = Subject.objects.filter(country__isnull=False).values_list('country').distinct()
     return JsonResponse({
-        "countries": [x[0] for x in subjects]
+        "countries": [x[0] for x in result_subjects]
     })
 
 
 @login_required
 def referrals(request):
-    subjects = Subject.objects.filter(referral__isnull=False).values_list('referral').distinct()
+    result_subjects = Subject.objects.filter(referral__isnull=False).values_list('referral').distinct()
     return JsonResponse({
-        "referrals": [x[0] for x in subjects]
+        "referrals": [x[0] for x in result_subjects]
     })
 
 
@@ -135,12 +135,12 @@ def subjects(request, type):
         filtered_subjects = get_subjects_filtered(ordered_subjects, filters)
         sliced_subjects = filtered_subjects[start:(start + length)]
 
-        subjects = sliced_subjects
+        result_subjects = sliced_subjects
 
         count_filtered = filtered_subjects.count()
 
         data = []
-        for subject in subjects:
+        for subject in result_subjects:
             data.append(serialize_subject(subject))
 
         return JsonResponse({
diff --git a/smash/web/static/css/export.css b/smash/web/static/css/export.css
new file mode 100644
index 0000000000000000000000000000000000000000..ffab23233d813aab070b92753890709a998839ed
--- /dev/null
+++ b/smash/web/static/css/export.css
@@ -0,0 +1,9 @@
+.cell {
+    display: table-cell;
+    border-bottom: 1px solid black;
+    border: 1px solid #BBBBBB;
+    padding:4px;
+    text-align: center;
+    vertical-align: middle;
+
+}
diff --git a/smash/web/templates/export/index.html b/smash/web/templates/export/index.html
index b1813ec7f47d6d675a61a633580272169aa20250..a4e8aef298bbe802d4997a9f54f325ca03b8d0c5 100644
--- a/smash/web/templates/export/index.html
+++ b/smash/web/templates/export/index.html
@@ -3,6 +3,7 @@
 
 {% block styles %}
     {{ block.super }}
+    <link rel="stylesheet" href="{% static 'css/export.css' %}">
 {% endblock styles %}
 
 {% block ui_active_tab %}'export'{% endblock ui_active_tab %}
@@ -18,15 +19,21 @@
 {% block maincontent %}
 
     <div>
-        <a href="{% url 'web.views.export_to_csv2' 'subjects' %}" class="btn btn-app">
-            <i class="fa fa-download"></i>
-            Subjects
-        </a>
-        <br/>
-        <a href="{% url 'web.views.export_to_csv2' 'appointments' %}" class="btn btn-app">
-            <i class="fa fa-download"></i>
-            Appointments
-        </a>
+        <h3>Subjects</h3>
+        <ul>
+            <li><a href="{% url 'web.views.export_to_excel' 'subjects' %}"><i class="fa fa-file-excel-o"></i> XLS -
+                Excel</a>
+            </li>
+            <li><a href="{% url 'web.views.export_to_excel' 'appointments' %}"><i class="fa fa-file-text-o"></i> CSV -
+                Text based</a></li>
+        </ul>
+        <h3>Appointments</h3>
+        <ul>
+            <li><a href="{% url 'web.views.export_to_csv' 'subjects' %}"><i class="fa fa-file-excel-o"></i> XLS -
+                Excel</a></li>
+            <li><a href="{% url 'web.views.export_to_csv' 'appointments' %}"><i class="fa fa-file-text-o"></i> CSV -
+                Text based</a></li>
+        </ul>
     </div>
 
     <div class="box-body">
diff --git a/smash/web/templates/visits/add.html b/smash/web/templates/visits/add.html
index 9e03dbec7d16943bfdcbca5cb129b6f1f25d76d4..749641be57b7d9c1e4160a5d7457fff0cbfa5fed 100644
--- a/smash/web/templates/visits/add.html
+++ b/smash/web/templates/visits/add.html
@@ -25,12 +25,6 @@
         <a href="{% url 'web.views.visits' %}" class="btn btn-block btn-default">Cancel</a>
     </div>
 
-    {% comment %}
-    <div class="box-header with-border">
-        <h3 class="box-title">Details of a visit</h3>
-    </div>
-    {% endcomment %}
-
     <form method="post" action="" class="form-horizontal">
         {% csrf_token %}
 
diff --git a/smash/web/tests/test_view_appointments.py b/smash/web/tests/test_view_appointments.py
index e32a1b54a167a1aeaf9eb19da20b4a8484d91b88..8caa43d8487a125a9956f044d522e9b4f40dbc0f 100644
--- a/smash/web/tests/test_view_appointments.py
+++ b/smash/web/tests/test_view_appointments.py
@@ -81,10 +81,14 @@ class AppointmentsViewTests(LoggedInTestCase):
         form_subject = SubjectEditForm(instance=subject, prefix="subject")
         form_data = {}
         for key, value in form_appointment.initial.items():
-            if value is not None:
+            if isinstance(value, datetime.datetime):
+                form_data['appointment-{}'.format(key)] = value.strftime('%Y-%m-%d %H:%M')
+            elif value is not None:
                 form_data['appointment-{}'.format(key)] = value
         for key, value in form_subject.initial.items():
-            if value is not None:
+            if isinstance(value, datetime.datetime):
+                form_data['subject-{}'.format(key)] = value.strftime('%Y-%m-%d %H:%M')
+            elif value is not None:
                 form_data['subject-{}'.format(key)] = value
         form_data["appointment-status"] = Appointment.APPOINTMENT_STATUS_FINISHED
 
diff --git a/smash/web/tests/test_view_export.py b/smash/web/tests/test_view_export.py
new file mode 100644
index 0000000000000000000000000000000000000000..f15c2cf439a9012999ff91ef88a9fc1e928a0679
--- /dev/null
+++ b/smash/web/tests/test_view_export.py
@@ -0,0 +1,27 @@
+# coding=utf-8
+from django.urls import reverse
+
+from functions import create_subject, create_appointment
+from . import LoggedInTestCase
+
+
+class TestExportView(LoggedInTestCase):
+    def test_export_subjects_to_csv(self):
+        create_subject()
+        response = self.client.get(reverse('web.views.export_to_csv', kwargs={'data_type': "subjects"}))
+        self.assertEqual(response.status_code, 200)
+
+    def test_export_appointments_to_csv(self):
+        create_appointment()
+        response = self.client.get(reverse('web.views.export_to_csv', kwargs={'data_type': "appointments"}))
+        self.assertEqual(response.status_code, 200)
+
+    def test_export_subjects_to_excel(self):
+        create_subject()
+        response = self.client.get(reverse('web.views.export_to_excel', kwargs={'data_type': "subjects"}))
+        self.assertEqual(response.status_code, 200)
+
+    def test_export_appointments_to_excel(self):
+        create_appointment()
+        response = self.client.get(reverse('web.views.export_to_excel', kwargs={'data_type': "appointments"}))
+        self.assertEqual(response.status_code, 200)
diff --git a/smash/web/urls.py b/smash/web/urls.py
index 332b57008700a272e3962fbc9ce23eceffa4bb75..a2e1a0191019f89ae7f1db70d641c63c9e2fe171 100644
--- a/smash/web/urls.py
+++ b/smash/web/urls.py
@@ -160,7 +160,8 @@ urlpatterns = [
     ####################
 
     url(r'^export$', views.export.export, name='web.views.export'),
-    url(r'^export/(?P<type>[A-z]+)$', views.export.export_to_csv2, name='web.views.export_to_csv2'),
+    url(r'^export/csv/(?P<data_type>[A-z]+)$', views.export.export_to_csv, name='web.views.export_to_csv'),
+    url(r'^export/xls/(?P<data_type>[A-z]+)$', views.export.export_to_excel, name='web.views.export_to_excel'),
 
     ####################
     #       CONFIGURATION     #
diff --git a/smash/web/views/export.py b/smash/web/views/export.py
index 6f98432d6a056091e83a53173d503d0692290f66..359386c2552b4bd0c7e8afd46bb2353beba5917e 100644
--- a/smash/web/views/export.py
+++ b/smash/web/views/export.py
@@ -1,6 +1,7 @@
 # coding=utf-8
 import csv
 
+import django_excel as excel
 from django.contrib.auth.decorators import login_required
 from django.http import HttpResponse
 
@@ -10,23 +11,43 @@ from ..models import Subject, Appointment
 
 
 @login_required
-def export_to_csv2(request, type="subjects"):
+def export_to_csv(request, data_type="subjects"):
     # Create the HttpResponse object with the appropriate CSV header.
     response = HttpResponse(content_type='text/csv')
-    response['Content-Disposition'] = 'attachment; filename="' + type + '-' + get_today_midnight_date().strftime(
+    response['Content-Disposition'] = 'attachment; filename="' + data_type + '-' + get_today_midnight_date().strftime(
         "%Y-%m-%d") + '.csv"'
 
+    if data_type == "subjects":
+        data = get_subjects_as_array()
+    elif data_type == "appointments":
+        data = get_appointments_as_array()
+    else:
+        return e500_error(request)
     writer = csv.writer(response, quotechar=str(u'"'), quoting=csv.QUOTE_ALL)
-    if type == "subjects":
-        write_subjects_to_csv(writer)
-    elif type == "appointments":
-        write_appointments_to_csv(writer)
+    for row in data:
+        writer.writerow([s.encode("utf-8") for s in row])
+
+    return response
+
+
+@login_required
+def export_to_excel(request, data_type="subjects"):
+    filename = data_type + '-' + get_today_midnight_date().strftime("%Y-%m-%d") + ".xls"
+    if data_type == "subjects":
+        data = get_subjects_as_array()
+    elif data_type == "appointments":
+        data = get_appointments_as_array()
     else:
         return e500_error(request)
+
+    response = excel.make_response_from_array(data, 'xls', file_name=filename)
+    response['Content-Disposition'] = 'attachment; filename="' + filename + '"'
+
     return response
 
 
-def write_subjects_to_csv(writer):
+def get_subjects_as_array():
+    result = []
     subject_fields = []
     for field in Subject._meta.fields:
         if field.name != "ID":
@@ -36,17 +57,22 @@ def write_subjects_to_csv(writer):
     for field in subject_fields:
         field_names.append(field.verbose_name)
 
-    writer.writerow(field_names)
+    result.append(field_names)
 
     subjects = Subject.objects.order_by('-last_name')
     for subject in subjects:
         row = []
         for field in subject_fields:
-            row.append(getattr(subject, field.name))
-        writer.writerow([unicode(s).replace("\n", ";").replace("\r", ";").encode("utf-8") for s in row])
+            cell = getattr(subject, field.name)
+            if cell is None:
+                cell = ""
+            row.append(cell)
+        result.append([unicode(s).replace("\n", ";").replace("\r", ";") for s in row])
+    return result
 
 
-def write_appointments_to_csv(writer):
+def get_appointments_as_array():
+    result = []
     appointments_fields = []
     for field in Appointment._meta.fields:
         if field.name != "visit" and field.name != "id" and \
@@ -58,20 +84,24 @@ def write_appointments_to_csv(writer):
     for field in appointments_fields:
         field_names.append(field.verbose_name)
 
-    writer.writerow(field_names)
+    result.append(field_names)
 
     appointments = Appointment.objects.order_by('-datetime_when')
 
     for appointment in appointments:
-        row = [appointment.visit.subject.nd_number, appointment.visit.subject.last_name,
-               appointment.visit.subject.first_name, appointment.visit.follow_up_title()]
+        if appointment.visit is not None:
+            row = [appointment.visit.subject.nd_number, appointment.visit.subject.last_name,
+                   appointment.visit.subject.first_name, appointment.visit.follow_up_title()]
+        else:
+            row = ["---", "---", "---", "---"]
         for field in appointments_fields:
             row.append(getattr(appointment, field.name))
         type_string = ""
-        for type in appointment.appointment_types.all():
-            type_string += type.code + ","
+        for appointment_type in appointment.appointment_types.all():
+            type_string += appointment_type.code + ","
         row.append(type_string)
-        writer.writerow([unicode(s).replace("\n", ";").replace("\r", ";").encode("utf-8") for s in row])
+        result.append([unicode(s).replace("\n", ";").replace("\r", ";") for s in row])
+    return result
 
 
 def export(request):
diff --git a/smash/web/views/notifications.py b/smash/web/views/notifications.py
index 0d47a354c00a01796a5a656f2543a5cdf715ddf7..6a580bc56a8768fc0c11dc3443690296dae55915 100644
--- a/smash/web/views/notifications.py
+++ b/smash/web/views/notifications.py
@@ -1,5 +1,6 @@
 # coding=utf-8
 import datetime
+from django.utils import timezone
 
 from django.contrib.auth.models import User, AnonymousUser
 from django.db.models import Count, Case, When
@@ -239,6 +240,6 @@ def get_filter_locations(user):
 
 
 def get_today_midnight_date():
-    today = datetime.datetime.now()
-    today_midnight = datetime.datetime(today.year, today.month, today.day)
+    today = timezone.now()
+    today_midnight = datetime.datetime(today.year, today.month, today.day, tzinfo=today.tzinfo)
     return today_midnight