2014-05-06 3 views
8

Моя программа анализирует входную строку на объект LocalDate. В большинстве случаев строка выглядит как 30.03.2014, но иногда она выглядит как 3/30/2014. В зависимости от этого, мне нужно использовать другой шаблон для вызова DateTimeFormatter.ofPattern(String pattern) с. В принципе, мне нужно проверить, соответствует ли строка шаблону dd.MM.yyyy или M/dd/yyyy перед выполнением разбора.Как проверить, соответствует ли строка даты дате, используя API времени?

Регулярное выражение подход будет что-то вроде:

LocalDate date; 
if (dateString.matches("^\\d?\\d/\\d{2}/\\d{4}$")) { 
    date = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("M/dd/yyyy")); 
} else { 
    date = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("dd.MM.yyyy")); 
} 

Это работает, но было бы неплохо использовать строку даты шаблона при совпадении строки также.

Существуют ли стандартные способы сделать это с помощью нового API Java 8 time, не прибегая к правильному сопоставлению регулярных выражений? Я просмотрел документы для DateTimeFormatter, но ничего не нашел.

+0

Почему вы не строкой 'replace (" // ",". ")'? –

+0

Я не думаю, что существует конкретный метод проверки того, соответствует ли дата заданному шаблону. Я бы использовал метод SimpleDateFormat.parse и проверял исключение ParseException. Если вы уверены, что дата правильная и она находится в одном из двух шаблонов, вы можете просто проверить, есть ли «.». в строке. – maxvv

+2

@RobertNiestroj Поскольку месяц и день не расположены в одном и том же месте. –

ответ

8

Хорошо, я собираюсь сделать это как ответ. Один из способов - создать класс, который будет содержать шаблоны.

public class Test { 
    public static void main(String[] args){ 
     MyFormatter format = new MyFormatter("dd.MM.yyyy", "M/dd/yyyy"); 
     LocalDate date = format.parse("3/30/2014"); //2014-03-30 
     LocalDate date2 = format.parse("30.03.2014"); //2014-03-30 
    } 
} 

class MyFormatter { 
    private final String[] patterns; 

    public MyFormatter(String... patterns){ 
     this.patterns = patterns; 
    } 

    public LocalDate parse(String text){ 
     for(int i = 0; i < patterns.length; i++){ 
      try{ 
       return LocalDate.parse(text, DateTimeFormatter.ofPattern(patterns[i])); 
      }catch(DateTimeParseException excep){} 
     } 
     throw new IllegalArgumentException("Not able to parse the date for all patterns given"); 
    } 
} 

Вы могли бы улучшить это как @MenoHochschild сделал непосредственно создание массива DateTimeFormatter из массива String вы передаете в конструктор.


Другим способом было бы использовать DateTimeFormatterBuilder, добавляя форматы, которые вы хотите. Там могут быть некоторые другие способы сделать это, я не глубоко разбираюсь в документации :-)

DateTimeFormatter dfs = new DateTimeFormatterBuilder() 
          .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd"))                 
          .appendOptional(DateTimeFormatter.ofPattern("dd.MM.yyyy"))                      
          .toFormatter(); 
LocalDate d = LocalDate.parse("2014-05-14", dfs); //2014-05-14 
LocalDate d2 = LocalDate.parse("14.05.2014", dfs); //2014-05-14 
0

Подход @ZouZou является возможным решением.

Для того, чтобы избежать использования исключений для программной логики, насколько это возможно (тоже не так хорошо производительность повышается) после alternative можно считать:

static final String[] PATTERNS = {"dd.MM.yyyy", "M/dd/yyyy"}; 
static final DateTimeFormatter[] FORMATTERS = new DateTimeFormatter[PATTERNS.length]; 

static { 
    for (int i = 0; i < PATTERNS.length; i++) { 
    FORMATTERS[i] = DateTimeFormatter.ofPattern(PATTERNS[i]); 
    } 
} 

public static LocalDate parse(String input) { 
    ParsePosition pos = new ParsePosition(); 
    for (int i = 0; i < patterns.length; i++) { 
    try { 
     TemporalAccessor tacc = FORMATTERS[i].parseUnresolved(input, pos); 
     if (pos.getErrorIndex < 0) { 
     return LocalDate.from(tacc); // possibly throwing DateTimeException => validation failure 
     } 
    } catch (DateTimeException ex) { // catches also possible DateTimeParseException 
     // go to next pattern 
    } 
    pos.setIndex(0); 
    pos.setErrorIndex(-1); 
    } 
    throw new IllegalArgumentException("Input does not match any pattern: " + input); 
} 

Больше объяснения о методе parseUnresolved():

Этот метод выполняет только первую фазу синтаксического анализа, поэтому нет второй фазы, содержащей предварительную проверку или объединение усилий анализируемых полей. Однако LocalDate.from() проверяет каждый вход, поэтому я думаю, что этого все еще достаточно. Преимущество состоит в том, что parseUnresolved() использует индекс ошибки ParsePosition. Это согласуется с традиционным java.text.Format -behaviour.

К сожалению, альтернативный и более интуитивный метод DateTimeFormater.parse() сначала создает DateTimeParseException, а затем сохраняет индекс ошибки в этом исключении. Поэтому я решил не использовать этот метод, чтобы избежать создания ненужного исключения. Для меня эта подробная информация API является сомнительным дизайнерским решением.