Working with dates in Thymeleaf

April 25, 2020 No comments Thymeleaf Date Calendar

1. Introduction

Thymeleaf is a template engine based on Java created for processing XHTML, XML, JS, CSS, and other web documents. Thymeleaf comes with lots of features. In this article, we are going to present utility methods used for processing dates.

2. Maven dependencies

Let's start with maven dependencies required for Thymeleaf projects. Thymeleaf is mainly used with Spring and Spring Boot applications so our dependencies consider that kind of configuration.

We need the following dependencies to start using Thymeleaf in Spring Boot applications:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

To start working with new Java 8 Date classes, we will add the following dependency to our pom.xml:

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>

The latest versions of the above dependencies could be found using the following links:

3. Spring Web Controller

To present how new and old utility methods for processing date works we created a simple Spring Controller class that will serve date.html template on the root context. We also add several variables to our template model to have some example dates ready to process and format.

package com.frontbackend.thymeleaf.extras.java8time.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;

@Controller
public class DatesController {

    @GetMapping("/")
    public String dates(Model model) {
        model.addAttribute("date", new Date());
        model.addAttribute("localDateTime", LocalDateTime.now());
        model.addAttribute("localDate", LocalDate.now());
        model.addAttribute("java8Instant", Instant.now());

        return "dates";
    }
}

4. Processing dates with #dates and #temporals utility classes

Thymeleaf comes with many extra features that could be added to our project by simply using special maven dependencies. Additional extras are created and supported by the Thymeleaf team to be compatible with the newest versions of Java.

By adding thymeleaf-extras-java8time dependency we can start using Java 8 Time API right away. The new utility class #temporals will appear in context and it will be available to use in Thymeleaf expressions.

To test utility methods we use the following Thymeleaf template:

<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>Spring Boot Thymeleaf Application - Working with dates</title>
</head>
<body>

<h2>Format ISO</h2>
<p th:text="${#dates.formatISO(date)}"></p>
<p th:text="${#temporals.formatISO(localDate)}"></p>
<p th:text="${#temporals.formatISO(localDateTime)}"></p>
<p th:text="${#temporals.formatISO(java8Instant)}"></p>

<h1>Format dates</h1>
<p th:text="${#dates.format(date, 'dd.MM.yyyy')}"></p>
<p th:text="${#temporals.format(localDate, 'MM-yyyy')}"></p>
<p th:text="${#temporals.format(localDateTime, 'dd-MM-yyyy HH:mm')}"></p>
<p th:text="${#temporals.format(java8Instant, 'dd-MM-yyyy HH:mm:ss')}"></p>
<p th:text="${#temporals.format(localDateTime, 'dd-MMMM-yyyy', new java.util.Locale('en', 'EN'))}">
<p th:text="${#temporals.format(localDateTime, 'dd-MMMM-yyyy', new java.util.Locale('es', 'ES'))}">
<p th:text="${#temporals.format(localDateTime, 'dd-MMMM-yyyy', new java.util.Locale('fr', 'FR'))}">

<h2>Get date fields</h2>
<table style="width:300px">
    <tr>
        <td>Date</td>
        <td>LocalDateTime</td>
    </tr>
    <tr>
        <td>
            <p th:text="${#dates.day(date)}"></p>
            <p th:text="${#dates.month(date)}"></p>
            <p th:text="${#dates.monthName(date)}"></p>
            <p th:text="${#dates.monthNameShort(date)}"></p>
            <p th:text="${#dates.year(date)}"></p>
            <p th:text="${#dates.dayOfWeek(date)}"></p>
            <p th:text="${#dates.dayOfWeekName(date)}"></p>
            <p th:text="${#dates.dayOfWeekNameShort(date)}"></p>
            <p th:text="${#dates.hour(date)}"></p>
            <p th:text="${#dates.minute(date)}"></p>
            <p th:text="${#dates.second(date)}"></p>
        </td>
        <td>
            <p th:text="${#temporals.day(localDateTime)}"></p>
            <p th:text="${#temporals.month(localDateTime)}"></p>
            <p th:text="${#temporals.monthName(localDateTime)}"></p>
            <p th:text="${#temporals.monthNameShort(localDateTime)}"></p>
            <p th:text="${#temporals.year(localDateTime)}"></p>
            <p th:text="${#temporals.dayOfWeek(localDateTime)}"></p>
            <p th:text="${#temporals.dayOfWeekName(localDateTime)}"></p>
            <p th:text="${#temporals.dayOfWeekNameShort(localDateTime)}"></p>
            <p th:text="${#temporals.hour(localDateTime)}"></p>
            <p th:text="${#temporals.minute(localDateTime)}"></p>
            <p th:text="${#temporals.second(localDateTime)}"></p>
        </td>
    </tr>
</table>

</body>
</html>

This is the final result we'll see in the browser: Thymeleaf working with dates

To work with LocalDateTime, LocalDate and Instant we need to use #temporals utility. For standard Dates there is built-in #dates utility available without additional dependencies.

Notice we could display date using specific locale, for example below piece of HTML:

<p th:text="${#temporals.format(localDateTime, 'dd-MMMM-yyyy', new java.util.Locale('en', 'EN'))}">
<p th:text="${#temporals.format(localDateTime, 'dd-MMMM-yyyy', new java.util.Locale('es', 'ES'))}">
<p th:text="${#temporals.format(localDateTime, 'dd-MMMM-yyyy', new java.util.Locale('fr', 'FR'))}">

will be rendered to:

25-April-2020
25-abril-2020
25-avril-2020

It is important to remember that in order to work with time parts we need to have an object that supports time like for example LocalDateTime.

The following expression will try to get a SecondOfMinute part of the LocalDate object that does not support the time:

<p th:text="${#temporals.second(localDate)}"></p>

This will cause the following exception in runtime:

java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: SecondOfMinute
    at java.time.LocalDate.get0(LocalDate.java:680) ~[na:1.8.0_252]
    at java.time.LocalDate.get(LocalDate.java:622) ~[na:1.8.0_252]

5. Conclusion

In this article, we presented date processing methods using Thymeleaf utility classes. For objects presented in Java 8 like LocalDate, LocalDateTime, Instant we need to add special dependency thymeleaf-extras-java8time that include #temporals utility ready to be used in the Thymeleaf templates.

The code used in this tutorial can be found in the GitHub project.

{{ message }}

{{ 'Comments are closed.' | trans }}