diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2821735c50c4168df452f06b1db4446250325b46..cc4832b7dde515af24a582777577a085e6d67e32 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,43 +1,63 @@
-before_script:
-  - pip install --user untangle
-
 stages:
 - build
 - test
 - report
 
+variables:
+  GRADLE_OPTS: "-Dorg.gradle.daemon=false"
+  TEST_REPORTS: "/builds/rschoene/eraser/eraser-base/build/reports/tests/test/"
+  JACOCO_REPORT: "/builds/rschoene/eraser/eraser-base/build/reports/jacoco/test/jacocoTestReport.xml"
+
+before_script:
+  - export GRADLE_USER_HOME=`pwd`/.gradle
+
 build:
+  image: gradle:jdk8
   stage: build
   script:
-  - ./gradlew --console=plain assemble
-  retry: 2
-  when: on_success
+    - ./gradlew --console=plain --build-cache assemble
+  cache:
+    key: "$CI_COMMIT_REF_NAME"
+    policy: push
+    paths:
+      - build
+      - .gradle
 
 test:
+  image: gradle:jdk8
   stage: test
   script:
-  - ./gradlew --continue --console=plain test jacocoTestReport
-  retry: 2
-  when: on_success
+    - ./gradlew --continue --console=plain check jacocoTestReport
+  cache:
+    key: "$CI_COMMIT_REF_NAME"
+    policy: pull
+    paths:
+      - build
+      - .gradle
   artifacts:
     when: always
-    # paths:
-    # - $TEST_REPORTS
-    # - $JACOCO_DATA1
-    # - $JACOCO_DATA2
+    paths:
+      - $TEST_REPORTS
+      - $JACOCO_REPORT
 
 coverage:
-  image: python:3.7.1-stretch
+  image: python:3.7.1-alpine
   stage: report
   dependencies:
   - test
   script:
-  # - ./gradlew --continue --console=plain -x test
-  - python2 print-coverage.py
+#    - ./gradlew --continue --console=plain -x test jacocoTestReport
+    - pip install --user untangle
+    - python print-coverage.py
   coverage: "/Covered (\\d{1,3}\\.\\d{2}%) of instructions for all projects\\./"
+  cache:
+    key: "$CI_COMMIT_REF_NAME"
+    policy: pull
+    paths:
+      - build
+      - .gradle
   allow_failure: true
-  when: on_success
   artifacts:
     when: always
-    # paths:
-    # - $COVERAGE_REPORTS
+    paths:
+      - $JACOCO_REPORT
diff --git a/README.md b/README.md
index 447a85398e03ceec5aa75c3edeefddeff8f3a80d..1f690dbf64d9ff6210a61ad8d5e2a0860be48da8 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
+[![pipeline status](https://git-st.inf.tu-dresden.de/rschoene/eraser/badges/master/pipeline.svg)](https://git-st.inf.tu-dresden.de/rschoene/eraser/commits/master)
+[![coverage report](https://git-st.inf.tu-dresden.de/rschoene/eraser/badges/master/coverage.svg)](https://git-st.inf.tu-dresden.de/rschoene/eraser/commits/master)
+
 # ERASER - OpenLicht Knowledge Base
 
 ## Overview
diff --git a/eraser-base/build.gradle b/eraser-base/build.gradle
index 85a65b83c238bbb2b268d54fe3494d6a4f69bc86..e33ec3bede37eafa883466bd32cbd16883e26eba 100644
--- a/eraser-base/build.gradle
+++ b/eraser-base/build.gradle
@@ -32,6 +32,13 @@ run {
     }
 }
 
+test {
+    testLogging {
+        events "passed", "skipped", "failed"
+        exceptionFormat "full"
+    }
+}
+
 jacocoTestReport {
     reports {
         xml.enabled true
diff --git a/eraser-base/src/main/jastadd/Item.jrag b/eraser-base/src/main/jastadd/Item.jrag
index 44bd760f2c5923d3b2b885e77f1d532824488ea0..0da01f65292f82b4056ccf79015348b768f700a5 100644
--- a/eraser-base/src/main/jastadd/Item.jrag
+++ b/eraser-base/src/main/jastadd/Item.jrag
@@ -1,6 +1,8 @@
 aspect ItemHandling {
 
-  private static final java.text.DateFormat DateTimeItem.FORMAT = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
+  private static final java.text.DateFormat DateTimeItem.FORMAT = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS") {{
+    setTimeZone(TimeZone.getTimeZone("UTC"));
+  }};
 
   //--- getStateAsString ---
   syn String Item.getStateAsString();
diff --git a/eraser-base/src/test/resources/tests/ppc3/output.eraser b/eraser-base/src/test/resources/tests/ppc3/output.eraser
index 46b76f0c1dd447ab18282e729dba93e7b277e6f5..414cf9778f02c5e4697e17be4b97da5fb4e38a6b 100644
--- a/eraser-base/src/test/resources/tests/ppc3/output.eraser
+++ b/eraser-base/src/test/resources/tests/ppc3/output.eraser
@@ -2,7 +2,7 @@ Color Item: id="color1" label="a Color Item" state="1,2,3" topic="item/hsb/color
 Contact Item: id="contact1" label="a Contact Item" state="true" topic="item/bool/contact1/state" ;
 Image Item: id="image1" label="an Image Item" state="def" topic="item/str/image1/state" ;
 Location Item: id="location1" label="a Location Item" state="ghi" topic="item/str/location1/state" ;
-DateTime Item: id="datetime1" label="a DateTime Item" state="1970-01-18T21:43:35.826+01:00" topic="item/date/datetime1/state" ;
+DateTime Item: id="datetime1" label="a DateTime Item" state="1970-01-18T20:43:35.826" topic="item/date/datetime1/state" ;
 Item: id="default1" label="a Default Item" state="pqr" topic="item/str/default1/state" ;
 Dimmer Item: id="dimmer1" label="a Dimmer Item" state="123.0" topic="item/double/dimmer1/state" ;
 Player Item: id="player1" label="a Player Item" state="jkl" topic="item/str/player1/state" ;
diff --git a/print-coverage.py b/print-coverage.py
index 00239ab85b7dfd926924cef6c79a0758a22ab3ed..30ee86794382a8e055ce3fa0e0746cd872981b34 100644
--- a/print-coverage.py
+++ b/print-coverage.py
@@ -1,6 +1,8 @@
+import os
 import untangle
+print('Current path: ' + os.path.abspath(os.curdir))
 obj = untangle.parse('eraser-base/build/reports/jacoco/test/jacocoTestReport.xml')
 instructions = [o for o in obj.report.counter if o['type'] == 'INSTRUCTION'][0]
 missed, covered = int(instructions['missed']), int(instructions['covered'])
 # print missed / (missed + covered)
-print 'Covered %.2f%% of instructions for all projects.' % (missed * 100.0 / (missed + covered))
+print('Covered %.2f%% of instructions for all projects.' % (missed * 100.0 / (missed + covered)))