Spring Boot
JSON
Date Formatting
Java
Jackson

Date format in the json output using spring boot

Master System Design with Codemia

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

Introduction

By default, Spring Boot's Jackson serializer converts java.util.Date to a Unix timestamp (milliseconds since epoch) and java.time.LocalDateTime to an array like [2025,9,23,14,30,0]. To get human-readable formats like "2025-09-23T14:30:00", configure the date format either globally in application.properties, per-field with @JsonFormat, or via a custom ObjectMapper bean. The recommended approach for new code is to use java.time classes (LocalDate, LocalDateTime, ZonedDateTime) with the jackson-datatype-jsr310 module, which Spring Boot auto-configures.

The Default Problem

java
1@RestController
2public class EventController {
3    @GetMapping("/event")
4    public Event getEvent() {
5        Event event = new Event();
6        event.setName("Conference");
7        event.setDate(new Date());
8        event.setLocalDate(LocalDate.now());
9        event.setLocalDateTime(LocalDateTime.now());
10        return event;
11    }
12}
13
14// Default JSON output:
15// {
16//   "name": "Conference",
17//   "date": 1695484200000,           ← Unix timestamp (not readable)
18//   "localDate": [2025, 9, 23],      ← Array (not standard)
19//   "localDateTime": [2025, 9, 23, 14, 30, 0]  ← Array
20// }

Fix 1: application.properties (Global)

properties
1# application.properties
2spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
3spring.jackson.time-zone=UTC
4spring.jackson.serialization.write-dates-as-timestamps=false
yaml
1# application.yml
2spring:
3  jackson:
4    date-format: "yyyy-MM-dd HH:mm:ss"
5    time-zone: UTC
6    serialization:
7      write-dates-as-timestamps: false

write-dates-as-timestamps=false is the key setting. It tells Jackson to serialize dates as ISO-8601 strings instead of numeric timestamps or arrays.

json
1// After configuration:
2{
3  "name": "Conference",
4  "date": "2025-09-23 14:30:00",
5  "localDate": "2025-09-23",
6  "localDateTime": "2025-09-23T14:30:00"
7}

Fix 2: @JsonFormat (Per Field)

java
1import com.fasterxml.jackson.annotation.JsonFormat;
2import java.time.LocalDateTime;
3import java.util.Date;
4
5public class Event {
6    private String name;
7
8    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "UTC")
9    private Date date;
10
11    @JsonFormat(pattern = "dd/MM/yyyy")
12    private LocalDate localDate;
13
14    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
15    private LocalDateTime localDateTime;
16
17    // getters and setters
18}
json
1{
2  "name": "Conference",
3  "date": "2025-09-23 14:30:00",
4  "localDate": "23/09/2025",
5  "localDateTime": "2025-09-23T14:30:00"
6}

@JsonFormat overrides the global configuration for specific fields. Use it when different fields need different formats.

Fix 3: Custom ObjectMapper Bean

java
1import com.fasterxml.jackson.databind.ObjectMapper;
2import com.fasterxml.jackson.databind.SerializationFeature;
3import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
4import org.springframework.context.annotation.Bean;
5import org.springframework.context.annotation.Configuration;
6
7@Configuration
8public class JacksonConfig {
9
10    @Bean
11    public ObjectMapper objectMapper() {
12        ObjectMapper mapper = new ObjectMapper();
13        mapper.registerModule(new JavaTimeModule());
14        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
15        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
16        mapper.setTimeZone(TimeZone.getTimeZone("UTC"));
17        return mapper;
18    }
19}

This gives full control over serialization. Spring Boot uses this ObjectMapper for all JSON processing.

Fix 4: Custom Serializer

java
1import com.fasterxml.jackson.core.JsonGenerator;
2import com.fasterxml.jackson.databind.JsonSerializer;
3import com.fasterxml.jackson.databind.SerializerProvider;
4import java.io.IOException;
5import java.time.LocalDateTime;
6import java.time.format.DateTimeFormatter;
7
8public class CustomDateTimeSerializer extends JsonSerializer<LocalDateTime> {
9    private static final DateTimeFormatter FORMATTER =
10        DateTimeFormatter.ofPattern("dd-MMM-yyyy HH:mm");
11
12    @Override
13    public void serialize(LocalDateTime value, JsonGenerator gen,
14                          SerializerProvider provider) throws IOException {
15        gen.writeString(value.format(FORMATTER));
16    }
17}
18
19// Usage
20public class Event {
21    @JsonSerialize(using = CustomDateTimeSerializer.class)
22    private LocalDateTime eventDate;
23}
24// Output: "eventDate": "23-Sep-2025 14:30"

Handling Deserialization (JSON to Java)

java
1public class CreateEventRequest {
2    private String name;
3
4    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
5    private LocalDateTime startTime;
6
7    // Jackson automatically parses "2025-09-23 14:30:00" to LocalDateTime
8}
java
1// POST /events
2// Body: { "name": "Meeting", "startTime": "2025-09-23 14:30:00" }
3
4@PostMapping("/events")
5public Event createEvent(@RequestBody CreateEventRequest request) {
6    // request.getStartTime() is a LocalDateTime object
7    return eventService.create(request);
8}

The @JsonFormat pattern works for both serialization (Java to JSON) and deserialization (JSON to Java).

Time Zone Handling

java
1public class Event {
2    // ZonedDateTime includes timezone information
3    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX")
4    private ZonedDateTime scheduledAt;
5    // Output: "2025-09-23T14:30:00+00:00"
6
7    // OffsetDateTime for UTC offset
8    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssZ")
9    private OffsetDateTime createdAt;
10    // Output: "2025-09-23T14:30:00+0000"
11}
properties
# Force all dates to a specific timezone
spring.jackson.time-zone=America/New_York

Common Pitfalls

  • Missing jackson-datatype-jsr310: Java 8 date/time classes (LocalDate, LocalDateTime) require the jackson-datatype-jsr310 module. Spring Boot auto-includes it, but if you customize the ObjectMapper, you must register new JavaTimeModule() manually or these types serialize as arrays.
  • @JsonFormat timezone ignored for LocalDateTime: LocalDateTime has no timezone concept. Setting timezone in @JsonFormat has no effect on it. Use ZonedDateTime or OffsetDateTime when timezone matters.
  • Date format not applied to deserialization: If your @JsonFormat pattern does not match the incoming JSON string exactly, Jackson throws InvalidFormatException. Ensure the request format matches the pattern precisely.
  • Global format overridden by @JsonFormat: @JsonFormat on a field takes precedence over application.properties settings. If one field shows a different format, check for a field-level annotation.
  • Using java.util.Date in new code: java.util.Date is mutable, not timezone-aware, and cumbersome to format. Use java.time.LocalDateTime or java.time.ZonedDateTime for new code — they work better with Jackson and are immutable.

Summary

  • Set spring.jackson.serialization.write-dates-as-timestamps=false to get ISO-8601 strings instead of timestamps
  • Use @JsonFormat(pattern = "...") for per-field format control
  • Spring Boot auto-registers JavaTimeModule — use java.time classes (LocalDate, LocalDateTime, ZonedDateTime)
  • Configure global format in application.properties or via a custom ObjectMapper bean
  • Use ZonedDateTime or OffsetDateTime when timezone information is needed
  • @JsonFormat works for both serialization (output) and deserialization (input)

Course illustration
Course illustration

All Rights Reserved.