Serialization and deserialization: TL;DR
Instant parsedBack = Instant.parse(Instant.now().toString());
System.out.println(parsedBack);
2025-07-27T18:11:47.276158411Z
Use ISO 8601 and java.time
- For serializing date and time (for example for data transfer or for persistence)
use the standard ISO 8601 format.
- For all date and time work, since Java 8 use java.time,
the modern Java date and time API.
The class you need from it is probably
Instant,
depending on your more exact requirements.
The classes Date, DateFormat amd SimpleDateFormat were always badly designed
and troublesome to work with, so avoid them.
The two points go nicely hand in hand:
Instant originalInstant = Instant.now();
String serializedToIso8601 = originalInstant.toString();
Instant theSameInstant = Instant.parse(serializedToIso8601);
Parsing the string from Date.toString() back
If you are receiving the string from Date.toString(), first of all be aware that generally you cannot parse it back into an Instant or date-time object equal to the original Date. The hindrances include:
- Milliseconds from the original
Date are lost since they are not in the string, leading to an inaccuracy of up to 999 milliseconds.
- The era from the original
Date is not in the string either. So if your original Date was in year 44 BCE, you will get the corresponding date in year 44 CE (AD).
- The time zone abbreviation in the string is often (most often?) ambiguous, so there is a great risk of getting the wrong time zone and hence a wrong time. To make matters worse, an ambiguous time zone abbreviation will be interpreted differently on different JVMs. I believe that
CET can only be for Central European (Standard) Time, though, so with your example string you should be good.
With these limitations the format pattern string from the answer by Andreas Dolk also works with java.time. Declare:
private static final DateTimeFormatter dtf
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz y", Locale.ROOT);
I have changed yyyy to just y. The former obviously works with year 2012, For years outside the 1000 through 9999 range Date printed fewer or more digits. The single y parses 1 through 9 digits.
It’s essential to provide a locale. Otherwise the JVM’s default locale will be used, and if it’s not English, parsing will fail. In the worst case you will see your code running fine for many years, and suddenly it will break when one day someone runs it on a computer or device with a different locale setting. I use Locale.ROOT for “the locale neutral locale” or “don’t apply any locale specific processing”. It seems to be the correct approach here.
With this formatter parsing goes like:
String s = "Sun Dec 12 13:45:12 CET 2010";
ZonedDateTime zdt = ZonedDateTime.parse(s, dtf);
System.out.println("As ZonedDateTime: " + zdt);
Instant nearlyTheSameInstant = zdt.toInstant();
System.out.println("As Instant: " + nearlyTheSameInstant);
Output:
As ZonedDateTime: 2010-12-12T13:45:12+01:00[CET]
As Instant: 2010-12-12T12:45:12Z
Links
- Oracle tutorial: Trail: Date Time explaining how to use java.time.
- ISO 8601 on Wikipedia.
- Acknowledgement:
This answer was heavily inspired by thi-s answer by Anonymous.
I believe the answer belongs better here since this question is the original to that other one.
Date,DateFormatamdSimpleDateFormatwere always badly designed and troublesome to work with, so don’t any more.ISTin your string, is that for Icelandic Standard Time, Irish Standard Time (cannot be Irish summer time in February), Israel Standard Time, India Standard Time or something else? If we don’t know, we cannot make the correct conversion.java.util.Dateto aStringand now want to convert it back to aDate. Is this for serialization? You can and should avoid using an ambiguous time zone abbreviation for that purpose. The standard recommendation is to use ISO 8601 format.