Разбор даты с коротким месяцем без точки

у меня есть строка, представляющая дату в французский локаль: 09-окт-08:

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

String format2 = "dd-MMM-yy";

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

df2.format(new Date());

дает мне :

 28-oct.-09

что теперь лучший способ для меня, чтобы SimpleDateFormat понять ("09-oct-08")?

Полный Код :

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

это дает мне: java.текст.ParseException: непростительная дата: "09-oct-08"

и если я тогда попытаюсь войти:

df2.format(new Date()); 

я получаю : 28-октября.-09

6 ответов


Это, кажется, работает:

    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")));

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


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

df2.format(new Date()).replaceAll("\.", ""));

Edit, относительно лимон ответ:

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

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

    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, таких как Джода Время.


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


Ok, затем попробуйте "грубая сила":)

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");

java.время

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

о java.время

на java.время фреймворк, встроенный в Java 8, а затем заменяет хлопотную старую java.утиль.Дата./Календарные занятия. Новые классы вдохновлены очень успешными Joda Времени framework, предназначенный в качестве его преемника, похожий по концепции,но перестроенный. Определяется JSR 310. Расширенный к ThreeTen-Extra. Вижу учебник.

LocalDate

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

Французские Аббревиатуры

взгляните на то, что форматтеры в java.время ожидания для сокращенных имен месяцев в Ан франсэ.

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

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 букв написания. Более длинные имена сокращаются до четырех символов плюс точка (ПОЛНАЯ ОСТАНОВКА). Четыре месяца имеют имена достаточно короткие, чтобы использоваться без аббревиатур: mars, mai, juin, août.

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

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

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

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

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

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

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

когда мы получаем спичку, починка ввод должен быть правильно сокращен для правил локали (французские правила в нашем случае). Затем проанализируйте фиксированный вход. Это будет наша вторая попытка разбора, как мы сделали первую попытку наверху. Если эта вторая попытка не удалась, что-то очень не так, как отмечено в 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-oct-08 → localDate: 2008-10-09 → формат: 09-oct.-08 → outputImproper: 09-oct-08


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

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._..., поэтому мы просто удаляем их.

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

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