I have a LocalDateTime object that I format as follows:
LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
System.out.println(localDateTime.format(formatter));
That prints a nicely readable date of Oct 20, 2021 1:00:02 PM
.
But I would like to also add the time zone. My understanding is I need to use ZonedDateTime:
ZonedDateTime zdt = localDateTime.atZone(ZoneId.of("America/New_York"));
System.out.println(zdt);
But that produces the not so readable 2021-10-20T13:00:02.921-04:00[America/New_York]
.
Is there some way to format a ZonedDateTime so it's concise and readable like that produced by FormatStyle.MEDIUM, but also appended by the timezone (e.g: Oct 20, 2021 1:00:02 PM EST
)?
Note: I gather from this answer that I should not actually use "pseudo-zones", such as EST, due to their non-standardized nature.
LocalDateTime is an immutable date-time object that represents a date-time with default format as yyyy-MM-dd-HH-mm-ss. zzz. It provides a factory method that takes LocalDate and LocalTime input arguments to create LocalDateTime instance.
For time patterns, use mm for two-digit minute and ss for two-digit second. The hh pattern generates the two-digit hour for a 12-hour clock (e.g., 6PM is "06") and HH generates the two-digit hour for a 24-hour clock (e.g., 6PM is "18").
Class LocalDate. A date without a time-zone in the ISO-8601 calendar system, such as 2007-12-03 . LocalDate is an immutable date-time object that represents a date, often viewed as year-month-day.
ISO_LOCAL_DATE. public static final DateTimeFormatter ISO_LOCAL_DATE. The ISO date formatter that formats or parses a date without an offset, such as '2011-12-03'. This returns an immutable formatter capable of formatting and parsing the ISO-8601 extended local date format.
If you want a hint as to the time zone in use, use the LONG
format for time-of-day portion. Optionally specify a different format such as MEDIUM
for the date portion.
ZonedDateTime
.now( ZoneId.of( "America/New_York" ) )
.format(
DateTimeFormatter
.ofLocalizedDateTime(
FormatStyle.MEDIUM , // Date portion style.
FormatStyle.LONG // Time-of-day portion style.
)
.withLocale( Locale.US ) // Locale determines the human language and cultural norms used in localizing.
)
See this code run live at IdeOne.com.
Oct 20, 2021, 4:48:46 PM EDT
Never use EDT
, CST
, IST
, and such for data-exchange. Do not attempt parsing of such values. These are not real time zones, are not standardized, and are not even unique!
LocalDateTime.now
I cannot imagine any scenario where calling LocalDateTime.now
is the right thing to do. You capture the date and time-of-day but lack the context of a time zone or offset-from-UTC. So a LocalDateTime
by definition cannot represent a moment, is not a point on the timeline.
If you want to capture the current moment without committing to a particular time zone, capture the current moment as seen with an offset-from-UTC of zero hours-minutes-seconds.
Instant instant = Instant.now() ; // Current moment as seen in UTC.
ZonedDateTime.now
If you want to capture the current moment as seen in America/New_York
time zone, start with a ZonedDateTime
.
ZonedDateTime.now( ZoneId.of( "America/New_York" ) )
To generate text representing a java.time object, use toString
method to get text in standard ISO 8601 format. While such output may seem less readable at first glance, the standard formats are designed to be maximally readable by people across cultures.
To get a localized format, I suggest you let java.time automatically localize.
ZoneId z = ZoneId.of( "America/New_York" );
ZonedDateTime zdt = ZonedDateTime.now( z );
System.out.println( "zdt represented in standard ISO 8601 format: " + zdt.toString() );
Locale locale = Locale.US ;
DateTimeFormatter f_US = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM ).withLocale( locale ) ;
String outputLocalized_US = zdt.format( f_US ) ;
String outputLocalized_CA_fr = zdt.format( f_US.withLocale( Locale.CANADA_FRENCH ) ) ;
System.out.println( outputLocalized_US ) ;
System.out.println( outputLocalized_CA_fr ) ;
When run.
zdt represented in standard ISO 8601 format: 2021-10-20T16:37:57.752554-04:00[America/New_York]
Oct 20, 2021, 4:37:57 PM
20 oct. 2021 16 h 37 min 57 s
You can specify different formats for the date versus time-of-day portions. Use a longer format for time-of-day portion to get a hint of the time zone while using a shorter format for date portion, if you so desire.
DateTimeFormatter
.ofLocalizedDateTime(
FormatStyle.MEDIUM , // Date portion format.
FormatStyle.LONG // Time-of-day portion format.
)
Is there some way to format a ZonedDateTime so it reads similar to that produced by
FormatStyle.MEDIUM
, but is appended by the timezone - say, something like:Oct 20, 2021 4:05:13 PM EST
?
You can use the format, MMM d, uuuu h:mm:ss a zzz
with the DateTimeFormatter
.
Demo:
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/New_York"));
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MMM d, uuuu h:mm:ss a zzz", Locale.ENGLISH);
System.out.println(now.format(dtf));
}
}
Output:
Oct 20, 2021 6:41:45 PM EDT
ONLINE DEMO
the ZonedDateTime can retrieve the current ZoneId. With the Zone, you can just use the getDisplayName(TextStyle style, Locale locale)
getter. Just experiment which TextStyle is the best for you.
zdt.getZone().getDisplayName(TextStyle.SHORT, Locale.ENGLISH)
==> ET
Note that if you use LONG
or FULL
for the time style, the zone will be included:
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("America/New_York"));
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.LONG);
System.out.println(zdt.format(formatter));
In the US locale, this prints:
Oct 20, 2021, 4:34:16 PM EDT
This is documented here:
The
FULL
andLONG
styles typically require a time-zone. When formatting using these styles, a ZoneId must be available, either by usingZonedDateTime
orwithZone(java.time.ZoneId)
.
In this case, a time style of LONG
happens to be the same as MEDIUM
, but if you have to use MEDIUM
for some reason, you can use a DateTimeFormatterBuilder
and add the zone by hand:
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("America/New_York"));
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM))
.appendLiteral(" ")
.appendZoneText(TextStyle.SHORT).toFormatter();
System.out.println(zdt.format(formatter));
The advantage of this is that you can choose what style of timezone name you want. On the other hand, you might run into localisation issues, because I'm not sure if it is natural in all locales to put the timezone last.
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