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
溢出並將符號更改爲負值。類似地,當使用表達式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
我不太清楚你能做些什麼來解決問題。
第一件事是記錄您的時鐘產生的所有輸入,將它們與觀察到的3ten-bp的小車行爲相關聯,並且做一些研究爲什麼您的時鐘有時會發瘋。
關於threeten-bp(和Java-8!)中的錯誤,您可以希望threeten-bp-project團隊很快就會修復它(或者說Oracle!)。導致問題的輸入可能是錯誤的,因此您應該最好捕獲異常並將時鐘錯誤(作爲根本原因)的額外消息記錄下來。
什麼是108795?你的約會? – sasikumar
@sasikumar:實際上它是1872095944.已更新問題。我不確定那是否是日期。你的意思是毫秒吧? – Ashwin