Разбор даты с коротким месяцем без точки - PullRequest
14 голосов
/ 28 октября 2009

У меня есть строка, которая представляет дату в Французский Язык: 09-окт-08:

Мне нужно разобрать этой строки, поэтому я придумал этот SimpleDateFormat:

String format2 = "dd-MMM-yy";

Но у меня есть проблема с частью месяца, которая, как представляется, ожидается с конечной точкой:

df2.format(new Date());

дает мне:

 28-oct.-09

Каков сейчас лучший способ для меня, чтобы SimpleDateFormat понимал («09-окт-08»)?

Полный код:

String format2 = "dd-MMM-yy"; 
DateFormat df2 = new SimpleDateFormat(format2,Locale.FRENCH); 
date = df2.parse("09-oct-08"); 

Это дает мне: java.text.ParseException: Неразборчивая дата: "09-окт-08" ​​

А если я тогда попробую войти:

df2.format(new Date()); 

Получаю: 28-окт.-09

Ответы [ 6 ]

6 голосов
/ 28 октября 2009

Это похоже на работу:

    DateFormatSymbols dfsFr = new DateFormatSymbols(Locale.FRENCH);
    String[] oldMonths = dfsFr.getShortMonths();
    String[] newMonths = new String[oldMonths.length];
    for (int i = 0, len = oldMonths.length; i < len; ++ i) {
        String oldMonth = oldMonths[i];

        if (oldMonth.endsWith(".")) {
            newMonths[i] = oldMonth.substring(0, oldMonths[i].length() - 1);
        } else {
            newMonths[i] = oldMonth;
        }
    }
    dfsFr.setShortMonths(newMonths);
    DateFormat dfFr = new SimpleDateFormat(
        "dd-MMM-yy", dfsFr);

    // English date parser for creating some test data.
    DateFormat dfEn = new SimpleDateFormat(
        "dd-MMM-yy", Locale.ENGLISH);
    System.out.println(dfFr.format(dfEn.parse("10-Oct-09")));
    System.out.println(dfFr.format(dfEn.parse("10-May-09")));
    System.out.println(dfFr.format(dfEn.parse("10-Feb-09")));

Редактировать: похоже, Св. Тень победил меня.

3 голосов
/ 28 октября 2009

Вы можете просто удалить ".":

df2.format(new Date()).replaceAll("\\.", ""));
<Ч />

Редактировать, относительно лимона ответа:

Кажется, проблема с форматированием при использовании французского языка. Таким образом, я предлагаю вам просто использовать удаление ., как я объяснил.

Действительно, следующий код:

    String format2 = "dd-MMM-yy";
    Date date = Calendar.getInstance().getTime();
    SimpleDateFormat sdf = new SimpleDateFormat(format2, Locale.FRENCH);
    System.out.println(sdf.format(date));
    sdf = new SimpleDateFormat(format2, Locale.ENGLISH);
    System.out.println(sdf.format(date));

отображает следующий вывод:

28-oct.-09
28-Oct-09
<Ч />

Изменить еще раз

Хорошо, у меня сейчас твоя проблема.

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

        String[] givenMonths = { "jan", "fév", "mars", "avr.", "mai", "juin", "juil", "août", "sept", "oct", "nov", "déc" };
        String[] realMonths = { "janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc." };
        String original = "09-oct-08";
        for (int i = 0; i < givenMonths.length; i++) {
            original = original.replaceAll(givenMonths[i], realMonths[i]);
        }
        String format2 = "dd-MMM-yy";
        DateFormat df2 = new SimpleDateFormat(format2, Locale.FRENCH);
        Date date = df2.parse(original);
        System.out.println("--> " + date);

Согласен, это ужасно, но я не вижу другого решения, если вы используете SimpleDateFormat и Date классы.

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

1 голос
/ 13 ноября 2015

java.time

Давайте посмотрим, может ли помочь java.time framework.

О java.time

Инфраструктура java.time , встроенная в Java 8 и более поздние версии, заменяет проблемные старые классы java.util.Date/.Calendar. Новые классы вдохновлены очень успешным фреймворком Joda-Time , задуманным как его преемник, похожим по концепции, но с новой архитектурой. Определяется JSR 310 . Расширена проектом ThreeTen-Extra . См. Учебник .

LocalDate

В отличие от старых классов, java.time предлагает класс LocalDate для представления значения только для даты, без времени суток и часового пояса.

Французские сокращения

Посмотрите, что ожидают форматеры в java.time для сокращенных названий месяцев в ru Français .

Мы можем перебрать перечисление Month, чтобы получить список месяцев. Это перечисление предлагает метод getDisplayName для генерации локализованного названия месяца. Этот код демонстрирует, что метод производит тот же вывод, что и форматтер java.time.

DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "dd-MMM-yyyy" ).withLocale ( Locale.FRENCH );
for ( Month month : Month.values () ) {
    LocalDate localDate = LocalDate.of ( 2015 , month.getValue () , 1 );
    String output = formatter.format ( localDate );
    String displayName = month.getDisplayName ( TextStyle.SHORT , Locale.FRENCH );
    System.out.println ( "output: " + output + " | displayName: " + displayName );// System.out.println ( "input: " + input + " → " + localDate + " → " + output );
}
output: 01-janv.-2015 | displayName: janv.
output: 01-févr.-2015 | displayName: févr.
output: 01-mars-2015 | displayName: mars
output: 01-avr.-2015 | displayName: avr.
output: 01-mai-2015 | displayName: mai
output: 01-juin-2015 | displayName: juin
output: 01-juil.-2015 | displayName: juil.
output: 01-août-2015 | displayName: août
output: 01-sept.-2015 | displayName: sept.
output: 01-oct.-2015 | displayName: oct.
output: 01-nov.-2015 | displayName: nov.
output: 01-déc.-2015 | displayName: déc.

Мы находим смесь из 3 и 4 букв написания. Длинные имена сокращаются до четырех символов плюс точка ( FULL STOP ). Четыре месяца имеют достаточно короткие названия, чтобы использовать их без сокращений: mars, mai, juin, août.

Итак, как обсуждалось в других Ответах, простого решения нет.

Исправить источник данных

Мое первое предложение - исправить ваш источник данных. Этот источник, по-видимому, не соответствует надлежащим французским правилам сокращения. Йельский согласен с пониманием французского языка в Java 8. Кстати, если вы исправляете ваш источник данных, я настоятельно рекомендую использовать четырехзначные годы, так как два приводят к бесконечной путанице и неопределенности.

Исправить ввод

Конечно, источник может быть вне вашего контроля / влияния. В этом случае, как и в случае с другими Ответами, вам может потребоваться сделать грубую замену, а не пытаться применить какой-либо ум. С другой стороны, если единственная проблема с вашим вводом - просто пропустить точку (FULL STOP), то вы можете использовать программный код, используя перечисление Month вместо жесткого кодирования неправильных значений.

Я бы сделал начальную попытку разбора. Ловушка для DateTimeParseException, прежде чем пытаться исправить. Если выдается исключение, исправьте ввод.

Чтобы исправить ввод, попробуйте каждый месяц года, зацикливая возможный набор экземпляров enum. За каждый месяц получайте его сокращенное название. Удалите точку (FULL STOP) из этой аббревиатуры, чтобы она соответствовала тому, что мы подозреваем, является нашим неправильным входящим значением. Проверьте, действительно ли это соответствует входным данным. Если нет, переходите к следующему месяцу.

Когда мы получим совпадение, исправьте ввод, чтобы он был правильно сокращен для правил Locale (французские правила в нашем случае). Затем проанализируйте фиксированный ввод. Это будет наша вторая попытка разбора, так как мы сделали первоначальную попытку наверху. Если вторая попытка не удалась, что-то не так, как отмечено в FIXME:, показанном здесь. Но обычно эта вторая попытка разбора будет успешной, и мы можем выйти из цикла for перечисления Month.

Наконец, вы можете проверить успешность, проверив, является ли результат все еще фиктивным значением, установленным изначально (LocalDate.MIN).

String input = "09-oct-08"; // Last two digits are Year.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "dd-MMM-yy" ).withLocale ( Locale.FRENCH );
LocalDate localDate = LocalDate.MIN; // Some folks prefer a bogus default value as a success/failure flag rather than using a NULL.
try {
    localDate = LocalDate.parse ( input , formatter );
} catch ( DateTimeParseException e ) {
    // Look for any month name abbreviation improperly missing the period (FULL STOP).
    for ( Month month : Month.values () ) {
        String abbreviation = month.getDisplayName ( TextStyle.SHORT , Locale.FRENCH );
        String abbreviationWithoutFullStop = abbreviation.replace ( "." , "" ); // Get short abbreviation, but drop any period (FULL STOP).
        String proper = "-" + abbreviation + "-";
        String improper = "-" + abbreviationWithoutFullStop + "-";
        if ( input.contains ( improper ) ) {
            String inputFixed = input.replace ( improper , proper );
            try {
                localDate = LocalDate.parse ( inputFixed , formatter );
            } catch ( DateTimeParseException e2 ) {
                // FIXME: Handle this error. We expected this second parse attempt to succeed.
            }
            break; // Bail-out of the loop as we got a hit, matching input with a particular improper value.
        }
    }
}
Boolean success =  ! ( localDate.equals ( LocalDate.MIN ) );
String formatted = formatter.format ( localDate );;
String outputImproper = formatted.replace ( "." , "" );  // Drop any period (FULL STOP).

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

System.out.println ( "success: " + success + ". input: " + input + " → localDate: " + localDate + " → formatted: " + formatted + " → outputImproper: " + outputImproper );

успех: правда. вход: 09-окт-08 → localDate: 2008-10-09 → форматированный: 09-окт.-08 → outputImproper: 09-окт-08

1 голос
/ 28 октября 2009

Хорошо, тогда попробуйте «перебор»:)

DateFormatSymbols dfs = new DateFormatSymbols(Locale.FRENCH);
String[] months = new String[13]
<fill with correct month names or just replace these month, that are not fully correct>
dfs.setMonths(months);
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yy", dfs);
Date nweDate = sdf.parse("09-fév-08");
1 голос
/ 28 октября 2009
String format2 = "dd-MMM-yy";
Date date = Calendar.getInstance().getTime();
SimpleDateFormat sdf = new SimpleDateFormat(format2);
System.out.println(sdf.format(date));

Выходы 28-Oct-09

Я не вижу никаких точек, сэр. Вы пробовали перепроверить ваши отпечатки? Может быть, вы случайно поместили . рядом с MMM?


Вы получаете java.text.ParseException: Unparseable date: "09-oct-08", поскольку "09-oct-08" не соответствует форматированию Locale.FRENCH, либо используйте локаль по умолчанию (думаю, США), либо добавьте . рядом с oct

0 голосов
/ 23 февраля 2016

У меня была та же проблема (французская и лишние точки), и я считаю, что правильный способ решить эту проблему - переписать французскую локаль глобально следующим образом:

import moment from 'moment';
moment.locale('fr', { monthsShort: 'janv_févr_mars_avr_mai_juin_juil_août_sept_oct_nov_déc'.split('_') });

Оригинал monthsShortФранцузский объект имеет точки типа janv._févr._mars_avr._..., поэтому мы просто удаляем их.

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

Обратите внимание, что нам не нужно передавать полный объект локали, если мы просто хотим перезаписать, т.е. .: monthsShort.

...