java – 引发了奇怪的org.threeten.bp.DateTimeException?
作者:互联网
我的代码运行得很好.今天我突然开始得到这个异常 – org.threeten.bp.DateTimeException:无法打印字段DayOfMonth,因为值1872095944最大宽度为2
这是我的简单代码:
LocalDateTime date = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd - MM - uuuu");
String sDate = date.format(formatter);//EXCEPTION THROWN HERE
为什么这个问题突然?
编辑
这似乎是一个中间问题.它有时崩溃,其他时候工作正常.没有关于发生了什么的线索.一个
解决方法:
它不是一个格式化问题(这里只是一个症状),而是一个如何创建LocalDateTime实例的问题.根本原因很简单,在一些罕见的情况下,LocalDateTime.now()似乎会产生一个完全超出界限的日期.这个问题可能与这个问题跟踪器上的这个issue有关.
LocalDate.ofEpochDay(x) sometimes returns a wrong or illegal result
instead of throwing an exception for large values of x . For
instance, LocalDate.ofEpochDay(9223371671611556645L) returns a date
with a negative value for d.getDayOfMonth() instead of throwing a
DateTimeException .
请记住,now()方法必须在后台执行epoch转换,最后调用LocalDate.ofEpochDay(…).因此,如果你的时钟在Unix纪元以来以毫秒为单位产生一个不寻常的纪元值,那么这也会影响now().并且您的格式化程序只需通过有效调用getDayOfMonth()(实际上通过TemporalAccessor中的字段访问)从LocalDateTime获取日期.有问题的源代码:
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溢出并将符号更改为负数.类似地,当使用表达式400 * zeroDay时,输入Long.MIN_VALUE最终会溢出.我担心这不是显示代码的唯一问题.为了比较:格里高利算法的正确实现更像是在my own time library.
边注:
在我的库Time4J的帮助下,我已经分析过上面给出的测试输入会产生一年远超出界限,如在threeten-bp中定义的那样(范围是-999999999直到999999999):
PlainDate date = PlainDate.of(9223371671611556645L, EpochDays.UNIX);
// java.lang.IllegalArgumentException: Year out of range: 25252733927766555
我不太清楚你能做些什么来解决这个问题.
首先肯定要记录你的时钟产生的所有输入,将它们与三十二节的观察到的错误行为联系起来,并做一些研究,为什么你的时钟有时会疯狂.
关于threeten-bp(和Java-8!)中的错误,你可以希望三个bp项目团队很快就能修复它(或者更确切地说是Oracle!).导致问题的输入无论如何都可能是错误的,因此您应该最好地捕获异常并使用时钟错误的额外消息(作为根本原因)记录它.
标签:java,android,time,system-clock,threetenbp 来源: https://codeday.me/bug/20190706/1397108.html