Странное поведение в java.text.SimpleDateFormat, ожидающее yyyyMMdd с учетом yyyy-MM-dd - PullRequest
9 голосов
/ 28 июля 2011

Я столкнулся с очень странным поведением при использовании SimpleDateFormat для разбора строки на дату.Рассмотрим следующий модульный тест:

@Test
public void testParse() throws ParseException
{
    DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");

    String dateStr = "2012-12-21";
    Date parsedDate = dateFormat.parse(dateStr);
    Calendar date = Calendar.getInstance();
    date.setTime(parsedDate);

    Assert.assertEquals(2012, date.get(Calendar.YEAR));
    Assert.assertEquals(11, date.get(Calendar.MONTH)); // yeah, Calendar sucks
    Assert.assertEquals(21, date.get(Calendar.DAY_OF_MONTH));
}

Как видно, в приведенном выше коде есть преднамеренная ошибка : SimpleDateFormat инициализируется с "yyyyMMdd", но строкаразбирается в формате "yyyy-MM-dd".Я ожидал бы, что такая вещь приведет к ParseException, или, по крайней мере, будет проанализирована на основе максимальных усилий правильно .Вместо этого по какой-то странной причине дата анализируется как 2011-11-02.Эх!

Это недопустимо, поскольку одна ошибка при обработке входных данных может привести к чему-то совершенно неожиданному / разрушительному.Тем временем перешел на JodaTime, но было бы неплохо понять, что там пошло не так.

Ответы [ 4 ]

12 голосов
/ 28 июля 2011

Извлечение из JavaDoc для setLenient:

public void setLenient(boolean lenient)

Укажите, должен ли анализ даты / времени быть снисходительным.При мягком анализе синтаксический анализатор может использовать эвристика для интерпретации входных данных, которые точно не соответствуют формату этого объекта.
При строгом синтаксическом анализе входные данные должны соответствовать формату этого объекта.

Если вы установите значение false, вы получите ParseException

4 голосов
/ 28 июля 2011

Если вы используете функцию DateFormat.parse(), строка должна соответствовать формату ввода.если он этого не делает, функция синтаксического анализа разбирается неправильно.Вот комментарий об этом в javaDoc:

По умолчанию синтаксический анализ является мягким: если ввод не в форме, используемой методом формата этого объекта, но все еще может быть проанализирован как дата, тогдаРазбор успешен.Клиенты могут настаивать на строгом соблюдении формата, вызывая setLenient (false).

Тогда ваша проблема будет исправлена ​​добавлением строки setLenient(false).В этом случае Java выдает исключение.

2 голосов
/ 28 июля 2011

Ну, вход будет разделен на 3 компонента: год, месяц, день, и вы получите month = -12 и day = -21 (исправление см. Ниже ). Попробуйте разобрать 2012/12/21, и вы получите исключение:)

Редактировать: выдержка из JavaDoc:

Месяц: Если количество букв шаблона составляет 3 или более, месяц интерпретируется как текст; в противном случае оно интерпретируется как число.

Edit2: исправление

Глядя на источник SimpleDateFormat, кажется, что 2012-12-21 на самом деле разделен на это:

year = "2012"
month = "-1"
day = "2-" 

В комментариях источника указано, что - после числа может либо обозначать отрицательное число (в зависимости от локали), либо быть разделителем. В вашем случае это выглядит как разделитель, поэтому day = "2-" приводит к day = 2, следовательно, секунда ноября.

1 голос
/ 28 июля 2011

Вам нужно вызвать setLenient (false).По умолчанию установлено значение true, и Java пытается преобразовать строку, даже если она не соответствует 100%.

...