Convert ISO date formatted string with appropriate timezone

144 Views Asked by At

I am trying to update date value which is in ISO format (with tz) 2020-11-22T10:02:13.501-04:00 to format like 11/Nov/2020 10:02 AM EST.

I am using the below code but how do we get the timezone as (-04:00) is EST.

DateFormat df2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
SimpleDateFormat sdf = new SimpleDateFormat("dd/MMM/yyyy HH:mm aa zzz");
Date dateVal = df2.parse(dateStr);
String formatted = sdf.format(dateVal);`

This format dd/MMM/yyyy HH:mm aa zzz will default to server timezone but I want the timezone from the date.

2

There are 2 best solutions below

0
Reilas On

"... This format dd/MMM/yyyy HH:mm aa zzz will default to server timezone but I want the timezone from the date."

Don't include the timezone within the parse, it's just a notation.

Date dateVal = df2.parse(dateStr.substring(0, dateStr.lastIndexOf('-')));

And, when printing the value, the JVM is going to display the system's default time-zone, so manually append the time-zone text.

SimpleDateFormat sdf = new SimpleDateFormat("dd/MMM/yyyy HH:mm aa ");
Date dateVal = df2.parse(dateStr.substring(0, dateStr.lastIndexOf('-')));
String formatted = sdf.format(dateVal) + "EST";
0
Basil Bourque On

tl;dr

OffsetDateTime
.parse( "2020-11-22T10:02:13.501-04:00" )
.atZoneSameInstant( 
    ZoneId.of( "America/New_York" ) 
)
.format( 
    DateTimeFormatter
    .ofPattern ( "dd/MMM/uuuu HH:mm a z" )
    .withLocale ( Locale.US )
) 

See this code run at Ideone.

22/Nov/2020 09:02 AM EST

Note the change in hour-of-day, 9 versus 10. On that date, most time zones likely intended by "EST" were using an offset of -05:00 not -04:00. The -04:00 offset is used only in the summer in observance of Daylight Saving Time (DST). So the example shown in the Question is contradictory/incorrect.

Use real time zone names, not “EST”.

Avoid legacy classes

You are using terribly flawed date-time classes. These were years ago supplanted by the modern java.time classes defined in JSR 310.

java.time

OffsetDateTime

Parse your input string as a OffsetDateTime because that text includes a date, a time-of-day, and an offset from UTC (a count of hours-minutes-seconds ahead/behind the temporal meridian).

ISO 8601

Your input is in standard ISO 8601 format. So no need to specify a formatting pattern. The java.time classes use ISO 8601 formats by default when parsing/generating text.

OffsetDateTime odt = OffsetDateTime.parse( "2020-11-22T10:02:13.501-04:00" ) ;

EST is not a real time zone

You want to produce text in a localized format that includes a pseudo time zone such as EST. Be aware that such pseudo-zones are not official, are not standardized, and are not even unique(!).

So you need to determine what real time zone you intend. Real time zones are named with a format of Continent/Region such as Europe/Paris or Pacific/Auckland.

Given your example of -04:00 and "EST", I assume you intend a time zone on the east side of the Americas. Many such time zones may be intended by "EST". These range from the northern edges of Canada and Greenland, all the way down through the Caribbean to parts of South America. Examples include America/Detroit, America/Grand_Turk, America/Indiana/Indianapolis, America/New_York, America/Port-au-Prince.

Your offset incorrect on that date

If you did intend one of these EST-implied time zones, then your offset is wrong. On that date, November 22 of 2020, the time zones implied by EST were using an offset of "-05:00".

If your example data is wrong, is not what you truly intended, I suggest you edit your Question with corrections.

Example: America/New_York

I will take a wild guess that you intended America/New_York. Apply that zone to our OffsetDateTime to get a ZonedDateTime object.

ZoneId zoneId = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( zoneId ) ;

Generate standard text

Now we can generate text. First, let's generate text in standard ISO 8601 format that has been wisely extended by appending the name of the time zone in square brackets.

String output = zdt.toString() ;

2020-11-22T09:02:13.501-05:00[America/New_York]

Notice how the hour has changed from 10 to 9, and the offset from -04:00 to -05:00. This still represents the same moment, the same point on the timeline. But adjustments have been made to suit how that moment was indeed seen by people in the region covered by the time zone of America/New_York.

Generate localized text

You can specify a custom format to be used in generating text. But I would generally recommend you let Java automatically localize while generating text.

To generate localized text, specify a locale.

Locale locale = Locale.forLanguageTag ( "en-CA" );
DateTimeFormatter formatter =
        DateTimeFormatter
                .ofLocalizedDateTime ( FormatStyle.LONG )
                .withLocale ( locale );
String output = zdt.format ( formatter );

Or build a custom formatter. Again, specify a Locale unless you want to implicitly rely upon the JVM’s current default time zone at runtime.

Locale locale = Locale.US;
DateTimeFormatter formatter =
        DateTimeFormatter
                .ofPattern ( "dd/MMM/uuuu HH:mm a z" )
                .withLocale ( locale );
String output = zdt.format ( formatter );

22/Nov/2020 09:02 AM EST