tldr
java.util.Date juDate =
Date // Legacy class. Best to avoid wherever possible. Represents a moment as seen in UTC (zero offset) but it’s poorly designed `toString` applies the JVM’s current default time zone while generating text.
.from( // A new method on old legacy class to bridge between legacy and modern classes.
java.time.Instant // The modern class for representing a moment as seen with an offset of zero.
.parse( "2023-03-22T11:27:04Z" ) // Parsing text in standard ISO 8601 format.
)
;
Best to avoid the terribly flawed legacy date-time class java.util.Date
. Use only java.time classes.
Instant
.parse( "2023-03-22T11:27:04Z" ) // Returns an `Instant` object.
.atZone( // Adjust from UTC to a specific time zone.
ZoneId.of( "Asia/Kolkata" ) // Returns a `ZoneId` object.
) // Returns a `ZonedDateTime` object.
Incorrect formatting pattern, also unnecessary
2023-03-22T11:27:04Z
DateTimeFormatter.ofPattern("yyyy-MM-dd' HH:mm:ss"
, Locale.ENGLISH).ISO_OFFSET_DATE_TIME;
Your formatting pattern for parsing does not match the input data. The Z
on the end of the input indicates the date and time represent a moment as seen with an offset from UTC of zero hours-minutes-seconds. Your formatter ignores that crucial part.
And, the formatting pattern needs other fixes: a stray single-quote mark, and a SPACE that should instead be T
.
Furthermore, there is no need to define this formatting pattern at all. Your input text happens to comply with the ISO 8601 format. The java.time classes use ISO 8601 formats by default when parsing/generating text.
Instant instant = Instant.parse( "2023-03-22T11:27:04Z" ) ;
Avoid legacy date-time types
Date startDate = …
Both Date
classes bundled with Java are terribly flawed, designed by people who did not understand date-time handling. Avoid these classes. Use only the java.time classes defined in JSR 310.
If you must have an object of the legacy classes to interoperate with old code not yet updated to java.time, convert using new methods added to the old classes.
java.util.Date juDate = java.util.Date.from( instant ) ;
Beware: The toString
method of java.util.Date
unfortunately applies the JVM’s current time zone while generating its resulting text. This design flaw may be adding to your confusion. A java.util.Date
actually represents a moment with an offset from UTC of zero hours-minutes-seconds.
Adjusting to a time zone
An Instant
represents a moment as seen with an offset from UTC of zero hours-minutes-seconds.
If you want to view that moment through the lens of a particular time zone, apply a ZoneId
to get a ZonedDateTime
.
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, different wall-clock time.