91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何理解Java Date Timestamp 日期比較的錯誤分析

發布時間:2021-11-20 14:12:21 來源:億速云 閱讀:192 作者:柒染 欄目:大數據

這期內容當中小編將會給大家帶來有關如何理解Java Date Timestamp 日期比較的錯誤分析,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

場景重現:

  1. mysql數據庫(innodb engine)的tab表里有一個createAt字段,類型為datetime(6) 精確到毫秒。當然大家知道mysql的日期字段默認只精確到秒級的,若要到毫秒微妙可定義為datetime(6), 從5.6.4版本開始支持

  2. 業務接口A通過ORM框架在表中存入一條記錄,這里createAt存入
    2016-04-13 15:20:39.152

  3. 業務接口B需查到這條記錄載入實體類Entity中,其中createAt屬性為Date類型,值即為上方的日期。 (注:添加了@Temporal(TemporalType.TIMESTAMP)注解,則該字段類型為Timestamp。本場景是Date)

  4. 獲取當前的系統時間, 注意這里用了Timestamp
    Date now = new Timestamp(System.currentTimeMillis())
    毫秒格式化字符串為 2016-04-13 15:20:39.952
    你會發現多了后面的毫秒小數 952

  5. 調用 now.after(entire.createAt) 期望返回true, 但實際返回false!!


這樣就出現了一個怪異的情形:本來先存入數據庫一條帶有時間戳的記錄,取出來后跟當前的系統時間戳進行對比,竟然發現之前存入的時間是在未來?!

這里到底發生了什么導致
當前系統時間 .after( 之前存入的時間 ) = false?

源碼分析

通過查看源碼可以看到問題所在。
首先,Date類方法getMillisOf()的第一個if判斷中date不為空,但是isNormalized()返回true。這個normalize是CalendarDate中的私有屬性,只要調用過set/add之類修改時間的方法就會變成false。其他說明請看cdate的注釋。
其次,Date構造方法直接將系統的毫秒級別的long數值賦給了fasttime。
再來,Timestamp構造方法截取秒級的時間存入fasttime, 將毫秒微妙計入nanos中。

/*
 * If cdate is null, then fastTime indicates the time in millis.
 * If cdate.isNormalized() is true, then fastTime and cdate are in
 * synch. Otherwise, fastTime is ignored, and cdate indicates the
 * time.
 */

private transient BaseCalendar.Date cdate;public Date() {    
   this(System.currentTimeMillis()); }

public Date(long date) {    fastTime = date; }

static final long getMillisOf(Date date) {    
   if (date.cdate == null || date.cdate.isNormalized()) {        
       return date.fastTime;    }    BaseCalendar.Date d = (BaseCalendar.Date) date.cdate.clone();    
   return gcal.getTime(d); } Timestamp構造方法:
   public Timestamp(long time) {    
   super((time/1000)*1000); //毫秒除1000取整只剩下秒了,再乘以1000作為毫秒數值    nanos = (int)((time%1000) * 1000000);    
   if (nanos < 0) {        nanos = 1000000000 + nanos;        
       super.setTime(((time/1000)-1)*1000);    } }
 


調試分解

然后我們對比下new Date() vs new Timestamp(System.currentTimeMillis())
兩者存儲方式的區別通過下面兩個圖就可以清楚分辨,只要注意fastTime。

  • Date fastTime的最后三位是956,說明是精確到毫秒的

  • Timestamp的最后三位是000,說明被截取到秒,而真正的毫秒166被放到nanos中了


結論說明

  1. 錯誤的根源是混用了Date 和 Timestamp, 導致日期比對失效。
    ORM從數據庫中取出的時間類型是Date first(見文末圖),而當前的時間戳獲取方式錯用了Timestamp second(見文末圖), 只要修改為new Date() 就可以了。

  2. 如果無法避免混用,那就不要使用after() before()做日期對比!
    直接用 getTime() 比較long的大小即可!有興趣的同學可以看下Timestamp getTime()的源碼, 它會把nanos拼裝回數值中!


如何重現

兩個long類型的數據,一個800毫秒,一個900毫秒,可以看出after(before類似, compareTo慎用)返回的結果是錯誤的。


public static void main(String[] args) throws IOException {
    Date d = new Date(1473247063800L);
    Date t = new Timestamp(1473247063900L);
    System.out.println(d.getTime());
    System.out.println(t.getTime());
    System.out.println(t.after(d));  //false, 錯誤結果
    System.out.println(t.compareTo(d));  //1, 正確結果...Timestamp的compareTo方法被重載了所以這里沒問題。
    System.out.println(d.compareTo(t));  //1, 錯誤結果...Date的compareTo方法還是錯誤的。
    System.out.println(t.getTime() > d.getTime()); //true, 正確結果
}

上述就是小編為大家分享的如何理解Java Date Timestamp 日期比較的錯誤分析了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

壶关县| 庆城县| 儋州市| 乐清市| 长岛县| 县级市| 洛浦县| 什邡市| 蓝山县| 松溪县| 建昌县| 阿坝| 临沧市| 方城县| 黄浦区| 九龙城区| 信宜市| 陵川县| 理塘县| 平顶山市| 麻江县| 昌乐县| 吉隆县| 武川县| 禹州市| 安宁市| 延长县| 高尔夫| 突泉县| 沭阳县| 绥中县| 西城区| 马边| 彰化市| 紫金县| 小金县| 浦北县| 玉环县| 岢岚县| 榕江县| 济源市|