DateTimeFormatter does not parse custom date format

I have a problem with java DataTimeFormmater

. I feel like I missed something, but can't figure out what exactly.

String format = "yyyy-MM-dd'T'HH:mm:ss[.S]'T'zxxx";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);

String date = "2017-07-05T12:28:36.4TGMT+03:00";

System.out.println(formatter.format(ZonedDateTime.now()));
System.out.println(formatter.parse(date));

      

The above code creates the current string ZonedDateTime

and tries to parse the date time string with the same date formatting. The result it produces successfully 2017-07-05T06:07:51.0TCDT-05:00

, but does not parse2017-07-05T12:28:36.4TGMT+03:00

My goal is to disassemble 2017-07-05T12:28:36.4TGMT+03:00

and create an appropriate one DateTimeFormatter

.

+3


source to share


2 answers


You have to change the format:

String format = "yyyy-MM-dd'T'HH:mm:ss[.S]'T'[zzz][xxx]";

      

Both [zzz]

and [xxx]

are non-binding sections, because it zzz

can analyze whole or part GMT+03:00

, or just a short name of the zone (for example CDT

), and xxx

analyzes only the offset (for example, -05:00

- is therefore not required if found GMT+03:00

).

As a reminder, what the formatter.parse(date)

object returns TemporalAccessor

. If you want to create a specific type, it is better to use the appropriate class parse

:

System.out.println(ZonedDateTime.parse(date, formatter)); // 2017-07-05T12:28:36.400+03:00[GMT+03:00]

      


PS: The only problem with this formatting is that it prints all optional sections when formatted. So, if you do something like this:

String date = "2017-07-05T12:28:36.4TGMT+03:00";
ZonedDateTime z  = ZonedDateTime.parse(date, formatter);
System.out.println(formatter.format(z));

      

The output will be:

2017-07-05T12: 28: 36.4TGMT + 03: 00 + 03: 00

This is because it GMT+03:00

is the result zzz

and the second +03:00

is the result xxx

. If you don't want that, I repeat using 2 different ones DateTimeFormatter

(one for parsing, the other for formatting).

Or ("ugly" approach), use 2 different formatting:



DateTimeFormatter noGMT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.S]'T'zzzxxx");
DateTimeFormatter gmt = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.S]'TGMT'xxx");

      

Then you try to parse the first - if you get an exception, try with the second (or you check to see if your input contains GMT

to see which one to use).

I personally don't like this because it GMT

is part of the zone name and should not be considered a literal. But you end up ZonedDateTime

with the correct offset, so I'm not sure how wrong this approach is.


Abbreviations of time zones

Remember that you should avoid (as much as possible) the use of three-letter abbreviations (for example, CDT

or PST

) as they are ambiguous and not standard . CDT

can be like Central Daylight Time

(UTC-05: 00), Cuba Daylight Time

(UTC-04: 00) or even China Daylight Time

(UTC + 09: 00).

Prefer to use IANA time zone names if possible (always in the format Continent/City

such as America/Sao_Paulo

or Europe/Berlin

). Based on this list, there are over 40 time zones that use (or have used somewhere in the past) the abbreviation CDT

.

CDT

works for this case because some abbreviations have defaults, probably for retro compatibility reasons, but you shouldn't rely on them for all cases.

To make your timezone abbreviations always work (in case you can't avoid using them), you can create a formatter that uses a set of preferred zones. In this case I am using America/Chicago

(so that CST

or CDT

will be parsed as timezone in Chicago):

Set<ZoneId> preferedZones = new HashSet<>();
preferedZones.add(ZoneId.of("America/Chicago"));
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    // append first part of pattern (before timezone)
    .appendPattern("yyyy-MM-dd'T'HH:mm:ss[.S]'T'")
    // append zone name, use prefered zones (optional)
    .optionalStart().appendZoneText(TextStyle.SHORT, preferedZones).optionalEnd()
    // offset (optional)
    .appendPattern("[xxx]")
    // create formatter
    .toFormatter();

      

This formatter works the same as above for both inputs (with and without GMT

) and uses the America/Chicago

default timezone as the CDT

input. You can add as many zones as you want to install according to your use cases.

As a reminder, this formatter has the same output issues (it prints all optional sections) as stated above.

+3


source


TL; DR

OffsetDateTime.parse(
    "2017-07-05T12:28:36.4TGMT+03:00".replace( "TGMT" , "" ) 
)

      

More details

Your format is strange, like a strange misunderstanding or distortion of the standard ISO 8601 formats .



If all of your inputs have "TGMT" in the last part, align it according to ISO 8601.

The java.time classes use standard default formats when parsing / generating strings. Therefore, there is no need to define a formatting template.

OffsetDateTime odt = OffsetDateTime.parse( "2017-07-05T12:28:36.4TGMT+03:00".replace( "TGMT" , "" ) ) ;

      

And never use pseudo-random letters 3-4 like CMT

, EST

and IST

. These are not real time zones, not standardized, or even unique (!). Live names are in a format continent/region

such as America/Montreal

or Pacific/Auckland

.

+2


source







All Articles