import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
public class Test001 {
public static void main(String[] args) {
Date dt = new Date();
LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS zzz").withZone(ZoneId.of("America/New_York"));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS zzz");
System.out.println(formatter.format(localDateTime));
System.out.println(sdf.format(dt));
}
}
2016-04-19 11:25:34.917 ET
2016-04-19 11:25:34.637 EDT
The timezone of my laptop is "America/New York" (i.e. Eastern Time US/Canada).
I wonder how to get "EDT" instead of "ET" by using DateTimeFormatter
.
I wonder also in general: why is the DateTimeFormatter
not compatible with SimpleDataFormat
in terms of parse/format patterns (as this example shows they are not compatible).
The format you are seeing "ET" is known as the "Generic non-location" format in Unicode Locale Data Markup Language (LDML). The format you want, "EDT", is known as the "Specific non-location" format.
The relevant source code in DateTimeFormatterBuilder
checks to see if the date-time object can supply ChronoField.INSTANT_SECONDS
. If it can, then the "specific non-location" format is used, if not then the "generic non-location" format is used.
Since you are formatting a LocalDateTime
, which does not support access to ChronoField.INSTANT_SECONDS
, you are getting the "generic non-location" format. To get the output you want, use ZonedDateTime
or OffsetDateTime
instead. (The instant is needed to determine whether it is summer or winter time.)
Note that SimpleDateFormat
and DateTimeFormatter
do differ and it is not correct to assume the patterns are identical. The decision was taken to resynchronize DateTimeFormatter
with the LDML specification, which will have benefits in the future.
This answer provides a solution and an explanation, however I must note that the JDK code is being overly harsh here. Since you are supplying both a LocalDateTime
and a ZoneId
, the code should be able to do better, and determine ChronoField.INSTANT_SECONDS
on the fly and thus use the "specific non-location" format. Thus, I think there is an edge case JDK issue here.
You shouldn't be operating on a LocalDateTime
. The (almost)equivalent of Date
is Instant
. You'll want to format an Instant
as if it was in your timezone. So
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS zzz").withZone(ZoneId.of("America/New_York"));
Instant now = Instant.now();
System.out.println(formatter.format(now));
which prints
2016-04-19 12:07:57.684 EDT
Alternatively, you can use a ZonedDateTime
without setting a ZoneId
for your DateTimeFormatter
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS zzz");
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/New_York")))
System.out.println(formatter.format(now));
which also prints
2016-04-19 12:11:01.667 EDT
I don't have the documentation for why this all works, but the gist is that these temporals (the date object you're trying to format) have offsets, which have zone rules, which can be daylight saving time or not. The formatter uses that in its printing.
A LocalDateTime
does not have an offset or timezone. Your formatter overrides it but with an offset that is not daylight saving time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With