Как передать несколько форматов даты в DateTimeFormatter, используя Scala - PullRequest
0 голосов
/ 10 апреля 2019

У меня есть три формата даты: ГГГГ-ММ-ДД, ДДММГГГ, ММДДГГГГ, вот так я передаю формат даты в Spark для разбора.

scala> val formatter = DateTimeFormatter.ofPattern("[MMddyyyy][yyyy-MM-dd][yyyyMMdd]")
formatter: java.time.format.DateTimeFormatter = [Value(MonthOfYear,2)Value(DayOfMonth,2)Value(YearOfEra,4,19,EXCEEDS_PAD)][Value(YearOfEra,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)][Value(YearOfEra,4,19,EXCEEDS_PAD)Value(MonthOfYear,2)Value(DayOfMonth,2)]

Для формата ММддйййй работает

scala> LocalDate.parse("10062019",formatter)
res2: java.time.LocalDate = 2019-10-06

Для формата yyyyMMdd он работает

scala> LocalDate.parse("2019-06-20",formatter)
res3: java.time.LocalDate = 2019-06-20

Для формата yyyyMMdd выдает ошибку

scala> LocalDate.parse("20190529",formatter)
java.time.format.DateTimeParseException: Text '20190529' could not be parsed: Invalid value for MonthOfYear (valid values 1 - 12): 20
  at java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1920)
  at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1855)
  at java.time.LocalDate.parse(LocalDate.java:400)
  ... 66 elided
Caused by: java.time.DateTimeException: Invalid value for MonthOfYear (valid values 1 - 12): 20
  at java.time.temporal.ValueRange.checkValidIntValue(ValueRange.java:330)
  at java.time.temporal.ChronoField.checkValidIntValue(ChronoField.java:722)
  at java.time.chrono.IsoChronology.resolveYMD(IsoChronology.java:550)
  at java.time.chrono.IsoChronology.resolveYMD(IsoChronology.java:123)
  at java.time.chrono.AbstractChronology.resolveDate(AbstractChronology.java:472)
  at java.time.chrono.IsoChronology.resolveDate(IsoChronology.java:492)
  at java.time.chrono.IsoChronology.resolveDate(IsoChronology.java:123)
  at java.time.format.Parsed.resolveDateFields(Parsed.java:351)
  at java.time.format.Parsed.resolveFields(Parsed.java:257)
  at java.time.format.Parsed.resolve(Parsed.java:244)
  at java.time.format.DateTimeParseContext.toResolved(DateTimeParseContext.java:331)
  at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1955)
  at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
  ... 67 more

Если я передаю 2 формата yyyyMMdd, yyyy-MM-dd, он работает нормально

    scala> val formatter = DateTimeFormatter.ofPattern("[yyyy-MM-dd][yyyyMMdd]") 
scala> LocalDate.parse("20190529",formatter)
res5: java.time.LocalDate = 2019-05-29

scala> LocalDate.parse("2019-06-20",formatter)
res6: java.time.LocalDate = 2019-06-20

То же, что и гггг-мм-дд, ммддггй формат даты

   scala> val formatter = DateTimeFormatter.ofPattern("[yyyy-MM-dd][MMddyyyy]")

    scala> LocalDate.parse("10062019",formatter)
    res7: java.time.LocalDate = 2019-10-06

    scala> LocalDate.parse("2019-06-20",formatter)
    res8: java.time.LocalDate = 2019-06-20

Можно ли как-нибудь передать три разных формата?

Ответы [ 2 ]

0 голосов
/ 10 апреля 2019

Только с информацией в вопросе это невозможно. Строка 10111213 может обозначать 13 декабря 1011 или 11 октября 1213. Однако, если предположить, что ваши даты всегда после 1300 года, вам повезло, потому что тогда часть строки YYYY не может быть проанализирована как MMDD потому что месяц будет 13 или больше, то есть недействительным. Вы можете использовать это для решения, какой из форматов является правильным для использования.

Я бы использовал три средства форматирования и попробовал бы их по очереди:

private static final DateTimeFormatter[] DATE_FORMATTERS = {
        DateTimeFormatter.ofPattern("uuuuMMdd"),
        DateTimeFormatter.ofPattern("MMdduuuu"),
        DateTimeFormatter.ofPattern("uuuu-MM-dd")
};

С этим просто сделайте:

    String dateString = "20190529";

    LocalDate result = null;
    for (DateTimeFormatter df : DATE_FORMATTERS) {
        try {
            result = LocalDate.parse(dateString, df);
            break;
        } catch (DateTimeParseException dtpe) {
            // Ignore; try next formatter
        }
    }
    System.out.println("" + dateString + " was parsed to " + result);

Вывод:

20190529 был проанализирован до 2019-05-29

Давайте попробуем и два других формата:

10062019 был проанализирован до 2019-10-06

2019-06-20 был проанализирован до 2019-06-20

Я рекомендую добавить нулевую проверку , чтобы перехватить любую непарсируемую строку даты, и проверку диапазона в проанализированную дату, чтобы 10111213 не проскальзывал как действительный. Например:

    if (result == null) {
        System.out.println(dateString + " could not be parsed");
    }
    else if (result.isBefore(LocalDate.now(ZoneId.of("Asia/Aden")))) {
        System.out.println("Date should be in the future, was " + result);
    }

PS Я предполагаю опечатку в первом предложении вашего вопроса:

У меня есть три формата даты: ГГГГ-ММ-ДД, ДДММГГГГ, ММДДГГГГ, вот как Я передаю формат даты в Spark для разбора.

Средний формат должен был быть ГГГГММДД (иначе у вас нет шансов).

0 голосов
/ 10 апреля 2019

Вы не можете иметь в форматере [yyyyMMdd] и [MMddyyyy] одновременно. Моя идея - нормализовать, чтобы у вас было [yyyy-MM-dd] и [MM-dd-yyyy] вместо 3 форматов.

Надеюсь, это помогло

Отредактировано:

Если у вас нет шансов, вы можете сделать что-то подобное, но это не очень красиво.

val formatter1 = DateTimeFormatter.ofPattern("[yyyy-MM-dd][MMddyyyy]")
val formatter2 = DateTimeFormatter.ofPattern("[yyyy-MM-dd][yyyyMMdd]")

val time = "20190529"

if (time.matches("2+\\d*")) LocalDate.parse(time,formatter2) else 
LocalDate.parse(time,formatter1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...