java.text.ParseException: Неразборчивая дата - PullRequest
9 голосов
/ 31 августа 2011

Я получаю следующую ошибку: ´java.text.ParseException: Неразборчивая дата: «31 августа 09:53:19 2011» ´ с этим форматом: new SimpleDateFormat("MMM dd HH:mm:ss yyyy");

Кто-нибудь видит проблему?

Ответы [ 3 ]

26 голосов
/ 31 августа 2011

Убедитесь, что вы используете правильную локаль. (Конструктор SimpleDateFormat(String) использует системный языковой стандарт по умолчанию , который может быть не тем, который вы хотите использовать.)

Это прекрасно работает на моей машине:

String input = "Aug 31 09:53:19 2011";
DateFormat df = new SimpleDateFormat("MMM dd HH:mm:ss yyyy", Locale.US);
System.out.println(df.parseObject(input));

(При использовании, например, Locale.FRENCH, получается ParseException.)

6 голосов
/ 31 августа 2011

Сам формат в порядке для ввода, который вы дали.Но вы можете получить эту ошибку, если в качестве локали по умолчанию задано нечто, где «Aug» не является допустимым сокращением названия месяца.Попробуйте использовать, например, Locale.US, и вы увидите, что он будет работать:

DateFormat df = new SimpleDateFormat("MMM dd HH:mm:ss yyyy", Locale.US);
Date date = df.parse("Aug 31 09:53:19 2011");
5 голосов
/ 18 августа 2015

ТЛ; др

  • Укажите Locale, чтобы определить человеческие языковые и культурные нормы, используемые при переводе названия месяца.
  • Используйте современные java.time классы, а не утомительные унаследованные классы.

Придуманный пример:

LocalDateTime.parse(                                       // Parse input text as a `LocalDateTime` lacking any concept of time zone or offset-from-UTC.
    "Aug 31 09:53:19 2011" , 
    DateTimeFormatter.ofPattern( "MMM dd HH:mm:ss yyyy" )  // Specify formatting pattern to match input string.
                     .withLocale( Locale.US )              // The `Locale` determines the human language and cultural norms used in translating the input text.
)                                                          // Returns a `LocalDateTime` object.

Подробнее

Два других ответа от aioobe и от Jesper являются правильными: неявно используется Locale с человеческим языком, который не соответствует языку вашего ввода текста.

Этот ответ объясняет новый способ выполнения работы. Кроме того, в других Ответах не рассматривается ключевой вопрос о часовом поясе.

java.time

Перенесемся через несколько лет из этой публикации, и теперь у нас есть новый java.time пакет , встроенный в Java 8 и более поздние версии. Эти новые классы вытесняют старые классы java.util.Date/.Calendar & SimpleDateFormat. Эти старые классы оказались неприятными, запутанными и ошибочными.

Шаблон форматера

Определите данные для анализа и их формат.

String input = "Aug 31 09:53:19 2011";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "MMM dd HH:mm:ss uuuu" );

Если не указано, DateTimeFormatter назначается Locale, который в настоящее время является значением по умолчанию в JVM. Это значение по умолчанию может измениться в любой момент, даже во время выполнения (!). Поэтому всегда указывайте желаемый / ожидаемый Locale.

formatter = formatter.withLocale( Locale.US );  // Or Locale.UK, Locale.CANADA_FRENCH, etc.

Учитывая, что на входе отсутствует какая-либо информация о часовом поясе или смещении от - UTC , анализируйте как LocalDateTime.

LocalDateTime ldt = LocalDateTime.parse( input , formatter );

Если из контекста вы знаете предполагаемое смещение от UTC или часовой пояс для этого значения даты и времени, присвойте его.

Если UTC, используйте константу ZoneOffset.UTC, чтобы получить объект OffsetDateTime.

OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC );

Часовой пояс - это смещение от UTC плюс набор правил для обработки аномалий, таких как летнее время (DST). Используйте правильные имена часовых поясов , никогда не используйте 3-4 буквенных сокращения .

ZoneId zoneId_Montreal = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ldt.atZone( zoneId_Montreal );

Укажите часовой пояс

Этот элемент человеческого языка был ключевым недостающим элементом для ответа на Вопрос. Указание правильного Locale для человеческого языка, соответствующего языку вашей входной строки, решает эту проблему.

Но учтите, что часовой пояс также важен; другие ответы игнорировали эту проблему, тем самым неявно используя текущий часовой пояс JVM по умолчанию. Это не рекомендуется, поскольку это зависит от операционной системы хоста в качестве начального значения по умолчанию (может варьироваться), и, кроме того, любой код в любом потоке любого приложения в JVM может изменить текущий часовой пояс JVM по умолчанию во время время выполнения. Лучше указать желаемый / ожидаемый часовой пояс, чем неявно полагаться на значение по умолчанию.

Неизменяемые объекты

Обратите внимание на синтаксис. Эти классы разработаны, чтобы быть неизменными . Таким образом, вместо изменения (изменения) объекта создается новый новый объект на основе значений старого объекта. Это означает, что мы не влияем на объект DateTimeFormatter, определенный выше и содержащийся в переменной formatter (ссылка на объект). Мы создаем, используем и отбрасываем новый объект DateTimeFormatter (фактически, два новых объекта) в этой строке кода.

Справочник методов

Документация предлагает альтернативный способ разбора строки - вызвать метод parse, где вы передаете ссылку на метод (новое в Java 8) из класса какой результат вы желаете (например, TemporalQuery): ZonedDateTime::from, LocalDateTime::from, LocalDate::from и т. д.

ZonedDateTime zdt = formatter.withZone( zoneId_Montreal ).withLocale( Locale.ENGLISH ).parse( input, ZonedDateTime :: from );

Для демонстрации давайте развернемся и создадим строковое представление этого значения ZonedDateTime, но на французском языке Québécois.

String output = formatter.withLocale( Locale.CANADA_FRENCH ).format( zdt );

Еще лучше, давайте локализуем, а не жестко кодируем определенный формат.

String outputLocalized = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ).format( zdt );

Дамп на консоль.

System.out.println( "input: " + input );
System.out.println( "formatter: " + formatter );
System.out.println( "zdt: " + zdt );
System.out.println( "output: " + output );
System.out.println( "outputLocalized: " + outputLocalized );

При запуске.

input: Aug 31 09:53:19 2011
formatter: Text(MonthOfYear,SHORT)' 'Value(DayOfMonth,2)' 'Value(HourOfDay,2)':'Value(MinuteOfHour,2)':'Value(SecondOfMinute,2)' 'Value(YearOfEra,4,19,EXCEEDS_PAD)
zdt: 2011-08-31T09:53:19-04:00[America/Montreal]
output: août 31 09:53:19 2011
outputLocalized: mercredi 31 août 2011 9 h 53 EDT

О java.time

The java.time Framework встроен в Java 8 и более поздние версии.Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat

Проект Joda-Time , теперь в режиме обслуживания , рекомендует перейти на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial .И поиск переполнения стека для многих примеров и объяснений.Спецификация: JSR 310 .

Вы можете обмениваться java.time объектами непосредственно с вашей базой данных.Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии.Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

  • Java SE 8 , Java SE 9 , Java SE 10, а позже
    • Встроенный.
    • Часть стандартного Java API с встроенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функций java.time перенесена на Java 6 & 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии реализации комплекта Android классов java.time.
    • Для более ранних версий Android (<26) проект <a href="https://github.com/JakeWharton/ThreeTenABP" rel="nofollow noreferrer"> ThreeTenABP адаптируется ThreeTen-Backport (упомянуто выше).См. Как использовать ThreeTenABP… .
...