2015-09-28 3 views
13

Я хотел проверить дату на стороне клиента, поэтому я написал следующий код. Но вместо получения исключения я получаю правильный объект даты для строки даты 31-го февраля, что явно недействительная дата.Java 8 LocalDateTime обрабатывает недопустимую дату

public class Test { 

    public static void main(String[] args) { 
     String dateFormat = "HH:mm:ss MM/dd/yyyy"; 
     String dateString = "11:30:59 02/31/2015"; 
     DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormat, Locale.US); 
     try { 
      LocalDateTime date = LocalDateTime.parse(dateString, dateTimeFormatter); 
      System.out.println(date); 
     } catch (Exception e) { 
      // Throw invalid date message 
     } 
    } 
} 

Выход: 2015-02-28T11: 30: 59

Кто-нибудь знает, почему LocalDateTime является разбор этой даты, вместо того, чтобы бросать исключение.

+0

Почему вы ждете исключения? – Andrew

+2

@AndrewTobilko, предположительно потому, что 31 февраля не существует. – aioobe

+0

Но форматер не знает об этом. – Satya

ответ

21

Вам просто нужно строгое ResolverStyle.

Разбор текстовой строки происходит в две фазы. Фаза 1 представляет собой основной синтаксический анализ текста в соответствии с полями, добавленными к строителю. Фаза 2 разрешает проанализированные пары значений поля в дату и/или временные объекты. Этот стиль используется для контроля того, как происходит этап 2, разрешая его.

Пример кода - где withResolverStyle(ResolverStyle.STRICT) это важное изменение, наряду с использованием uuuu, а не yyyy (где uuuu является «год» и «гггг» является «год эры», и, следовательно, неоднозначной):

import java.time.*; 
import java.time.format.*; 
import java.util.*; 

public class Test { 

    public static void main(String[] args) { 
     String dateFormat = "HH:mm:ss MM/dd/uuuu"; 
     String dateString = "11:30:59 02/31/2015"; 
     DateTimeFormatter dateTimeFormatter = DateTimeFormatter 
      .ofPattern(dateFormat, Locale.US) 
      .withResolverStyle(ResolverStyle.STRICT); 
     try { 
      LocalDateTime date = LocalDateTime.parse(dateString, dateTimeFormatter); 
      System.out.println(date); 
     } catch (DateTimeParseException e) { 
      // Throw invalid date message 
      System.out.println("Exception was thrown"); 
     } 
    } 
} 
+3

Измените yyyy на uuuu в строке формата, тогда вам не нужно возиться с ERA – Palamino

+0

@Palamino: Aha! Красиво сделано, спасибо. –

0

LocalDateTime.parse только выдаст ошибку, если строка передается в содержит недопустимые символы, количество дней, превышающих 31 или месяц превышая 12.

Например, если вы изменили свой код, например:

String dateString = "11:30:59 0zz2/31/2015"; 

исключение будет вызвано недействительными символами «zz» в течение указанной даты. Что касается того, почему это «округление» даты так сказать, что я не знаю.

Источник: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html#parse-java.lang.CharSequence-

+0

Нужно отметить и исправить RealSkeptic. – jste89

2
try { 
    SimpleDateFormat df = new java.text.SimpleDateFormat("HH:mm:ss MM/dd/yyyy"); 
    df.setLenient(false); 
    System.out.println(df.parse("11:30:59 02/29/2015")); 
} catch (java.text.ParseException e) { 
    System.out.println(e); 
} 

Я нашел одно решение признать дату как действительную дату с DateFormat.setLenient(boolean). Если вы попытаетесь разобрать любую недействительную дату, она выдает исключение синтаксического анализа.

Edit:

Java 8, но это поднимет исключение, если через месяц не между 1 и 12, если в день больше, чем 32. Точно не работает. Но за месяц его работала.

try { 
TemporalAccessor ta = DateTimeFormatter.ofPattern("HH:mm:ss MM/dd/yyyy").parse("11:30:59 02/32/2015"); 
} catch (Exception e) { 
System.out.println(e); 
} 

Выход:

java.time.format.DateTimeParseException: Text '11:30:59 02/32/2015' could not be 
parsed: Invalid value for DayOfMonth (valid values 1 - 28/31): 32 
+0

'SimpleDateFormat' не работает с Java 8' LocalDateTime'. Я ищу решение с Java8 LocalDateTime – Zeeshan

7

Java-8 DateTimeFormatter использует гггг означает YEAR_OF_ERA и уууу означает YEAR. Вы должны изменить вашу строку шаблона следующим образом:

String dateFormat = "HH:mm:ss MM/dd/uuuu"; 

The DateTimeFormatter по умолчанию для использования SMART стиля распознавателя, но вы хотите его использовать строгий стиль распознавателя.Измените код инициализации dateTimeFormatter следующим образом:

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormat, Locale.US) 
                 .withResolverStyle(ResolverStyle.STRICT); 
2

Это не округление. В феврале никогда не было 31 дня, и невозможно использовать проверяющий объект даты/времени для представления дня, который не существует.

В результате он принимает неверный ввод и дает наилучшее приближение к правильной дате (последняя дата февраля того же года).

SimpleDateFormat унаследовано от DateFormat, у которого есть метод setLenient(boolean value). Я ожидал бы, что если вы вышли на сайт setLenient(true) до разбора, он, вероятно, пожаловался бы больше, as detailed in the javadocs.

Смежные вопросы