Java
LocalDateTime
JacksonMapper
Deserialize
Java 8

Deserialize Java 8 LocalDateTime with JacksonMapper

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

LocalDateTime is a common type in modern Java applications, but Jackson does not deserialize it correctly unless the mapper knows about the Java time module. Once that module is registered, ISO-8601 strings usually work out of the box, and custom patterns can be added when incoming JSON uses a different format.

Why Default Jackson Setup Fails

LocalDateTime is part of java.time, not the older java.util.Date API. A plain ObjectMapper can handle many basic Java types, but Java 8 time classes need the jackson-datatype-jsr310 module.

Without that module, code like this often fails:

java
1import com.fasterxml.jackson.databind.ObjectMapper;
2
3public class Demo {
4    public static void main(String[] args) throws Exception {
5        ObjectMapper mapper = new ObjectMapper();
6        String json = "{\"createdAt\":\"2026-03-11T09:30:00\"}";
7
8        AuditEvent event = mapper.readValue(json, AuditEvent.class);
9        System.out.println(event.createdAt);
10    }
11
12    public static class AuditEvent {
13        public java.time.LocalDateTime createdAt;
14    }
15}

Jackson sees a string, but it does not yet know how to turn that string into a LocalDateTime.

Register the Java Time Module

The standard fix is to register JavaTimeModule on the mapper.

java
1import com.fasterxml.jackson.databind.ObjectMapper;
2import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
3
4public class Demo {
5    public static void main(String[] args) throws Exception {
6        ObjectMapper mapper = new ObjectMapper();
7        mapper.registerModule(new JavaTimeModule());
8
9        String json = "{\"createdAt\":\"2026-03-11T09:30:00\"}";
10        AuditEvent event = mapper.readValue(json, AuditEvent.class);
11
12        System.out.println(event.createdAt);
13    }
14
15    public static class AuditEvent {
16        public java.time.LocalDateTime createdAt;
17    }
18}

If the JSON uses a normal ISO-8601 timestamp without a zone offset, this is usually enough.

Use a Domain Class With Explicit Format When Needed

If the input format is not the default ISO shape, annotate the field with @JsonFormat.

java
1import com.fasterxml.jackson.annotation.JsonFormat;
2import java.time.LocalDateTime;
3
4public class AuditEvent {
5    public String message;
6
7    @JsonFormat(pattern = "yyyy/MM/dd HH:mm:ss")
8    public LocalDateTime createdAt;
9}

Then JSON like "2026/03/11 09:30:00" can be parsed correctly once the mapper still has JavaTimeModule registered.

Full Example With Serialization and Deserialization

It is common to configure both directions together so the same mapper reads and writes the same date-time shape.

java
1import com.fasterxml.jackson.databind.ObjectMapper;
2import com.fasterxml.jackson.databind.SerializationFeature;
3import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
4
5import java.time.LocalDateTime;
6
7public class JacksonTimeExample {
8    public static void main(String[] args) throws Exception {
9        ObjectMapper mapper = new ObjectMapper();
10        mapper.registerModule(new JavaTimeModule());
11        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
12
13        AuditEvent event = new AuditEvent();
14        event.message = "created";
15        event.createdAt = LocalDateTime.of(2026, 3, 11, 9, 30, 0);
16
17        String json = mapper.writeValueAsString(event);
18        System.out.println(json);
19
20        AuditEvent decoded = mapper.readValue(json, AuditEvent.class);
21        System.out.println(decoded.createdAt);
22    }
23
24    public static class AuditEvent {
25        public String message;
26        public LocalDateTime createdAt;
27    }
28}

Disabling WRITE_DATES_AS_TIMESTAMPS is especially useful if you also serialize the same type and want readable string output instead of array-like timestamp representations.

When a Custom Deserializer Makes Sense

Use a custom deserializer only when @JsonFormat is not enough. For example, you may receive several possible input patterns, or you may need validation logic tied to the field.

That is a specialized case. Most applications do not need a custom deserializer for LocalDateTime; they just need the Java time module and, sometimes, a pattern annotation.

Time Zone Awareness Matters

LocalDateTime deliberately has no time zone or offset. That is correct only when the JSON value is also meant to be zone-free. If the incoming data represents an absolute moment such as 2026-03-11T09:30:00Z, then OffsetDateTime or Instant may be the better domain type.

Choosing the wrong Java type is a common source of "deserialization problems" that are really domain-model problems.

Common Pitfalls

The most common mistake is creating a plain ObjectMapper and forgetting to register JavaTimeModule.

Another issue is using LocalDateTime for values that actually include an offset or represent a globally meaningful timestamp. That loses information even if deserialization technically succeeds.

Developers also sometimes add @JsonFormat but forget the mapper module, assuming the annotation alone is enough. Jackson still needs support for Java time types.

Finally, if you serialize and deserialize with different mapper configurations, your JSON shape can drift and cause subtle failures between services.

Summary

  • 'LocalDateTime support in Jackson requires JavaTimeModule.'
  • ISO-8601 strings usually deserialize correctly once that module is registered.
  • Use @JsonFormat when the incoming JSON uses a custom date-time pattern.
  • Disable timestamp-style serialization if you want stable string output.
  • Choose LocalDateTime only when the value is truly zone-free.

Course illustration
Course illustration

All Rights Reserved.