88936

How to parse string with date, but without time in local format to ZonedDateTime?

This question is similar to How to parse ZonedDateTime with default zone? but addinitional condition.

I have a string param that represent a date in UK format: "3/6/09". It doesn't contain time, only date. But may contain it and even time zone. And I want to parse it to ZonedDateTime.

public static ZonedDateTime parse(String value) { DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(SHORT).withLocale(Locale.UK).withZone(ZoneId.systemDefault()); TemporalAccessor temporalAccessor = formatter.parseBest(value, ZonedDateTime::from, LocalDateTime::from, LocalDate::from); if (temporalAccessor instanceof ZonedDateTime) { return ((ZonedDateTime) temporalAccessor); } if (temporalAccessor instanceof LocalDateTime) { return ((LocalDateTime) temporalAccessor).atZone(ZoneId.systemDefault()); } return ((LocalDate) temporalAccessor).atStartOfDay(ZoneId.systemDefault()); }

But, it fails with exception:

java.time.format.DateTimeParseException: Text '3/6/2009' could not be parsed at index 6

It's a bug for me, or isn't?

Answer1:

In my opinion is not a bug. Your approach is flawed.

First of all you are returning a ZonedDateTime so it is expected that the String contains full date, time and zone information. The string "3/6/09" should be parsed to a LocalDate.

Second, you are delegating a runtime detection of format to the library. Again, you should be parsing/formatting an expected format. Your application should know wether is expecting a full date & time or a partial (only date or only time).

Anyway you will have more luck detecting the format and then using different parsing methods.

Only local date:

DateTimeFormatter .ofLocalizedDate(FormatStyle.SHORT) .parse(value, LocalDate::from)`

Zoned date and time:

DateTimeFormatter .ofLocalizedDateTime(FormatStyle.SHORT, FormatStyle.SHORT) .parse(value, ZonedDateTime::from)`

Answer2:

The format used can be seen using the getLocalizedDateTimePattern() method:

String fmt = DateTimeFormatterBuilder.getLocalizedDateTimePattern( FormatStyle.SHORT, FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.UK);

The result is "dd/MM/yy HH:mm".

As such, the format is expecting both a date and a time with a space separator, so that is what must be provided.

In addition, the format/parse expects there to be two digits for the day-of-month and two digits for the month-of-year. Thus, you would need to pass in "03/06/09 00:00" in order to get the result you expect, in which case you can parse directly to a LocalDateTime.

Alternatively, use ofLocalizedDate():

DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(Locale.UK); LocalDate date = LocalDate.parse("03/06/99", formatter);

Note that the input must still have two digits for the day and month.

Alternatively, parse using a specific pattern that can handle the missing leading zeroes:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yy"); LocalDate date = LocalDate.parse("3/6/99", formatter); LocalDate date = LocalDate.parse("03/06/99", formatter); // handles both "3/6/99" and "03/06/99"

Update: Lenient parsing also handles this case:

DateTimeFormatter formatter = new DateTimeFormatterBuilder() .parseLenient().appendPattern("dd/MM/yy").toFormatter(); LocalDate date = LocalDate.parse("3/6/99", formatter); LocalDate date = LocalDate.parse("03/06/99", formatter); // handles both "3/6/99" and "03/06/99"

Recommend

  • How to get time from user with respect to timezone
  • Java daylight saving seems to be wrong
  • What is the Standard way to Parse different Dates passed as Query-Params to the REST API?
  • Newbie question about maven
  • AngularJS ng-option get index
  • Symfony2 redirect to https route fails (uses wrong port)
  • ASPNetCore MVC Routing Let Server Handle Specific Route
  • npm 5.4.1 install/uninstall all failing
  • OpenGL 3.3 on Mac OSX El Capitan with LWJGL
  • why overloaded new operator is calling constructor even I am using malloc inside overloading functio
  • C++ Partial template specialization - design simplification
  • How to use an array of arrays with array_map(…) in PHP?
  • Different response to non-authenticated users and AJAX calls
  • jQuery show() function is not executed in Safari if submit handler returns true
  • How to draw moving and Running sine wave chart using JFree chart in java?
  • output of program is not same as passed argument
  • Cross-Platform Protobuf Serialization
  • Incrementing object id automatically JS constructor (static method and variable)
  • javascript inside java/jsp code
  • Running a C# exe file
  • Eraser for UIBezierPath
  • How to limit post in wp_query
  • Upload files with Ajax and Jquery
  • Build own AppleScript numerical error handling
  • How to format a variable of double type
  • Android Studio and gradle
  • AngularJs get employee from factory
  • coudnt use logback because of log4j
  • Java static initializers and reflection
  • Exception on Android 4.0 `android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode)`
  • Change div Background jquery
  • IndexOutOfRangeException on multidimensional array despite using GetLength check
  • Bitwise OR returns boolean when one of operands is nil
  • JaxB to read class hierarchy
  • Is there any way to bind data to data.frame by some index?
  • Django query for large number of relationships
  • Why is Django giving me: 'first_name' is an invalid keyword argument for this function?
  • How can i traverse a binary tree from right to left in java?
  • How can I use `wmic` in a Windows PE script?
  • How to push additional view controllers onto NavigationController but keep the TabBar?