Выброшено странное исключение org.threeten.bp.DateTimeException?

Мой код работал нормально. Сегодня внезапно я начал получать это исключение - org.threeten.bp.DateTimeException: Field DayOfMonth cannot be printed as the value 1872095944 max width is 2 Это мой простой код:

LocalDateTime date = LocalDateTime.now();
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd - MM - uuuu");
    String sDate = date.format(formatter);//EXCEPTION THROWN HERE

С чего вдруг эта проблема?

РЕДАКТИРОВАТЬ

Похоже, это промежуточная проблема. Иногда зависает, а в остальное время работает нормально. Никаких намеков на то, что происходит. А


person Ashwin    schedule 09.01.2016    source источник
comment
что такое 108795? твоя дата?   -  person sasikumar    schedule 09.01.2016
comment
@sasikumar: на самом деле это 1872095944. Обновил вопрос. Я не уверен, что это дата. Вы имеете в виду в миллисекундах, верно?   -  person Ashwin    schedule 09.01.2016


Ответы (2)


Это не столько проблема форматирования (здесь просто симптом), сколько проблема создания экземпляра LocalDateTime. Основная причина заключается просто в том, что LocalDateTime.now() в некоторых редких случаях выдает день месяца, полностью выходящий за пределы. Эта проблема, вероятно, связана с этой проблемой в системе отслеживания ошибок threeten-bp.

LocalDate.ofEpochDay(x) иногда возвращает неправильный или недопустимый результат вместо создания исключения для больших значений x . Например, LocalDate.ofEpochDay(9223371671611556645L) возвращает дату с отрицательным значением для d.getDayOfMonth() вместо создания DateTimeException .

Имейте в виду, что метод now() должен выполнять преобразование эпохи в фоновом режиме и, наконец, вызывать LocalDate.ofEpochDay(...). Поэтому, если ваши часы выдают необычное значение эпохи в миллисекундах с эпохи Unix, это также может повлиять на now(). И ваш форматер просто извлекает день месяца из вашего LocalDateTime, фактически вызывая getDayOfMonth() (на самом деле через доступ к полю в TemporalAccessor). Рассматриваемый исходный код:

281     public static LocalDate ofEpochDay(long epochDay) { 
282         long zeroDay = epochDay + DAYS_0000_TO_1970; 
283         // find the march-based year 
284         zeroDay -= 60;  // adjust to 0000-03-01 so leap day is at end of four year cycle 
285         long adjust = 0; 
286         if (zeroDay < 0) { 
287             // adjust negative years to positive for calculation 
288             long adjustCycles = (zeroDay + 1) / DAYS_PER_CYCLE - 1; 
289             adjust = adjustCycles * 400; 
290             zeroDay += -adjustCycles * DAYS_PER_CYCLE; 
291         } 
292         long yearEst = (400 * zeroDay + 591) / DAYS_PER_CYCLE; 
293         long doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400); 
294         if (doyEst < 0) { 
295             // fix estimate 
296             yearEst--; 
297             doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400); 
298         } 
299         yearEst += adjust;  // reset any negative year 
300         int marchDoy0 = (int) doyEst; 
301 

302         // convert march-based values back to january-based 
303         int marchMonth0 = (marchDoy0 * 5 + 2) / 153; 
304         int month = (marchMonth0 + 2) % 12 + 1; 
305         int dom = marchDoy0 - (marchMonth0 * 306 + 5) / 10 + 1; 
306         yearEst += marchMonth0 / 10; 
307 

308         // check year now we are certain it is correct 
309         int year = YEAR.checkValidIntValue(yearEst); 
310         return new LocalDate(year, month, dom); 
311     } 

Наиболее интересным и подозрительным является тот факт, что проверяется только год, а не месяц или день месяца. И действительно, взгляните на этот причудливый результат, состоящий из четырех частей, разделенных минус-символами (???):

LocalDate d = LocalDate.ofEpochDay(9223371671611556645L);
System.out.println(d); // -999999999-02-0-30
System.out.println(d.getDayOfMonth()); // -30

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

Обновление:

Исходный код LocalDate.ofEpochDay(long), показанный до сих пор, определенно сломан, в том числе из-за того, что нет проверки числового/арифметического переполнения. Например: ввод типа Long.MAX_VALUE вызывает переполнение выражения epochDay + DAYS_0000_TO_1970 и изменение знака на отрицательный. Аналогично, ввод Long.MIN_VALUE окончательно переполнится при использовании выражения 400 * zeroDay. И я боюсь, что это не единственная проблема показанного кода. Для сравнения: правильная реализация григорианского алгоритма скорее выглядела бы как в моя библиотека времени.

Примечание:

С помощью моей библиотеки Time4J я проанализировал, что приведенный выше тестовый ввод даст год далеко за пределы, поскольку также определяется в тридесяти битах (диапазон от -999999999 до +999999999):

PlainDate date = PlainDate.of(9223371671611556645L, EpochDays.UNIX);
// java.lang.IllegalArgumentException: Year out of range: 25252733927766555

Я не совсем уверен, что вы можете сделать, чтобы решить проблему.

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

По поводу бага в threeten-bp (и Java-8!), можно только надеяться, что команда threeten-bp-project скоро его исправит (точнее Oracle!). Входные данные, вызывающие проблемы, вероятно, в любом случае неверны, поэтому вам лучше всего перехватить исключение и зарегистрировать его с дополнительным сообщением о том, что часы неверны (в качестве основной причины).

person Meno Hochschild    schedule 30.01.2016
comment
Тем временем я обнаружил, что другое значение, дающее отрицательный день месяца: 9223372036854056247L - person Meno Hochschild; 17.02.2016
comment
Исправлено в бэкпорте - github.com/ThreeTen/threetenbp/issues/39 - person JodaStephen; 05.09.2016

Есть ли последние изменения в файле api. Я не вижу никакой опции u в списке разрешенных шаблонов.

Symbol  Meaning                     Presentation       Examples

  ------  -------                     ------------      -------

   G       era                         number/text       1; 01; AD; Anno 
Domini

   y       year                        year              2004; 04

   D       day-of-year                 number            189

   M       month-of-year               number/text       7; 07; Jul; July; J

   d       day-of-month                number            10


   Q       quarter-of-year             number/text       3; 03; Q3


   Y       week-based-year             year              1996; 96


   w       week-of-year                number            27

   W       week-of-month               number            27

   e       localized day-of-week       number            2; Tue; Tuesday; T

   E       day-of-week                 number/text       2; Tue; Tuesday; T

   F       week-of-month               number            3


   a       am-pm-of-day                text              PM

   h       clock-hour-of-am-pm (1-12)  number            12

   K       hour-of-am-pm (0-11)        number            0

   k       clock-hour-of-am-pm (1-24)  number            0

   H       hour-of-day (0-23)          number            0

   m       minute-of-hour              number            30


   s       second-of-minute            number            55

   S       fraction-of-second          fraction          978

   A       milli-of-day                number            1234

   n       nano-of-second              number            987654321

   N       nano-of-day                 number            1234000000

   V       time-zone ID                zone-id America/Los_Angeles; Z; -08:30

   z       time-zone name              zone-name  Pacific Standard Time; PST

   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;

   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;

   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;


   p       pad next                    pad modifier      1

   '       escape for text             delimiter


   ''      single quote                literal           '

[       optional section start

 ]       optional section end

{}      reserved for future use
person user2503849    schedule 09.01.2016
comment
Я изменил его на «гггг». Это сработало изначально. Но потом снова закралась проблема с тем же исключением. Это промежуточная проблема. Иногда это работает, а иногда выбрасывается исключение - person Ashwin; 09.01.2016
comment
Да, у вас устаревший javadoc. Настоящий знает u (как пролептический григорианский год), посмотрите Oracle. - person Meno Hochschild; 30.01.2016