隨筆-4  評論-4  文章-0  trackbacks-0

          本文從Google blogger上搬過來的,原文由于眾所周知的原因在國內無法訪問了,順帶鄙視一下。

          前段時間 CSDN 上有人問起 Win32 FileTime 格式與 Java 中Date格式如何進行相互轉換。詳見:http://topic.csdn.net/u/20090420/11/8016744d-d151-4041-a837-5a14f2592e3f.html

          根據 MSDN 上關于FILETIME結構的描述,可以很方便地在FILETIME與 Java 中Date進行互轉。MSDN 上稱,FILETIME采用 64 位數值表示與 UTC 時間 1601 年 1 月 1 日 0 時起百納秒的時間間隔。

          MSDN 上FILETIME結構的描述為:

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

          由于DWORD僅能表示 32 位無符號的整數,因此需要使用兩個DWORD才能表示 file time。dwLowDateTime是指 file time 的低 32 位值,而dwHighDateTime是指 file time 的高 32 位值。

          在 Java 中的時間是采用 Unix 紀元,即與 UTC 時間 1970 年 1 月 1 日 0 時起的毫秒時間間隔,在 Java 中是使用long類型來表示這個值的。

          有了上面的知識點,就可以很容易地把 Win32 FileTime 時間與 Java 中Date進行互相轉換。需要做的是計算出 1601 年 1 月 1 日 0 時與 1970 年 1 月 1 日 0 時之間的毫秒數差值,加上 Unix 紀元的毫秒數時間,再將其換算成百納秒就可以進行轉換了。按 Unix 紀元 1970 年 1 月 1 日 0 時之前均為負數。

          由于涉及時間計算,為了保證正確性,先用代碼來校驗一下時區,看看 1970 年 1 月 1 日 0 時是否為 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;
              }
          }
          

          上面代碼運行的結果是:

          -28800000
          

          可見這個結果是不正確的,由于我們當前系統的時區是 GMT+8 區,也就是比格林尼治標準時間相差 8 個小時,這 28800000 也正好是 8 個小時的毫秒數。我們只要為DateFormat加上下面這一段代碼就可以將格式化器轉為 GMT 時間(對于本文而言 UTC 時間與 GMT 時間沒有區別,具體的區別可以參考 更多閱讀 中提供的資料)。

          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());
          }
          

          此時我們輸出的結果就是 0 了,再將其換成“1601-01-01 00:00:00”時輸出為:

          -11644473600000
          

          由于這個值是個常量固定值,將這個值取絕對值暫且命名為UNIX_FILETIME_MILLISECOND_DIFF

          接下來需要獲得毫秒數與百納秒數的倍率。眾所周知,1 秒等于 103 毫秒,而 1 毫秒等于 106 納秒,因此可以推算出 1 毫秒等于 104 百納秒。

          由于FILETIME結構是采用兩個DWORD來表示的,對于 Java 而言,可以將DWORD映射為int類型。通過移位運算符<<可以將這兩個 32 位的int轉換為 64 位的long數據,以便于對 Unix 紀元毫秒數的計算。

          為了采用面向對象的方式進行設計,可以仿照FILETIME結構的定義,聲明一個FILETIME的類,其中包含高 32 位數字和低 32 位數字。為了封裝一下,把 Unix 紀元與FILETIME零起點的毫秒值與毫秒與百納秒的倍率置為常量。

          public class FileTime {
          
              /**
               * Unix 時間 1970-01-01 00:00:00 與 Win32 FileTime 時間 1601-01-01 00:00:00
               * 毫秒數差
               */
              public final static long UNIX_FILETIME_MILLISECOND_DIFF = 11644473600000L;
          
              /**
               * Win32 FileTime 采用 100ns 為單位的,定義 100ns 與 1ms 的倍率
               */
              public final static int MILLISECOND_100NANOSECOND_MULTIPLE = 10000;
          
              /**
               * FileTime 的低 32 位數
               */
              private int low;
          
              /**
               * FileTime 的高 32 位數
               */
              private int high;
          
              public FileTime() {
          
              }
          
              /**
               * 獲得 FileTime 以 64 位數字表示的數據
               * @return
               */
              public long getFileTime() {
                  return (((long)high << 32) & 0xffffffff) | ((long)low & 0xffffffff);
              }
          
              public FileTime(int low, int high) {
                  this.low = low;
                  this.high = high;
              }
          
              public int getLow() {
                  return low;
              }
          
              public void setLow(int low) {
                  this.low = low;
              }
          
              public int getHigh() {
                  return high;
              }
          
              public void setHigh(int high) {
                  this.high = high;
              }
          
              public String toString() {
                  return "high: " + high + ", low: " + low;
              }
          }
          

          定義好了結構,為了能與java.util.Date互轉,還需要增加一個toDate的方法和一個date2FileTime的靜態方法。

          /**
           * 將 Win32 的 FileTime 結構轉為 Java 中的 Date 類型
           * @param fileTime
           * @return
           */
          public Date toDate() {
              return new Date(getFileTime() / MILLISECOND_100NANOSECOND_MULTIPLE - 
                      UNIX_FILETIME_MILLISECOND_DIFF);
          }
          
          /**
           * 將 Java 中的 Date 類型轉為 Win32 的 FileTime 結構
           * @param date
           * @return
           */
          public static FileTime date2FileTime(Date date) {
              long time = (UNIX_FILETIME_MILLISECOND_DIFF + date.getTime()) * 
                      MILLISECOND_100NANOSECOND_MULTIPLE;
              FileTime fileTime = new FileTime();
              fileTime.setHigh((int)(time >> 32) & 0xffffffff);
              fileTime.setLow((int)time & 0xffffffff);
              return fileTime;
          }
          

          結構和代碼都定義完成了,寫個測試代碼來測試一下,看看“2010-07-10 15:35:18”的 FileTime 值是多少。

          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 date1 = parseDate("2010-07-10 15:35:18", format);
          
                  FileTime fileTime = FileTime.date2FileTime(date1);
                  System.out.println(fileTime.toString());
          
                  FileTime fileTile = new FileTime();
                  fileTile.setHigh(30089218);
                  fileTile.setLow(1907785472);
                  Date date2 = fileTile.toDate();
                  System.out.println(format.format(date2));
              }
          
              public static Date parseDate(String str, DateFormat format) {
                  Date date = null;
                  try {
                      date = format.parse(str);
                  } catch (ParseException e) {
                      e.printStackTrace();
                  }
                  return date;
              }
          }
          
          更多閱讀
          • 在中文維基百科上可以找到協調世界時(UTC)格林尼治標準時間(GMT)的相關資料,也可以在其他資源上搜索到相關資料。
          • 在 MSDN 上可以找到更多關于FILETIME結構的描述,
          • 更多關于java.text.SimpleDateFormat格式參數的信息可以參見這個類的API 文檔
          • 如果對于java.util.TimeZone這個類不是很了解的話,可以參見這個類的API 文檔
          posted on 2011-03-26 23:47 菜菜寶寶 閱讀(2400) 評論(0)  編輯  收藏 所屬分類: Java基礎

          只有注冊用戶登錄后才能發表評論。


          網站導航:
          博客園   IT新聞   Chat2DB   C++博客   博問  
           
          主站蜘蛛池模板: 赤壁市| 景谷| 屏南县| 峡江县| 华池县| 龙井市| 大冶市| 罗源县| 宁阳县| 通化县| 洪泽县| 呼和浩特市| 即墨市| 镇赉县| 武功县| 华坪县| 蓬莱市| 灵台县| 仙桃市| 彩票| 光山县| 夏河县| 铜鼓县| 东辽县| 花垣县| 曲水县| 淳安县| 广安市| 斗六市| 凉城县| 上栗县| 南平市| 梁平县| 丹巴县| 林芝县| 威信县| 隆昌县| 辉县市| 北票市| 靖州| 剑阁县|