The first three lines of your code using java.time
has been overly complicated making the calculation error-prone. I recommend you use the out-of-the-box constants to avoid any kind of ambiguity and error. Given below is the recommended way to do it:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
// Test
System.out.println(formatDateRfc1123(new Date()));
}
public static String formatDateRfc1123(final Date timestamp) {
// Use the out-of-the-box formatter
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.RFC_1123_DATE_TIME.withLocale(Locale.US);
// Use Date#toInstant to convert it into Instant
Instant instant = timestamp.toInstant();
// Use the out-of-the-box constant for UTC (or GMT)
ZoneId zoneId = ZoneOffset.UTC;
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, zoneId);
// ZonedDateTime zonedDateTime = instant.atZone(zoneId); //This is simpler
return dateTimeFormatter.format(zonedDateTime);
}
}
Note that the three-letter string representing a time zone is error-prone. You should always use the full name of the time zone i.e. Continent/City
. Given below is an example to demonstrate it.
import java.time.ZoneId;
public class Main {
public static void main(String[] args) {
ZoneId zoneId = ZoneId.of("EDT");
// ...
}
}
Output:
Exception in thread "main" java.time.zone.ZoneRulesException: Unknown time-zone ID: EDT
at java.base/java.time.zone.ZoneRulesProvider.getProvider(ZoneRulesProvider.java:279)
at java.base/java.time.zone.ZoneRulesProvider.getRules(ZoneRulesProvider.java:234)
at java.base/java.time.ZoneRegion.ofId(ZoneRegion.java:120)
at java.base/java.time.ZoneId.of(ZoneId.java:408)
at java.base/java.time.ZoneId.of(ZoneId.java:356)
at Main.main(Main.java:5)
The SimpleDateFormat
won't even throw an exception and silently format the date-time at UTC (or GMT). Such dangerous it is!
Incorrect:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
sdf.setTimeZone(TimeZone.getTimeZone("EDT"));
System.out.println(sdf.format(new Date()));
}
}
Output:
2020-12-05T01:36:48Z
Correct:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println(sdf.format(new Date()));
}
}
Output:
2020-12-04T20:36:05-05:00
Note that the date-time API of java.util
and their formatting API, SimpleDateFormat
are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API. Learn more about the modern date-time API at Trail: Date Time.
Note: If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.