Java - Неразрешимая дата
Я пытаюсь проанализировать дату, но странным образом получаю исключение.
Это код:
import java.util.Date;
String strDate = "Wed, 09 Feb 2011 12:34:27";
Date date;
SimpleDateFormat FORMATTER = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
try {
date = FORMATTER.parse(strDate.trim());
System.out.println(date);
} catch (ParseException e) {
e.printStackTrace();
}
Исключение составляет:
Исключение java.text.ParseException: неразрешимая дата: "Ср., 09 февраля 2011 г. 12:34:27" в java.text.DateFormat.parse(DateFormat.java:337) в DateTest.main(DateTest.java:17)
Я прочитал документацию и думаю, что мой шаблон правильный. Поэтому я не понимаю...
Есть идеи?
Спасибо!
Переведено автоматически
Ответ 1
Вероятно, это из-за того, что язык по умолчанию на вашем компьютере не английский.
Вам следует использовать:
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss", Locale.ENGLISH);
вместо этого.
Ответ 2
tl; dr
java.util.Date.from (
LocalDateTime.parse(
"Wed, 09 Feb 2011 12:34:27" ,
DateTimeFormatter.ofPattern( "EEE, dd MMM uuuu HH:mm:ss" , Locale.US )
).atZone( ZoneId.of( "America/Montreal" ) )
.toInstant()
)
Подробные сведения
В вопросе и другом ответе используются устаревшие, вызывающие проблемы старые классы даты и времени, которые теперь являются устаревшими, вытесненными классами java.time .
Использование java.time
Во входной строке отсутствуют какие-либо указания часового пояса или смещения от UTC. Поэтому мы анализируем как OffsetDateTime
.
Укажите a Locale
, чтобы определить (а) человеческий язык для перевода названия дня, названия месяца и тому подобного, и (б) культурные нормы, решающие вопросы аббревиатур, заглавных букв, знаков препинания, разделителей и тому подобного.
String input = "Wed, 09 Feb 2011 12:34:27" ;
Locale l = Locale.US ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "EEE, dd MMM uuuu HH:mm:ss" , l ) ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
ldt.toString(): 2011-02-09T12:34:27
Часовой пояс
И Вопрос, и другой ответ игнорируют важную проблему часового пояса.
Во входной строке отсутствует часовой пояс или смещение. Мы проанализировали как, LocalDateTime
который не является моментом на временной шкале, только смутное представление о возможных моментах. Подобно высказыванию "Рождество начинается в полночь 25 декабря 2017 года", это не имеет смысла, пока вы не разместите его в контексте определенного часового пояса. Рождество в Окленде, Новая Зеландия, наступает намного раньше, чем в Париже, Франция, и еще намного позже в Монреале, Квебек.
Если вы знаете предполагаемый часовой пояс, назначьте ZoneId
для получения ZonedDateTime
.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ldt.atZone( z ); // Assigning a time zone to determine an actual moment on the timeline.
Преобразование
Лучше избегать проблемных старых устаревших классов даты и времени. Но если вам необходимо взаимодействовать со старым кодом, еще не обновленным до типов java.time, вы можете выполнить преобразование между устаревшими классами и java.time. Ищите новые методы, добавляемые к старым классам.
A java.util.Date
- это момент на временной шкале по UTC. Итак, нам нужно извлечь Instant
из нашего ZonedDateTime
. Instant
Класс представляет момент на временной шкале в UTC с разрешением в наносекунды (до девяти (9) знаков десятичной дроби).
Instant instant = zdt.toInstant() ;
java.util.Date d = java.util.Date.from( instant ) ; // Convert from java.time to legacy class.
Идем в другом направлении.
Instant instant = d.toInstant() ; // Convert from legacy class to java.time class.
ZonedDateTime zdt = instant.atZone( z ) ; // Adjust from UTC into a particular time zone.
О java.time
Платформа java.time встроена в Java 8 и более поздние версии. Эти классы заменяют старые, вызывающие беспокойство, устаревшие классы даты и времени, такие как java.util.Date
, Calendar
, & SimpleDateFormat
.
Проект Joda-Time, который сейчас находится в режиме обслуживания, рекомендует перейти на классы java.time.
Чтобы узнать больше, ознакомьтесь с Руководством по Oracle. И найдите в Stack Overflow множество примеров и пояснений. Спецификация - 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) проект ThreeTenABP адаптирует ThreeTen-Backport (упомянутый выше). Смотрите , как использовать ThreeTenABP ....
Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является испытательным полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval
, YearWeek
, YearQuarter
и больше.
Ответ 3
Никогда не используйте SimpleDateFormat
или DateTimeFormatter
без Locale
Поскольку данная дата и время указаны на английском языке, вы должны использовать Locale.ENGLISH
с вашим анализатором даты и времени; в противном случае произойдет сбой синтаксического анализа в системе (компьютере, телефоне и т.д.), которая использует неанглоязычный тип локали.
Также обратите внимание, что API даты и времени java.util
и их API форматирования, SimpleDateFormat
устарели и подвержены ошибкам. Рекомендуется полностью прекратить их использование и переключиться на современный API для определения даты и времени.
- По какой-либо причине, если вам нужно придерживаться Java 6 или Java 7, вы можете использовать ThreeTen-Backport, который переносит большую часть функций java.time в Java 6 и 7.
- Если вы работаете над проектом Android и ваш уровень API Android по-прежнему не совместим с Java-8, проверьте API Java 8 +, доступные через десугаринг и Как использовать ThreeTenABP в Android Project.
ДЕМОНСТРАЦИЯ:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
final String strDateTime = "Wed, 09 Feb 2011 12:34:27";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE, dd MMM uuuu HH:mm:ss", Locale.ENGLISH);
LocalDateTime ldt = LocalDateTime.parse(strDateTime, dtf);
System.out.println(ldt);
}
}
Вывод:
2011-02-09T12:34:27
По умолчанию DateTimeFormatter#ofPattern
использует локаль ФОРМАТА по умолчанию, которую JVM устанавливает при запуске в зависимости от среды хоста. То же самое происходит с SimpleDateFormat
. Я попытался проиллюстрировать проблему с помощью следующей демонстрации:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
final String strDateTime = "Wed, 09 Feb 2011 12:34:27";
DateTimeFormatter dtfWithDefaultLocale = null;
System.out.println("JVM's Locale: " + Locale.getDefault());
// Using DateTimeFormatter with the default Locale
dtfWithDefaultLocale = DateTimeFormatter.ofPattern("EEE, dd MMM uuuu HH:mm:ss");
System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
System.out
.println("Parsed with JVM's default locale: " + LocalDateTime.parse(strDateTime, dtfWithDefaultLocale));
// Setting the JVM's default locale to Locale.FRANCE
Locale.setDefault(Locale.FRANCE);
// Using DateTimeFormatter with Locale.ENGLISH explicitly (recommended)
DateTimeFormatter dtfWithEnglishLocale = DateTimeFormatter.ofPattern("EEE, dd MMM uuuu HH:mm:ss",
Locale.ENGLISH);
System.out.println("JVM's Locale: " + Locale.getDefault());
System.out.println("DateTimeFormatter's Locale: " + dtfWithEnglishLocale.getLocale());
LocalDateTime zdt = LocalDateTime.parse(strDateTime, dtfWithEnglishLocale);
System.out.println("Parsed with Locale.ENGLISH: " + zdt);
System.out.println("JVM's Locale: " + Locale.getDefault());
// Using DateTimeFormatter with the default Locale
dtfWithDefaultLocale = DateTimeFormatter.ofPattern("EEE, dd MMM uuuu HH:mm:ss");
System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
System.out
.println("Parsed with JVM's default locale: " + LocalDateTime.parse(strDateTime, dtfWithDefaultLocale));
}
}
Вывод:
JVM's Locale: en_GB
DateTimeFormatter's Locale: en_GB
Parsed with JVM's default locale: 2011-02-09T12:34:27
JVM's Locale: fr_FR
DateTimeFormatter's Locale: en
Parsed with Locale.ENGLISH: 2011-02-09T12:34:27
JVM's Locale: fr_FR
DateTimeFormatter's Locale: fr_FR
Exception in thread "main" java.time.format.DateTimeParseException: Text 'Wed, 09 Feb 2011 12:34:27' could not be parsed at index 0
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:492)
at Main.main(Main.java:33)
Следующая демонстрация с использованием SimpleDateFormat
приведена просто для полноты картины:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) throws ParseException {
final String strDateTime = "Wed, 09 Feb 2011 12:34:27";
SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss", Locale.ENGLISH);
Date date = sdf.parse(strDateTime);
System.out.println(date);
}
}
Вывод:
Wed Feb 09 12:34:27 GMT 2011