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

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

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

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

          MSDN 上FILETIME結(jié)構(gòu)的描述為:

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

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

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

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

          由于涉及時間計算,為了保證正確性,先用代碼來校驗一下時區(qū),看看 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;
              }
          }
          

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

          -28800000
          

          可見這個結(jié)果是不正確的,由于我們當(dāng)前系統(tǒng)的時區(qū)是 GMT+8 區(qū),也就是比格林尼治標(biāo)準(zhǔn)時間相差 8 個小時,這 28800000 也正好是 8 個小時的毫秒數(shù)。我們只要為DateFormat加上下面這一段代碼就可以將格式化器轉(zhuǎn)為 GMT 時間(對于本文而言 UTC 時間與 GMT 時間沒有區(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());
          }
          

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

          -11644473600000
          

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

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

          由于FILETIME結(jié)構(gòu)是采用兩個DWORD來表示的,對于 Java 而言,可以將DWORD映射為int類型。通過移位運算符<<可以將這兩個 32 位的int轉(zhuǎn)換為 64 位的long數(shù)據(jù),以便于對 Unix 紀(jì)元毫秒數(shù)的計算。

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

          public class FileTime {
          
              /**
               * Unix 時間 1970-01-01 00:00:00 與 Win32 FileTime 時間 1601-01-01 00:00:00
               * 毫秒數(shù)差
               */
              public final static long UNIX_FILETIME_MILLISECOND_DIFF = 11644473600000L;
          
              /**
               * Win32 FileTime 采用 100ns 為單位的,定義 100ns 與 1ms 的倍率
               */
              public final static int MILLISECOND_100NANOSECOND_MULTIPLE = 10000;
          
              /**
               * FileTime 的低 32 位數(shù)
               */
              private int low;
          
              /**
               * FileTime 的高 32 位數(shù)
               */
              private int high;
          
              public FileTime() {
          
              }
          
              /**
               * 獲得 FileTime 以 64 位數(shù)字表示的數(shù)據(jù)
               * @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;
              }
          }
          

          定義好了結(jié)構(gòu),為了能與java.util.Date互轉(zhuǎn),還需要增加一個toDate的方法和一個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;
              FileTime fileTime = new FileTime();
              fileTime.setHigh((int)(time >> 32) & 0xffffffff);
              fileTime.setLow((int)time & 0xffffffff);
              return fileTime;
          }
          

          結(jié)構(gòu)和代碼都定義完成了,寫個測試代碼來測試一下,看看“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;
              }
          }
          
          更多閱讀
          posted on 2011-03-26 23:47 菜菜寶寶 閱讀(2409) 評論(0)  編輯  收藏 所屬分類: Java基礎(chǔ)

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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 安新县| 博爱县| 大城县| 闻喜县| 奎屯市| 达尔| 大余县| 托克托县| 平顶山市| 手游| 松原市| 肇庆市| 游戏| 静乐县| 本溪市| 杭锦旗| 云林县| 永登县| 蓝山县| 上高县| 承德市| 吉木乃县| 铜川市| 大冶市| 万荣县| 三台县| 衡阳市| 定陶县| 包头市| 西充县| 夏邑县| 博乐市| 青神县| 调兵山市| 腾冲县| 昌邑市| 民丰县| 扬中市| 西吉县| 达日县| 祁连县|