Ошибка Joda Time или моя ошибка? (Java Joda Time датируется как разбор строк)

Поэтому у меня возникла проблема с анализом даты с использованием хронологии JodaTime IslamicChronology поэтому написал небольшой пример, чтобы продемонстрировать мою проблему.

Вот код:

import org.joda.time.Chronology;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.chrono.IslamicChronology;

import java.util.Date;

/**
 * Test
 */
public class Test
{
    public static void main(String[] args)
    {
        Date now = new Date();

        String format = "dd MMM yyyy";
        Chronology calendarSystem = IslamicChronology.getInstance();
        DateTimeFormatter formatter = DateTimeFormat.forPattern(format).withChronology(calendarSystem);

        String nowAsString = formatter.print(now.getTime());

        System.out.println("nowAsString = " + nowAsString);

        long parsedNowTs = formatter.parseMillis(nowAsString);

        String parsedNowTsAsString = formatter.print(parsedNowTs);
    }
}

И вывод:

nowAsString = 16 10 1430
Exception in thread "main" java.lang.IllegalArgumentException: Invalid format: "16 10 1430" is malformed at "10 1430"
    at org.joda.time.format.DateTimeFormatter.parseMillis(DateTimeFormatter.java:634)
    at test.Test.main(Test.java:40)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    ...

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

Заранее спасибо.

3 ответа

Решение

Если кому-то интересно... Я нашел работу вокруг:

  • Создать новый класс, например IslamicChronologyWithNames который делегирует экземпляр IslamicChronology в пакете org.joda.time.DateTimeZone
  • Изменить один метод; assemble(Fields fields): вызовите метод делегата и затем установите fields.monthOfYear (и, возможно, dayOfWeek) для вашего собственного подкласса BasicMonthOfYearDateTimeField
  • Подкласс BasicMonthOfYearDateTimeField Затем можно найти имена файлов свойств для названия месяца (или дня, если DayOfWeek...). Подкласс должен быть в пакете org.joda.time.chrono, чтобы иметь возможность расширяться BasicMonthOfYearDateTimeField,

По-прежнему существует проблема, заключающаяся в том, что время Joda, по-видимому, проверяет дату, которую вы анализируете, перед вызовом методов подкласса, таких как getAsText(int fieldValue, Locale locale) и потому что он не знает имен месяцев, которые возвращает ваш класс, не проходит проверку и поэтому никогда не вызывает методы. Мой обходной путь должен был иметь статический метод в этом классе, который преобразовывает дату в виде строки с исламскими названиями месяцев в дату в виде строки с григорианскими английскими названиями месяцев. Так что перед звонком parseDateTime()Вызовите статический метод, а затем строка даты пройдет проверку. Затем вместо обработки названий исламских месяцев в convertText() метод, используйте григорианскую реализацию по умолчанию внутри вашего подкласса:

protected int convertText(String text, Locale locale)
{
    return GJLocaleSymbols.forLocale(locale).monthOfYearTextToValue(text);
}

Это должно работать! Надеюсь, это имеет смысл для тех, кто имеет такую ​​же проблему.

MMM в шаблоне формата указывает сокращенное название месяца. Числовой индекс месяца следует указывать с помощью MM.

Прочитав ваш комментарий на ответ dtsazza, я впервые понял вашу актуальную проблему.:)

Я взглянул на исходный код JODA, и кажется, что поддержка исламской хронологии довольно нарушена. Прежде всего, средство форматирования не поддерживает названия месяцев, поэтому шаблоны MMM и MMMM форматируются как номер месяца, хотя в соответствии с документацией DateTimeFormat сокращенное название месяца следует использовать для MMM, а полное имя месяца для MMMM.,

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

Если я заменю parseMillis с parseDateTimeЯ бы ожидал, что для синтаксического анализа будет использоваться хронология (по крайней мере, так сказано в документации), но похоже, что реализация игнорирует сконфигурированную хронологию и продолжает здесь также хронологию ISO.

Вы указали формат как dd MMM yyyy; согласно API это означает, что вам нужно указывать месяц в сокращенно-строковой форме (в данном случае "октябрь"). Входные данные, которые вы передали, будут правильно проанализированы, если формат dd MM yyyy,

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

long input = ...; // whatever
formatter.parseMillis(formatter.print(input));

бросает исключение. Хотя я не вижу каких-либо явных гарантий того, что это всегда должно работать, я, конечно, ожидаю, что это так и будет, поэтому да, я бы поддержал ваше утверждение, что это вероятная ошибка в самой Joda.

По крайней мере, если это ожидаемое поведение, должно быть более четкое указание на то, что это может произойти.

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