Исключение в потоке «main» java.time.format.DateTimeParseException: текст «1 апреля 2022 г., 12:00:00:000AM» не удалось проанализировать по индексу 19

У меня есть формат даты, например Apr 1 2022 12:00:00:000AM, и я хочу преобразовать его в 20220401 (ггггММдд). Как мы можем преобразовать формат даты

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Demo {
    public static void main(String[] args) {
        String value = "Apr  1 2022 12:00:00:000AM";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM d yyyy hh:mm:ss.SSSa");
        LocalDateTime dateTime = LocalDateTime.parse(value, formatter);
        System.out.println(dateTime);
    }
}

При запуске этого кода выдается ошибка ниже

Exception in thread "main" java.time.format.DateTimeParseException: Text 'Apr  1 2022 12:00:00:000AM' could not be parsed at index 4
    at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
    at java.time.LocalDateTime.parse(LocalDateTime.java:492)
    at Demo.main(Demo.java:10)

РЕДАКТИРОВАТЬ-1 Согласно предложениям Василия Бурка, ниже все еще не работает

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Demo {
    public static void main(String[] args) {
        String value = "Apr  1 2022 12:00:00:000AM".replace( "  " , " " ) ;
        Locale locale = new Locale.Builder().setLanguage("en").setRegion("US").build();
        DateTimeFormatter formatter = 
                DateTimeFormatter.
                ofPattern("MMM d yyyy hh:mm:ss.SSSa")
                .withLocale( locale ) ;
        
        LocalDateTime dateTime = LocalDateTime.parse(value, formatter);
        System.out.println(dateTime);
    }
}

Все та же ошибка

Exception in thread "main" java.time.format.DateTimeParseException: Text 'Apr 1 2022 12:00:00:000AM' could not be parsed at index 19

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

Sotirios Delimanolis 16.07.2024 15:29
could not be parsed at index 19 — В шаблоне формата вместо двоеточия стоит точка.
OneCricketeer 16.07.2024 15:49

вы не можете ожидать, что 12:00:00:000 соответствует hh:mm:ss.SSS - сначала используется : для отделения секунд от миллисекунд, а в шаблоне используется .

user85421 16.07.2024 15:49

Кстати: LocalDateTime.parse("Apr 1 2022 12:00:00:000AM", DateTimeFormatter.ofPattern("MMM [ ]d yyyy hh:mm:ss:SSSa", Locale.ROOT)) работает ( replace не нужно)

user85421 16.07.2024 15:53

Не храните даты в строках. Тогда вам также не нужно будет преобразовывать строку в одном формате в строку в другом формате. Если ваша дата взята из базы данных, получите LocalDate, OffsetDateTime или другой подходящий тип даты и времени в зависимости от типа данных в базе данных. Если вам нужен yyyymmdd для обмена данными, используйте встроенный BASIC_ISO_DATE форматтер.

Anonymous 16.07.2024 17:08

У вас есть два пробела после Apr? Что происходит, когда день месяца равен 10 или больше? Если число дополнено пробелами (выровнено по правому краю), посмотрите на букву шаблона формата p, чтобы узнать, как его проанализировать.

Anonymous 16.07.2024 17:16

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

Anonymous 22.07.2024 10:38
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
7
133
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

вр; доктор

  • Определенный вами шаблон форматирования не соответствует введенным вами данным по нескольким причинам.
  • Всегда указывайте Locale при анализе локализованного текста.
  • По возможности используйте только стандартные форматы ISO 8601 для текстового обмена значениями даты и времени.

ПРОСТРАНСТВЕННЫЙ символ

Между первыми двумя частями есть два символа ПРОБЕЛ. Замените одним ПРОБЕЛОМ.

 String value = "Apr  1 2022 12:00:00:000AM".replace( "  " , " " ) ;

Альтернативно вы можете указать необязательный ПРОБЕЛ в шаблоне форматирования с помощью квадратных скобок: [ ].

COLON персонаж

В вашем шаблоне форматирования указано, что между секундой и AM/PM следует ожидать символ ПОЛНОЙ СТОП (.). Но в вашей входной строке есть Двоеточие (:).

Измените шаблон форматирования в соответствии с введенными вами данными.

Locale

Укажите Locale явно, а не неявно, полагаясь на текущее значение по умолчанию JVM.

Locale locale = new Locale( "en" , "US" ) ;  // In Java 19+, use `Locale.of`. 
DateTimeFormatter formatter = 
        DateTimeFormatter
        .ofPattern("MMM d yyyy hh:mm:ss:SSSa");
        .withLocale( locale ) ;

Locale указывает человеческий язык и культурные нормы, которые будут использоваться при локализации. Сюда входит написание названия месяца и использование знаков препинания.

Генерация текста

Чтобы создать желаемый текст, извлеките LocalDate, чтобы сосредоточиться на дате без времени суток.

LocalDate ld = myLocalDateTime.toLocalDate() ;

Затем определите форматировщик для вашего формата.

В вашем случае нет необходимости определять собственный форматтер. Требуемый форматтер соответствует «базовой» форме стандартного формата ISO 8601, которая сводит к минимуму знаки препинания. Java предоставляет константу для этого конкретного формата: BASIC_ISO_DATE.

String output = ld.format( DateTimeFormatter.BASIC_ISO_DATE ) ;

Пример кода

    String input = "Apr  1 2022 12:00:00:000AM".replace( "  " , " " ) ;
    Locale locale =new  Locale( "en" , "US" ) ;  // In Java 19+, use `Locale.of`. 
    DateTimeFormatter formatter = 
        DateTimeFormatter
        .ofPattern("MMM d yyyy hh:mm:ss:SSSa")
        .withLocale( locale );
    LocalDateTime ldt = LocalDateTime.parse( input , formatter ) ;
    LocalDate ld = ldt.toLocalDate();
    String output = ld.format( DateTimeFormatter.BASIC_ISO_DATE ) ;
    System.out.println( output ) ;

Посмотрите этот код запустите на Ideone.com.

ИСО 8601

Избегайте анализа текста в пользовательских форматах и ​​избегайте анализа локализованного текста.

Международный стандарт ISO 8601 определяет понятные, простые и надежные форматы для обмена значениями даты и времени в виде текста. Они легко читаются как машинами, так и людьми разных культур.

Классы java.time по умолчанию используют ISO 8601 при синтаксическом анализе/генерации текста.

Идеальным решением является информирование издателя ваших данных о преимуществах использования ISO 8601.

Ваш вклад должен быть: 2022-04-01T00:00.

Спасибо Locale locale = Locale.of( "en" , "US" ) ; не работает с Java8?

PAA 16.07.2024 15:26

@Prateek Тогда используйте более старую технику для создания экземпляра Locale.

Basil Bourque 16.07.2024 15:27

С чего вы взяли, что это проблема локализации?

Sotirios Delimanolis 16.07.2024 15:28

У вас есть несколько ошибок в DateTimeFormatter.

  1. Между месяцем и днем ​​есть два пробела. Вот почему Java выдает следующую ошибку:

java.time.format.DateTimeParseException: текст «1 апреля 2022 г., 12:00:00:000AM» не удалось проанализировать по индексу 4

  1. Как написал @Basil в своем ответе, вам лучше передать Locale для правильного анализа вашей даты, поскольку Apr не будет анализироваться, если вы используете другую систему, например, итальянскую, которая принимает только apr.

  2. Наконец, у вас есть двоеточие (:) для разделения секунд и миллисекунд, а ваше значение содержит точку (.).

Это фиксированная версия вашего кода:

public class Demo {
    public static void main(String[] args) {
        String value = "Apr  1 2022 12:00:00:000AM";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM  d yyyy hh:mm:ss:SSSa", Locale.US);
        LocalDateTime dateTime = LocalDateTime.parse(value, formatter);
        System.out.println(dateTime);
    }
}

Отказ от ответственности: я внес изменения только в ваш DateTimeFormatter, предполагая, что вам придется придерживаться этого конкретного формата. Однако если вы создаете значения для анализа, не добавляйте лишние пробелы и используйте стандартные символы для разделения каждой группы.

Я писал свой ответ с ошибкой пробела и точки, когда @Basil опубликовал свой ответ только с решением Locale. Я был недостаточно быстр.

dani-vta 16.07.2024 15:37

Будут ли их строки дат с двухзначными датами иметь один пробел или два? Apr 13 или Apr 13?

Sotirios Delimanolis 16.07.2024 15:50

@SotiriosDelimanolis форматтеру все равно понадобятся два пробела независимо от количества цифр в дне (Apr 1 или Apr 11), если им нужно/хотят соблюдать этот формат.

dani-vta 16.07.2024 15:54

Это то, чего я добивался. Если их даты будут иметь вид Apr 13, то ваш формат подойдет. Но если второй пробел предназначен для механизма выравнивания, а их даты на самом деле заканчиваются как Apr 13 (одиночный пробел), тогда ваш формат не будет работать.

Sotirios Delimanolis 16.07.2024 15:56

@Sotirios Delimanolis Нет, это не уловка, чтобы восполнить пропущенную цифру. Это работает как для Apr 1, так и для Apr 13. Попробуйте это на onecompiler.com/java/42kbe6jh5

dani-vta 16.07.2024 16:00

Это не работает для Apr 13 (разделитель одинарного пробела). Я говорю, что мы не знаем, как форматируются строки OP для дат, отличных от однозначных цифр.

Sotirios Delimanolis 16.07.2024 16:03

@SotiriosDelimanolis ок, я наконец-то понял твою точку зрения. Я могу основывать свой ответ только на том, что опубликовано в вопросе. Как я сказал в своем ответе: «предполагая, что вам придется придерживаться этого конкретного формата». Я предполагаю, что это (двойное пространство) формат, который они хотят/должны использовать (по какой-либо причине).

dani-vta 16.07.2024 16:04

Кстати, необязательный пробел в шаблоне может быть представлен как "MMM [ ]d yyyy hh:mm:ss:SSSa"

user85421 16.07.2024 16:17

Другие вопросы по теме