WedX - журнал о программировании и компьютерных науках

Java не может проанализировать дату при использовании точек. вместо тире -

У меня непонятная проблема, рассмотрите этот рабочий код:

package com.mycompany.mavenproject2;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Main {
  public static void main(String[] args) throws ParseException {
    SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
    
    Date date = formatter.parse("01-Jan-2017 00:47:13");
    System.out.println(date);
  }
}

который печатает Sun Jan 01 00:47:13 CET 2017 при выполнении должным образом.

Однако, когда я заменяю каждый - точкой . в дате:

package com.mycompany.mavenproject2;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Main {
  public static void main(String[] args) throws ParseException {
    SimpleDateFormat formatter = new SimpleDateFormat("dd.MMM.yyyy HH:mm:ss");
    
    Date date = formatter.parse("01.Jan.2017 00:47:13");
    System.out.println(date);
  }
}

Код выдает исключение при выполнении:

Exception in thread "main" java.text.ParseException: Unparseable date: "01.Jan.2017 00:47:13"
    at java.base/java.text.DateFormat.parse(DateFormat.java:395)
    at com.mycompany.mavenproject2.Main.main(Main.java:11)

Я использую версию Java 12 и немецкий язык.

Есть у кого-нибудь идея?


  • Если я правильно читаю документацию, любой простой текст во входных данных должен точно соответствовать строке формата. Кажется, что нет оператора либо / или, ни оператора сопоставления. Для сложных строк вам, возможно, придется найти другой класс или выполнить синтаксический анализ самостоятельно. 03.05.2021
  • Всегда используйте Locale с типом синтаксического анализа / форматирования даты и времени. Ознакомьтесь с ответами на этот вопрос, чтобы узнать об этом подробнее. Ваш код работает для меня, потому что мой Locale по умолчанию поддерживает его. Однако я настоятельно рекомендую вам сделать это, как это сделано в этом решении. 03.05.2021
  • @markspace - но он ожидает, что буквальная точка в формате будет соответствовать буквальной точке во входных данных. 03.05.2021
  • Также обратите внимание, что устаревший API даты и времени (java.util типы даты и времени и их API форматирования, SimpleDateFormat) устарел и подвержен ошибкам. Рекомендуется полностью отказаться от его использования и перейти на java.time, современный API даты и времени 03.05.2021
  • Я воспроизвел описанное поведение на Java 11 с немецким языком по умолчанию. 03.05.2021

Ответы:


1

java.time

Я полностью согласен с комментариями, рекомендующими java.time, современный API даты и времени Java, для вашей работы с датой и временем.

Используйте это средство форматирования:

private static final DateTimeFormatter FORMATTER
        = DateTimeFormatter.ofPattern("dd.MMMuuuu HH:mm:ss", Locale.GERMAN);

Do:

    LocalDateTime dateTime = LocalDateTime.parse("01.Jan.2017 00:47:13", FORMATTER);
    System.out.println(dateTime);

Вывод при запуске на Java 11 с немецкой локалью:

2017-01-01T00:47:13

Вы можете спросить, почему по сравнению с вашей строкой шаблона формата я пропустил вторую точку? В Java 11 (и, вероятно, рядом с версиями Java, возможно, начиная с Java 9–16) немецкие сокращения месяцев имеют точку для обозначения аббревиатуры, поэтому Jan. для января (январь) и т. Д. Таким образом, в моем формате MMM соответствует Jan., а затем uuuu соответствует 2017 г.

Для более полного рассказа Java получает данные о локали, включая сокращения месяцев, используемые в разных регионах, из четырех источников, и не все источники согласны с тем, как выглядят сокращения месяцев на немецком языке. Начиная с Java 9, значение по умолчанию - CLDR,COMPAT, что означает, что предпочтительны данные языкового стандарта из CLDR, репозитория данных общего языкового стандарта Unicode. В том числе и упомянутые мной точки. Вы можете получить разные результаты, задав для системного свойства java.locale-providers значение, которое не начинается с CLDR.

Что пошло не так в вашем коде?

Я уже дал вам подсказку: в некоторых версиях Java сокращенные обозначения месяцев на немецком языке отмечены точкой. Итак, в вашем примере с точками в качестве разделителей ваш SimpleDateFormat сопоставил dd.MMM (без второй точки) с 01.Jan. (со второй точкой). В соответствии с форматом теперь должна появиться точка, но поскольку эта точка уже была использована, SimpleDateFOrmat посмотрел на 2017, решил, что это не точка, и выдал исключение, которое вы видели.

По-настоящему удивительное поведение было в вашем первом примере, когда SimpleDateFormat смог проанализировать 01-Jan-2017 00:47:13 без точек, хотя считает, что сокращение месяца должно заканчиваться точкой. Я видел буквально сотни примеров удивительного поведения SimpleDateFormat раньше, но никогда не видел ничего подобного этому.

И все эти сюрпризы заставляют меня сказать: всеми способами избегайте использования SimpleDateFormat.

Если вы настроены скептически, я вас не виню. Итак, чтобы продемонстрировать:

    SimpleDateFormat formatter = new SimpleDateFormat("MMMyyyy", Locale.GERMAN);
    
    System.out.println(formatter.format(0L));
    
    System.out.println(formatter.parse("Jan2017"));
    System.out.println(formatter.parse("Jan.2017"));

Вывод, все еще на Java 11:

Jan.1970
Sun Jan 01 00:00:00 CET 2017
Sun Jan 01 00:00:00 CET 2017

Мы видим, что SimpleDateFormat форматирует месяц с помощью точки и может анализировать строки как с точками, так и без них.

Это еще не все.

    SimpleDateFormat formatter = new SimpleDateFormat("MMM", Locale.GERMAN);

    System.out.println(formatter.format(0L));

Вывод:

Jan

На этот раз аббревиатура месяца была отформатирована без точки. Я понятия не имел, что происходит. Повторяю, забудьте о запутанном классе SimpleDateFormat. Это печально известный возмутитель спокойствия.

Ссылки

03.05.2021
Новые материалы

Как проанализировать работу вашего классификатора?
Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

Работа с цепями Маркова, часть 4 (Машинное обучение)
Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

Учебные заметки: создание моего первого пакета Node.js
Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

ИИ в аэрокосмической отрасли
Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


Для любых предложений по сайту: [email protected]