Jackson serializes a ZonedDateTime wrongly in Spring Boot
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
When ZonedDateTime looks wrong in a Spring Boot JSON response, the problem is usually not that Jackson is broken. More often, Jackson is following a default that does not match what you expected about offsets, zone IDs, or timestamp format.
What Jackson Actually Serializes
A ZonedDateTime contains three pieces of information: the local date and time, the offset from UTC, and the named zone such as Europe/Berlin. Those pieces are related, but not identical.
If you serialize a ZonedDateTime without extra configuration, Jackson often emits an ISO-8601 string with an offset. Depending on configuration, it may omit the bracketed zone ID and keep only the offset portion. That can make developers think the zone was lost, even when the instant itself is still correct.
For example, these two strings may represent the same moment:
- '
2026-03-11T10:00:00+01:00' - '
2026-03-11T09:00:00Z'
They are different textual representations of the same instant. Whether that is “wrong” depends on whether your API contract cares about the original named zone or only the instant in time.
Spring Boot and the Java Time Module
Modern Spring Boot setups usually work best when Jackson has Java time support and date timestamps are written as strings, not numeric arrays or epoch numbers.
If your output is an array or a numeric timestamp, this configuration is the first thing to inspect.
In Spring Boot, a clean way to enforce the same behavior application-wide is a customizer bean.
Preserving the Zone ID
Another common surprise is that the output contains the correct offset but not the named zone. If your consumers must see Europe/Berlin instead of just +01:00, enable the feature that writes the zone ID explicitly.
That distinction matters because an offset tells you the position from UTC at one moment, while a zone ID also carries daylight-saving rules for future or past calculations.
When the Time Zone Seems Shifted
Sometimes the serialized value is not just formatted differently. It is actually shifted. That usually happens because the value was converted earlier in the pipeline, not during serialization itself.
Typical causes include:
- creating the
ZonedDateTimein the wrong zone - converting to
InstantorOffsetDateTimeand later expecting the original named zone back - setting a global mapper time zone and assuming it rewrites
ZonedDateTimevalues in a predictable way
If you want a specific zone in the JSON, convert the value deliberately before serialization.
That makes the intent explicit and avoids relying on serializer side effects.
Choosing the Right Type
If your API only cares about an instant with an offset, OffsetDateTime is often simpler. If the API must preserve a named zone because downstream logic depends on local calendar rules, ZonedDateTime is the better type.
A lot of so-called serialization bugs are actually type-selection bugs. Developers choose ZonedDateTime, but the system only needs UTC instants. Or they choose OffsetDateTime, then later realize the original zone name matters.
Common Pitfalls
The most common mistake is assuming that “same instant” and “same text” are identical requirements. Jackson may serialize the correct instant in a format that looks unfamiliar.
Another frequent problem is forgetting to register Java time support or to disable timestamp serialization. That often produces numeric output or inconsistent formatting.
Developers also expect spring.jackson.time-zone or ObjectMapper#setTimeZone to fully control ZonedDateTime. In practice, date-time types that already embed zone information can behave differently from old java.util.Date workflows.
Finally, if clients truly need the named zone, do not assume the offset alone is enough. Enable zone ID output or serialize a dedicated field that carries the zone name explicitly.
Summary
- '
ZonedDateTimeissues are often caused by mismatched expectations about offsets, instants, and zone IDs.' - Register
JavaTimeModuleand disableWRITE_DATES_AS_TIMESTAMPSfor readable JSON. - Enable
WRITE_DATES_WITH_ZONE_IDif the API must preserve the named zone. - Convert to the intended zone before serialization instead of relying on global mapper settings.
- Use
OffsetDateTimewhen only the instant and offset matter, andZonedDateTimewhen the zone rules matter too.
Related reading
- Jackson Vs. Gson
- Jackson with JSON Unrecognized field, not marked as ignorable
- Java-R integration?
- Java8 Why is it forbidden to define a default method for a method from java.lang.Object
- Java - Convert integer to string
- Java - escape string to prevent SQL injection
- Java - get the current class name?
- Java - How to create new Entry (key, value)

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.