How to parse dates in multiple formats using SimpleDateFormat
Как анализировать даты в нескольких форматах с помощью SimpleDateFormat
Я пытаюсь проанализировать некоторые даты, которые выводятся из документа. Похоже, что пользователи ввели эти даты в похожем, но не точном формате.
вот форматы:
9/09 9/2009 09/2009 9/1/2009 9-1-2009
Каков наилучший способ попытаться проанализировать все это? Они кажутся наиболее распространенными, но я предполагаю, что меня смущает то, что если у меня есть шаблон "M / yyyy", который не будет всегда перехватываться перед "MM / yyyy", должен ли я настраивать свои блоки try / catch, вложенные от наименее ограничительного к наиболее ограничительному способу? похоже, что потребуется много дублирования кода, чтобы сделать это правильно.
Переведено автоматически
Ответ 1
Вам нужно будет использовать разные SimpleDateFormat объекты для каждого отдельного шаблона. Тем не менее, вам не нужно так много разных, благодаря этому:
Число: Для форматирования количество букв шаблона равно минимальному количеству цифр, а более короткие числа дополняются нулем до этого количества. При анализе количество букв шаблона игнорируется, если только это не необходимо для разделения двух смежных полей.
Итак, вам понадобятся эти форматы:
"M/y" (это включает 9/09, 9/2009 и 09/2009)
"M/d/y" (это охватывает 9/1/2009)
"M-d-y" (это охватывает 9-1-2009)
Итак, мой совет был бы написать метод, который работает примерно так (непроверенный):
Date tryParse(String dateString) { for (String formatString : formatStrings) { try { returnnewSimpleDateFormat(formatString).parse(dateString); } catch (ParseException e) {} }
returnnull; }
Ответ 2
Как насчет простого определения нескольких шаблонов? Они могут поступать из файла конфигурации, содержащего известные шаблоны, жестко закодированные, которые читаются как:
for (SimpleDateFormat pattern : knownPatterns) { try { // Take a try returnnewDate(pattern.parse(candidate).getTime());
} catch (ParseException pe) { // Loop on } } System.err.println("No known Date format found: " + candidate); returnnull;
Ответ 3
Matt's approach above is fine, but please be aware that you will run into problems if you use it to differentiate between dates of the format y/M/d and d/M/y. For instance, a formatter initialised with y/M/d will accept a date like 01/01/2009 and give you back a date which is clearly not what you wanted. I fixed the issue as follows, but I have limited time and I'm not happy with the solution for 2 main reasons:
It violates one of Josh Bloch's quidelines, specifically 'don't use exceptions to handle program flow'.
I can see the getDateFormat() method becoming a bit of a nightmare if you needed it to handle lots of other date formats.
If I had to make something that could handle lots and lots of different date formats and needed to be highly performant, then I think I would use the approach of creating an enum which linked each different date regex to its format. Then use MyEnum.values() to loop through the enum and test with if(myEnum.getPattern().matches(date)) rather than catching a dateformatexception.
Anway, that being said, the following can handle dates of the formats 'y/M/d' 'y-M-d' 'y M d' 'd/M/y' 'd-M-y' 'd M y' and all other variations of those which include time formats as well:
publicstatic Date stringToDate(String input){ Datedate=null; StringdateFormat= getDateFormat(input); if(dateFormat == null){ thrownewIllegalArgumentException("Date is not in an accepted format " + input); }
for(String sep : dateSeparators){ StringactualDateFormat= patternForSeparator(dateFormat, sep); //try first with the time for(String time : timeFormats){ date = tryParse(input,actualDateFormat + " " + time); if(date != null){ return date; } } //didn't work, try without the time formats date = tryParse(input,actualDateFormat); if(date != null){ return date; } }