Ошибка Joda Time или моя ошибка? (Java Joda Time датирует как разбор строк) - PullRequest
2 голосов
/ 06 октября 2009

поэтому у меня возникла проблема с анализом даты, используя хронологию 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 ]

7 голосов
/ 15 октября 2009

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

  • Создать новый класс, например 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);
}

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

5 голосов
/ 06 октября 2009

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

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

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

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

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

2 голосов
/ 06 октября 2009

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

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

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

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

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

...