diff --git a/main.go b/main.go
index 6341d5c04abc655822a8a579eed64c76ef6ee218..fcdb1c96e6e847a2e91c5e125a12678f3b545ca3 100644
--- a/main.go
+++ b/main.go
@@ -5,6 +5,7 @@ import (
 	"log"
 	"net/http"
 	"os"
+	"regexp"
 
 	"github.com/gofiber/fiber/v2"
 	"github.com/gofiber/fiber/v2/middleware/filesystem"
@@ -14,8 +15,13 @@ import (
 //go:embed public/*
 var public embed.FS
 
+const pattern = `^(@?\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2})|([+-]\d+([.,]\d+)?[mhdy]{1}(\s[xi]\d+([.,]\d+)?)?)$`
+
 func main() {
 	_ = godotenv.Load(".env")
+	if _, err := os.Stat(os.Getenv("FAKETIME_TIMESTAMP_FILE")); os.IsNotExist(err) {
+		os.WriteFile(os.Getenv("FAKETIME_TIMESTAMP_FILE"), []byte("0d\n"), 0644)
+	}
 	app := fiber.New()
 	app.Use("/", filesystem.New(filesystem.Config{
 		Root:       http.FS(public),
@@ -27,8 +33,11 @@ func main() {
 		return c.SendFile(os.Getenv("FAKETIME_TIMESTAMP_FILE"))
 	})
 	app.Post("/api/timestamp", func(c *fiber.Ctx) error {
-		value := []byte(c.FormValue("value"))
-		return os.WriteFile(os.Getenv("FAKETIME_TIMESTAMP_FILE"), value, 0644)
+		if matched, _ := regexp.MatchString(pattern, c.FormValue("value")); matched {
+			value := []byte(c.FormValue("value"))
+			return os.WriteFile(os.Getenv("FAKETIME_TIMESTAMP_FILE"), value, 0644)
+		}
+		return fiber.NewError(fiber.StatusBadRequest, "Malformed time string")
 	})
 	log.Fatal(app.Listen(os.Getenv("HTTP_ADDR")))
 }
diff --git a/public/index.html b/public/index.html
index e2e89472a3e35d3bee2703290b46611795bcc7ec..7b1f018319b2f2364c28f1dedb6919f1b942d544 100644
--- a/public/index.html
+++ b/public/index.html
@@ -1,8 +1,37 @@
 <!DOCTYPE html>
 <head>
     <link href="style.css" rel="stylesheet" type="text/css">
+    <script>
+        function getTimestamp() {
+            document.getElementById("error").innerHTML = "";
+            fetch('/api/timestamp')
+                .then(response => response.text())
+                .then(value => document.getElementById("timestamp").value = value);
+        }
+        function setTimestamp(event) {
+            event.preventDefault();
+            let formData = new FormData();
+            formData.append("value", document.getElementById("timestamp").value);
+            fetch('/api/timestamp', {
+                method: 'POST',
+                body: formData
+            })
+                .then(response => response.status == 200 ? "" : response.text())
+                .then(text => document.getElementById("error").innerHTML = text);
+        }
+    </script>
 </head>
-<body>
-    <h1>{{.Title}}</h1>
+<body onload="getTimestamp()">
+    <form onsubmit="setTimestamp(event)">
+        <input id="timestamp" type="text" name="timestamp">
+        <input type="submit" value="Submit">
+        <input type="reset" value="Reset" onclick="getTimestamp()">
+    </form>
+    <p id="error"></p>
+    <pre>
+absolute: YYYY-MM-DD hh:mm:ss
+start at: @YYYY-MM-DD hh:mm:ss
+relative: (+|-)120(m,h,d,y)
+    </pre>
 </body>
 </html>
diff --git a/public/style.css b/public/style.css
index 69fad6da5c44f553cbf72e1feee429a71e8ffebb..333b2d000f5ecee789b5837a63bedeab772589c8 100644
--- a/public/style.css
+++ b/public/style.css
@@ -1,3 +1,7 @@
 html {
-    background-color: red;
+    background-color: white;
+}
+
+#error {
+    color: red;
 }
diff --git a/test/docker/dropwizard/Dockerfile b/test/docker/dropwizard/Dockerfile
index 32dac7b7ce33884fcd949f7b2b32475870c89289..a351aa9974297040942b90f5519b1dddad78a200 100644
--- a/test/docker/dropwizard/Dockerfile
+++ b/test/docker/dropwizard/Dockerfile
@@ -12,6 +12,7 @@ FROM openjdk:17-jdk-slim
 ENV DEBIAN_FRONTEND noninteractive
 RUN apt-get update && apt-get install libfaketime
 ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1
+ENV FAKETIME_DONT_RESET=1
 ENV FAKETIME_CACHE_DURATION=1
 ENV FAKETIME_DONT_FAKE_MONOTONIC=1
 ENV FAKETIME_TIMESTAMP_FILE=/var/lib/faketime/faketimerc
diff --git a/test/docker/java/Dockerfile b/test/docker/java/Dockerfile
index 6711f8056938334aeb2163434734413bb6708422..618984052b66041c05aa5cbbe3646fcca8415e46 100644
--- a/test/docker/java/Dockerfile
+++ b/test/docker/java/Dockerfile
@@ -2,6 +2,7 @@ FROM openjdk:17-jdk-slim
 ENV DEBIAN_FRONTEND noninteractive
 RUN apt-get update && apt-get install libfaketime
 ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1
+ENV FAKETIME_DONT_RESET=1
 ENV FAKETIME_CACHE_DURATION=1
 ENV FAKETIME_DONT_FAKE_MONOTONIC=1
 ENV FAKETIME_TIMESTAMP_FILE=/var/lib/faketime/faketimerc
diff --git a/test/docker/postgres/Dockerfile b/test/docker/postgres/Dockerfile
index dcf3f88ad201907a07c6a88871f79208582ed270..88187c45198c6f25b9489b57d79e3179250ac30a 100644
--- a/test/docker/postgres/Dockerfile
+++ b/test/docker/postgres/Dockerfile
@@ -3,6 +3,7 @@ FROM postgres:bullseye
 ENV DEBIAN_FRONTEND noninteractive
 RUN apt-get update && apt-get install libfaketime
 ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1
+ENV FAKETIME_DONT_RESET=1
 ENV FAKETIME_CACHE_DURATION=1
 ENV FAKETIME_TIMESTAMP_FILE=/var/lib/faketime/faketimerc
 ENTRYPOINT ["/bin/sh"]