Win32 FILETIME 結(jié)構(gòu)與 java.util.Date 互轉(zhuǎn)

MSDN 上關(guān)于 FILETIME 結(jié)構(gòu)的描述,可以很方便地在 FILETIME 與 Java 中 Date 進(jìn)行互轉(zhuǎn)。根據(jù) MSDN 上的描述,FILETIME 采用 64 位數(shù)值表示與 UTC 時(shí)間 1601 年 1 月 1 日 0 時(shí)起百納秒的時(shí)間間隔。

MSDN 上的描述卸例,FILETIME 的結(jié)構(gòu)如下:

typedef struct _FILETIME {  
    DWORD dwLowDateTime;  
    DWORD dwHighDateTime;  
} FILETIME, *PFILETIME;  

由于 DWORD 是 windows.h 中定義數(shù)據(jù)類型称杨,表示 32 位無符號整數(shù)的 unsigned long 類型,因此要需要使用兩個(gè) DWORD 才能表示 file time筷转。dwLowDateTime 是指 file time 的低 32 位值,而 dwHighDateTime 是指 file time 的高 32 位值悬而。

在 Java 中的時(shí)間是采用 Unix 紀(jì)元呜舒,即與 UTC 時(shí)間 1970 年 1 月 1 日 0 時(shí)起的毫秒時(shí)間間隔,在 Java 中是使用 long 類型來表示這個(gè)值的笨奠。

有了上面的知識點(diǎn)袭蝗,就可以很容易地把 Win32 FileTime 時(shí)間與 Java 中 Date 進(jìn)行互相轉(zhuǎn)換。需要做的是計(jì)算出 1601 年 1 月 1 日 0 時(shí)與 1970 年 1 月 1 日 0 時(shí)之間的毫秒數(shù)差值般婆,再加上 Unix 紀(jì)元的毫秒數(shù)時(shí)間到腥,再將其換算成百納秒就可以進(jìn)行轉(zhuǎn)換了。按 Unix 紀(jì)元 1970 年 1 月 1 日 0 時(shí)之前均為負(fù)數(shù)蔚袍。

由于涉及時(shí)間計(jì)算乡范,為了保證正確性,先用代碼來校驗(yàn)一下時(shí)區(qū)啤咽,看看 1970 年 1 月 1 日 0 時(shí)是否為 0晋辆。

import java.text.DateFormat;  
import java.text.ParseException;  
import java.text.SimpleDateFormat;  
import java.util.Date;  
  
public class Test5 {  
  
    public static void main(String[] args) {  
        DateFormat format = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );  
        Date date = parseDate( "1970-01-01 00:00:00", format );  
        System.out.println( date.getTime() );  
    }  
      
    public static Date parseDate(String str, DateFormat format) {  
        Date date = null;  
        try {  
            date = format.parse( str );  
        }
        catch (ParseException e) {  
            e.printStackTrace();  
        }  
        return date;  
    }  
}  

上面代碼運(yùn)行的結(jié)果是:

-28800000

可見這個(gè)結(jié)果是不正確的,由于我們當(dāng)前系統(tǒng)的時(shí)區(qū)是 GMT+8 區(qū)宇整,也就是比格林尼治標(biāo)準(zhǔn)時(shí)間相差 8 個(gè)小時(shí)瓶佳,這 28800000 也正好是 8 個(gè)小時(shí)的毫秒數(shù)翩迈。我們只要為 DateFormat 加上下面這一段代碼就可以將格式化器轉(zhuǎn)為 GMT 時(shí)間(對于本文而言 UTC 時(shí)間與 GMT 時(shí)間沒有區(qū)別晦毙,具體的區(qū)別可以參考其他資料)抢肛。

public static void main(String[] args) {
    DateFormat format = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
    format.setTimeZone( TimeZone.getTimeZone("UTC") );
    Date date = parseDate( "1970-01-01 00:00:00", format );
    System.out.println( date.getTime() );
}

此時(shí)我們輸出的結(jié)果就是 0 了业崖,再將其換成“1601-01-01 00:00:00”時(shí)輸出為:

-11644473600000

由于這個(gè)值是個(gè)常量固定值盲链,將這個(gè)值取絕對值暫且命名為UNIX_FILETIME_MILLISECOND_DIFF疆拘。

接下來需要獲得毫秒數(shù)與百納秒數(shù)的倍率央拖。眾所周知窍育,1 秒等于 103 毫秒埃儿,而 1 毫秒等于 106 納秒器仗,因此 1 毫秒等于 104 百納秒。

由于 FILETIME 結(jié)構(gòu)是采用兩個(gè) DWORD 來表示的童番,由于 DWORD 是無符號 32 位整數(shù)精钮,在 Java 中沒有對應(yīng)類型,因此將 DWORD 映射為 long 類型剃斧。通過移位運(yùn)算符 << 可以將這兩個(gè) 32 位的 long 轉(zhuǎn)換為 64 位的 long 數(shù)據(jù)轨香,以便于對 Unix 紀(jì)元毫秒數(shù)的計(jì)算。

為了采用面向?qū)ο蟮姆绞竭M(jìn)行設(shè)計(jì)幼东,可以仿照 FILETIME 結(jié)構(gòu)的定義臂容,聲明一個(gè) FILETIME 的類科雳,其中包含高 32 位數(shù)字和低 32 位數(shù)字。為了封裝一下脓杉,把 Unix 紀(jì)元與 FILETIME 零起點(diǎn)的毫秒值與毫秒與百納秒的倍率置為常量糟秘。

public class FileTime {

    /**
     * Unix 時(shí)間 1970-01-01 00:00:00 與 Win32 FileTime 時(shí)間 1601-01-01 00:00:00
     * 毫秒數(shù)差
     */
    public final static long UNIX_FILETIME_MILLISECOND_DIFF = 11644473600000L;

    /**
     * Win32 FileTime 采用 100ns 為單位的,定義 100 ns 與 1 ms 的倍率
     */
    public final static int MILLISECOND_100NANOSECOND_MULTIPLE = 10000;

    /**
     * FileTime 的低 32 位數(shù)
     */
    private final long low;

    /**
     * FileTime 的高 32 位數(shù)
     */
    private final long high;

    public FileTime(long high, long low) {
        this.high = high;
        this.low = low;
    }

    /**
     * 獲得 FileTime 以 64 位數(shù)字表示的數(shù)據(jù)
     * @return FileTime 的數(shù)據(jù)值
     */
    public long getFileTime() {
        return ((high << 32) & 0xffffffff00000000L) | (low & 0xffffffffL);
    }

    public long getLow() {
        return low;
    }

    public long getHigh() {
        return high;
    }

    @Override
    public String toString() {
        return "high: " + high + ", low: " + low;
    }
}

定義好了結(jié)構(gòu)球散,為了能與 java.util.Date 互轉(zhuǎn)尿赚,還需要增加一個(gè) toDate 的方法和一個(gè) date2FileTime 的靜態(tài)方法。

/**
 * 將 Win32 的 FileTime 結(jié)構(gòu)轉(zhuǎn)為 Java 中的 Date 類型
 * @param fileTime
 * @return
 */
public Date toDate() {
    return new Date(getFileTime() / MILLISECOND_100NANOSECOND_MULTIPLE -
            UNIX_FILETIME_MILLISECOND_DIFF);
}

/**
 * 將 Java 中的 Date 類型轉(zhuǎn)為 Win32 的 FileTime 結(jié)構(gòu)
 * @param date
 * @return
 */
public static FileTime date2FileTime(Date date) {
    long time = (UNIX_FILETIME_MILLISECOND_DIFF + date.getTime()) *
            MILLISECOND_100NANOSECOND_MULTIPLE;
    long high = (time >> 32) & 0xffffffffL;
    long low = time & 0xffffffffL;
    FileTime fileTime = new FileTime( high, low );
    return fileTime;
}

結(jié)構(gòu)和代碼都定義完成了蕉堰,寫個(gè)測試代碼來測試一下凌净,看看當(dāng)前時(shí)間的 FileTime 值是多少:

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Test {
  
    public static void main(String[] args) {
          
        Date date1 = new Date();

        FileTime fileTime = FileTime.date2FileTime(date1);
        System.out.println(fileTime.toString());

        FileTime fileTile = new FileTime( fileTime.getHigh(), fileTime.getLow() );
        Date date2 = fileTile.toDate();
        System.out.printf( "%tF %<tT%n", date2 );
    }  
      
    public static Date parseDate(String str, DateFormat format) {  
        Date date = null;  
        try {  
            date = format.parse(str);  
        }
        catch (ParseException e) {  
            e.printStackTrace();  
        }  
        return date;  
    }  
} 

更多閱讀

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市屋讶,隨后出現(xiàn)的幾起案子冰寻,更是在濱河造成了極大的恐慌,老刑警劉巖皿渗,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件斩芭,死亡現(xiàn)場離奇詭異,居然都是意外死亡羹奉,警方通過查閱死者的電腦和手機(jī)秒旋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诀拭,“玉大人迁筛,你說我怎么就攤上這事「ぃ” “怎么了细卧?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長筒占。 經(jīng)常有香客問我贪庙,道長,這世上最難降的妖魔是什么翰苫? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任止邮,我火速辦了婚禮,結(jié)果婚禮上奏窑,老公的妹妹穿的比我還像新娘导披。我一直安慰自己,他們只是感情好埃唯,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布撩匕。 她就那樣靜靜地躺著,像睡著了一般墨叛。 火紅的嫁衣襯著肌膚如雪止毕。 梳的紋絲不亂的頭發(fā)上模蜡,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天,我揣著相機(jī)與錄音扁凛,去河邊找鬼忍疾。 笑死,一個(gè)胖子當(dāng)著我的面吹牛令漂,可吹牛的內(nèi)容都是我干的膝昆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼叠必,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了妹窖?” 一聲冷哼從身側(cè)響起纬朝,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎骄呼,沒想到半個(gè)月后共苛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蜓萄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年隅茎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嫉沽。...
    茶點(diǎn)故事閱讀 40,133評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辟犀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绸硕,到底是詐尸還是另有隱情堂竟,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布玻佩,位于F島的核電站出嘹,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏咬崔。R本人自食惡果不足惜税稼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望垮斯。 院中可真熱鬧郎仆,春花似錦、人聲如沸甚脉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽牺氨。三九已至狡耻,卻和暖如春墩剖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背夷狰。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工岭皂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人沼头。 一個(gè)月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓爷绘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親进倍。 傳聞我的和親對象是個(gè)殘疾皇子土至,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評論 2 355