How to Work with Dates in Thymeleaf – 如何在Thymeleaf中处理日期问题

最后修改: 2017年 1月 10日


1. Introduction


Thymeleaf is a Java template engine able to work directly with Spring. For an intro to Thymeleaf and Spring, have a look at this write-up.


Besides these basic functions, Thymeleaf offers us a set of utility objects that will help us perform common tasks in our application.


In this tutorial, we’ll discuss the processing and formatting of the new and old Java Date classes with a handful of features of Thymeleaf 3.0.

在本教程中,我们将讨论新旧JavaDate类的处理和格式化问题,以及Thymeleaf 3.0的一些特性。

2. Maven Dependencies


First, let’s create the configuration to integrate Thymeleaf with Spring into our pom.xml:



The latest versions of thymeleaf and thymeleaf-spring5 can be found on Maven Central. Note that, for a Spring 4 project, the thymeleaf-spring4 library must be used instead of thymeleaf-spring5.

thymeleafthymeleaf-spring5的最新版本可以在Maven中心找到。请注意,对于Spring 4项目,必须使用thymeleaf-spring4库而不是thymeleaf-spring5

Moreover, in order to work with new Java 8 Date classes, we’ll need to add another dependency to our pom.xml:

此外,为了与新的Java 8 Date 类一起工作,我们需要在pom.xml中添加另一个依赖项。


The thymeleaf extras is an optional module, fully supported by the official Thymeleaf team, that was created for compatibility with the Java 8 Time API. It adds a #temporals object to the Context as a utility object processor during expression evaluations. This means that it can be used to evaluate expressions in Object-Graph Navigation Language (OGNL) and Spring Expression Language (SpringEL).

thymeleaf extras是一个可选的模块,由Thymeleaf官方团队完全支持,它是为了与Java 8 Time API兼容而创建。它向Context添加了一个#temporals对象,作为表达式评估期间的实用对象处理器。这意味着它可以用来评估对象-图形导航语言(OGNL)和Spring表达式语言(SpringEL)中的表达式。

3. Old and New: java.util and java.time

3.新与旧 java.utiljava.time

The Time package is a new date, time, and calendar API for the Java SE platform. The main difference between this new API and the old legacy Date API is that the new API distinguishes between machine and human views of a timeline. The machine view reveals a sequence of integral values relative to the epoch, whereas the human view reveals a set of fields (for example, year, month, and day).

Time包是Java SE平台的一个新的日期、时间和日历API。这个新的API与旧的传统Date API之间的主要区别是,新的API区分了时间线的机器视图和人类视图。机器视图显示了相对于epoch的积分值序列,而人类视图显示了一组字段(例如,年、月、日)。

To work with the new Time package, we need to configure our template engine to use the new Java8TimeDialect:


private ISpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
    SpringTemplateEngine engine = new SpringTemplateEngine();
    engine.addDialect(new Java8TimeDialect());
    return engine;

This will add the #temporals object similar to the ones in the Standard Dialect, allowing the formatting and creation of Temporal objects from Thymeleaf templates.


In order to test the processing of new and old classes, we’ll create the following variables and add them as model objects to our controller class:


model.addAttribute("standardDate", new Date());

Now, we’re ready to use Thymeleaf’s Expression and Temporals utility objects.


3.1. Format Dates


The first function that we want to cover is the formatting of a Date object (which is added to the Spring model parameters). We’ll use the ISO8601 format:


<h1>Format ISO</h1>
<p th:text="${#dates.formatISO(standardDate)}"></p>
<p th:text="${#temporals.formatISO(localDateTime)}"></p>
<p th:text="${#temporals.formatISO(localDate)}"></p>
<p th:text="${#temporals.formatISO(timestamp)}"></p>

No matter how our Date was set on the back-end side, it will be displayed in Thymeleaf according to the selected standard. The standardDate is going to be processed by the #dates utility. The new LocalDateTime, LocalDate, and Instant classes are going to be processed by the #temporals utility.


Moreover, if we want to set the format manually, we can do it by using:


<h1>Format manually</h1>
<p th:text="${#dates.format(standardDate, 'dd-MM-yyyy HH:mm')}"></p>
<p th:text="${#temporals.format(localDateTime, 'dd-MM-yyyy HH:mm')}"></p>
<p th:text="${#temporals.format(localDate, 'MM-yyyy')}"></p>

As we can observe, we cannot process the Instant class with #temporals.format(…) — it will result in UnsupportedTemporalTypeException. Moreover, formatting the LocalDate is only possible if we specify only the particular date fields, skipping the time fields.


Let’s see the final result:



3.2. Obtain Specific Date Fields


In order to obtain the specific fields of the java.util.Date class, we should use the following utility objects:



For the new java.time package, we should stick with #temporals utilities:



Let’s look at a few examples. First, let’s show today’s day of the week:


<h1>Show only which day of a week</h1>
<p th:text="${}"></p>
<p th:text="${}"></p>
<p th:text="${}"></p>

Next, let’s show the name of the weekday:


<h1>Show the name of the week day</h1>
<p th:text="${#dates.dayOfWeekName(standardDate)}"></p>
<p th:text="${#temporals.dayOfWeekName(localDateTime)}"></p>
<p th:text="${#temporals.dayOfWeekName(localDate)}"></p>

Finally, let’s show the current second of the day:


<h1>Show the second of the day</h1>
<p th:text="${#dates.second(standardDate)}"></p>
<p th:text="${#temporals.second(localDateTime)}"></p>

Please note that in order to work with time parts, we would need to use LocalDateTime, as LocalDate will throw an error.


4. How to Use a Date-Picker in a Form


Let’s look at how to use a date-picker to submit a Date value from a Thymeleaf form.


First, let’s create a Student class with a Date attribute:


public class Student implements Serializable {
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birthDate;

The @DateTimeFormat annotation declares that the birthDate field should be formatted as a Date.

@DateTimeFormat注解声明birthDate字段应被格式化为a Date

Next, we’ll create a Thymeleaf form to submit a Date input:


<form th:action="@{/saveStudent}" method="post" th:object="${student}">
        <label for="student-birth-date">Date of birth:</label>
        <input type="date" th:field="${student.birthDate}" id="student-birth-date"/>
        <button type="submit" class="button">Submit</button>

When we submit the form, a controller will intercept the Student object mapped in the form with th:object attribute. Also, the th:field attribute binds the input value with the birthDate field.


Now, let’s create a controller to intercept the POST request:


@RequestMapping(value = "/saveStudent", method = RequestMethod.POST)
public String saveStudent(Model model, @ModelAttribute("student") Student student) {
    model.addAttribute("student", student);
    return "datePicker/displayDate.html";

After we submit the form, we’ll display the birthDate value on another page with the pattern dd/MM/yyyy:


<h1>Student birth date</h1>
<p th:text="${#dates.format(student.birthDate, 'dd/MM/yyyy')}"></p>

The result shows our form with a date-picker:



After submitting the form, we’ll see the selected date:


display date

5. Conclusion


In this quick tutorial, we discussed Java Date processing features implemented in the Thymeleaf framework, version 3.0.


How to test? Our suggestion is to play with the code in a browser first, then check our existing JUnit tests as well.


Please note that our examples do not cover all available options in Thymeleaf. If you want to learn about all types of utilities, then take a look at our article covering Spring and Thymeleaf Expressions.

请注意,我们的例子并没有涵盖Thymeleaf的所有可用选项。如果您想了解所有类型的实用程序,那么请看我们的文章,内容包括Spring和Thymeleaf Expressions

The full implementation of this tutorial can be found over on GitHub.