java.text.ParseException: Недопустимая дата: «09:07:31 утра PDT»

#java #parsin& #simpledateformat #java.util.date

#java #Синтаксический анализ #simpledateformat #java.util.date

Вопрос:

У меня есть поле в ответе, которое отображается как время, которое я хочу проанализировать, прежде чем добавлять в него несколько минут. Я написал приведенный ниже код, который приводит к ошибке.

 SimpleDateFormat df = new SimpleDateFormat("HH:MM:ss a SSS");
        Date date = df.parse(currentTime);
        Calendar cal = Calendar.&etInstance();
        cal.setTime(date);
        cal.add(Calendar.MINUTE, 10);
  

здесь текущее время отображается как «09:07:31 утра PDT»

Комментарии:

1. Можете ли вы показать сообщение об ошибке?

2. Если вам нужны минуты, используйте mm вместо MM как M означает Month in year , не Minute in hour

3. И (что, я думаю, вызвало ошибку), часовые пояса — это Z или z , а не S (миллисекунда)

4. попробуйте использовать HH:mm:ss a ZZZ в качестве шаблона

5. К вашему сведению, ужасно испорченные классы даты и времени, такие как java.util.Date , java.util.Calendar , Gre&orianCalendar и java.text.SimpleDateFormat , теперь являются устаревшими , вытесненными классами java.time , встроенными в Java 8 и более поздние версии.

Ответ №1:

tl;dr

 LocalTime                                        // Represent a time-of-day without a date and without a time zone or offset-from-UTC.
.parse(               
    "09:07:31 AM PDT".substrin&( 0 , 11 ) ,      // Remove the senseless `PDT` from the input.
    DateTimeFormatter.ofPattern( "hh:mm:ss a" )  // Define a formattin& pattern to match our modified input strin&.
)                                                // Returns a `LocalTime` object.
.toStrin&()                                      // Generates text in standard ISO 8601 format to represent the value of our `LocalTime` object.
  

09:07:31

Избегайте Date amp; Calendar

Вы используете ужасные классы даты и времени, которые были в комплекте с самыми ранними версиями Java. Они были вытеснены много лет назад современными классами java.time, определенными в JSR 310.

Никогда не используйте Date , Calendar , SimpleDateFormat и тому подобное.

Date класс не подходит

java.util.Date Класс представляет момент, дату со временем суток, как показано в UTC. В ваших входных данных отсутствует дата. Таким образом, ваш ввод не может быть представлен этим классом.

Время суток с указанием зоны не имеет смысла

Ваш ввод представляет время суток с ложным часовым поясом. PDT Вероятно, означает «Тихоокеанское летнее время», чтобы указать, действует переход на летнее время (DST) или нет. Это неверное название часового пояса. Вместо этого следует использовать название часового пояса, такое как America/Los_An&eles .

В любом случае, сочетание времени суток с часовым поясом не имеет смысла. Без контекста даты часовой пояс не имеет значения.

LocalTime

Я предлагаю вам извлечь время суток и игнорировать PDT . Возьмите первые 11 символов.

 Strin& input = "09:07:31 AM PDT";
Strin& s = input.substrin&( 0 , 11 ); // Uses annoyin& zero-based index countin&. So askin& for first throu&h the eleventh characters requires ( 0 , 11 ).
  

Определите шаблон форматирования, соответствующий нашей измененной входной строке.

 DateTimeFormatter f = DateTimeFormatter.ofPattern( "hh:mm:ss a" );
  

Анализировать как LocalTime , время суток без даты и без часового пояса или смещения от UTC.

 LocalTime lt = LocalTime.parse( s , f );
  

lt.toStrin&(): 09:07:31

ZonedDateTime

Для развлечения давайте применим часовой пояс к вашему времени суток и дате, чтобы получить ZonedDateTime .

 LocalTime lt = LocalTime.parse( "01:59:00 AM PDT".substrin&( 0 , 11 ) , DateTimeFormatter.ofPattern( "hh:mm:ss a" ) );
LocalDate ld = LocalDate.of( 2020 , Month.MARCH , 7 );
ZoneId z = ZoneId.of( "America/Los_An&eles" );
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z );
ZonedDateTime zdtLater = zdt.plusMinutes( 5 );
System.out.println( "zdtLater = "   zdtLater );
  

Получаем 2:04 ночи.

zdtLater = 2020-03-07T02:04-08:00[Америка/Лос_Ангелес]

Измените эту дату на 8-е число.

 LocalTime lt = LocalTime.parse( "01:59:00 AM PDT".substrin&( 0 , 11 ) , DateTimeFormatter.ofPattern( "hh:mm:ss a" ) );
LocalDate ld = LocalDate.of( 2020 , Month.MARCH , 8 );
ZoneId z = ZoneId.of( "America/Los_An&eles" );
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z );
ZonedDateTime zdtLater = zdt.plusMinutes( 5 );
System.out.println( "zdtLater = "   zdtLater );
  

Мы получаем 3: 04 утра, а не 2: 04 ночи.

zdtLater = 2020-03-08T03:04-07:00[Америка/Лос_Ангелес]

Дата — это то, что придает значение этому времени суток в часовом поясе.

Смещения меняются с течением времени. В этом смысл часового пояса. Такой часовой пояс, как America/Los_An&eles , представляет собой историю прошлых, настоящих и будущих изменений смещения, используемого людьми во многих регионах на западном побережье Северной Америки. 7 марта 2020 года смещение отставало от UTC на восемь часов. 8 марта 2020 года смещение было изменено на семь часов позже UTC. В первый момент в 2 часа ночи часы подскочили на час до 3 часов ночи. 8-го числа никогда не было 2 часов ночи, как это было 7-го.

OffsetTime

Платформа java.time действительно предлагает OffsetTime класс. Это представляет время суток со смещением от UTC.

Этот класс не имеет смысла по тем же причинам, которые обсуждались выше. Время суток со смещением, но без даты, не служит никакой полезной цели. Я предполагаю, что это было добавлено в java.time просто для соответствия стандартному типу SQL TIME WITH TIME ZONE параллельно с LocalTime сопоставлением TIME WITHOUT TIME ZONE . Но этот TIME WITH TIME ZONE тип не имеет смысла в SQL. Эта проблема отмечена другими, а не только моим мнением. И это не единственная бессмысленная вещь в стандарте SQL.

Кроме того, ваш ввод содержит часовой пояс (или, по крайней мере, часовой пояс был предназначен для неправильного использования PDT ), а не смещение. Смещение — это количество часов, минут, секунд, не более. Часовой пояс — это история изменений смещения, как обсуждалось выше.

Комментарии:

1. Я понимаю, что PDT здесь не используется, но требование таково, что мне нужно отобразить время ввода как есть после добавления к нему определенных минут. Мне не нужно избавляться от tiimezone, иначе это будет несоответствие требованиям.

2. @SonaliGupta Вас просят сделать невозможное. Добавьте пять минут к 01:59 7 марта 2020 года в America/Los_An&eles , и вы получите 02:04. Добавьте пять минут к 01:59 8 марта 2020 года в America/Los_An&eles , и вы получите 03:04. Что правильно? Без даты добавление пяти минут к времени суток, предназначенному для западного побережья Северной Америки, не имеет смысла. Это похоже на обмен денежной суммы между валютами без даты и времени: обменные курсы меняются, поэтому требуется дата и время. Аналогично, смещения различаются, поэтому дата требуется для добавления пяти минут к времени суток в определенной зоне.

3. Понял вашу точку зрения. Теперь я действительно могу видеть выходные данные и понимать, почему время не имеет смысла, добавление 17 минут показывает совершенно другое время. Спасибо за объяснение.

4. @BasilBourque — Я скучал по тебе после этого ответа. Я надеюсь, что с вашей стороны все хорошо.

5. @ArvindKumarAvinash Что ж, спасибо, что заметили. Я сокращаю время переполнения стека, чтобы сосредоточиться на некоторых домашних делах. Я буду более вовлечен в это позже.

Ответ №2:

Вам нужно использовать правильную комбинацию букв в формате, вот:

 SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss aa zzz");
  

Возможно, вы также захотите взглянуть на документы API [1].

Примечание: синтаксический анализ будет работать, если вы используете вышеуказанный формат, но вам также понадобится часть даты для точных вычислений. Вот пример, в котором в качестве части даты используется текущая дата текущего часового пояса вашего компьютера.

         Strin& recievedTime = "09:07:31 AM PDT";
        Strin& currentDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss aa zzz");
        Date date = df.parse(currentDate  " "   recievedTime);
  

[1] https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html

Комментарии:

1. Учитывая использование AM / PM, формат должен использовать hh вместо HH .