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

孤者浪人 提交于 2019-12-24 02:43:15

问题


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?


回答1:


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



回答2:


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"


来源:https://stackoverflow.com/questions/27488494/how-to-parse-string-with-date-but-without-time-in-local-format-to-zoneddatetime

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!