Ошибка 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.
По крайней мере, если это ожидаемое поведение, должно быть более четкое указание на то, что это может произойти.