Home > database >  LocalDateTime using FormatStyle.MEDIUM plus time zone
LocalDateTime using FormatStyle.MEDIUM plus time zone

Time:10-21

I have a LocalDateTime object that I'm formatting 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 display 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 as readable 2021-10-20T13:05:13.921-04:00[America/New_York].

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?

I gather, from this answer I should avoid "pseudo-zones", such as EST, due to their non-standardized nature (although, standard or not, I'd venture to say that's what most users are accustomed to). So if EST, etc., are not feasible within the Java libraries, I'd still like to produce the readable date produced by FormatStyle.MEDIUM, followed by some representation of time zone.

Is that possible?

CodePudding user response:

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

CodePudding user response:

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 and LONG styles typically require a time-zone. When formatting using these styles, a ZoneId must be available, either by using ZonedDateTime or withZone(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.

CodePudding user response:

tl;dr

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. These are not real time zones, are not standardized, and are not even unique!

Avoid 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. 

Use 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

Separate formats for date & time

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.
            )   

CodePudding user response:

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

  • Related