隨筆-4  評(píng)論-4  文章-0  trackbacks-0

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

          前段時(shí)間 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 時(shí)間 1601 年 1 月 1 日 0 時(shí)起百納秒的時(shí)間間隔。

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

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

          由于DWORD僅能表示 32 位無符號(hào)的整數(shù),因此需要使用兩個(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è)值的。

          有了上面的知識(shí)點(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í)間(對(duì)于本文而言 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è)值取絕對(duì)值暫且命名為UNIX_FILETIME_MILLISECOND_DIFF

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

          由于FILETIME結(jié)構(gòu)是采用兩個(gè)DWORD來表示的,對(duì)于 Java 而言,可以將DWORD映射為int類型。通過移位運(yùn)算符<<可以將這兩個(gè) 32 位的int轉(zhuǎn)換為 64 位的long數(shù)據(jù),以便于對(duì) 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 為單位的,定義 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),還需要增加一個(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;
              FileTime fileTime = new FileTime();
              fileTime.setHigh((int)(time >> 32) & 0xffffffff);
              fileTime.setLow((int)time & 0xffffffff);
              return fileTime;
          }
          

          結(jié)構(gòu)和代碼都定義完成了,寫個(gè)測(cè)試代碼來測(cè)試一下,看看“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) 評(píng)論(0)  編輯  收藏 所屬分類: Java基礎(chǔ)

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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 吉隆县| 马边| 乐陵市| 汝南县| 夏津县| 古田县| 平顶山市| 双江| 洪洞县| 鄱阳县| 武宣县| 尖扎县| 哈巴河县| 广安市| 甘洛县| 晴隆县| 嘉黎县| 府谷县| 红安县| 新兴县| 织金县| 东安县| 揭东县| 富锦市| 胶南市| 房山区| 东方市| 霸州市| 甘谷县| 金门县| 玉门市| 林口县| 元朗区| 乌审旗| 昭觉县| 武山县| 林西县| 五原县| 青阳县| 许昌市| 洛隆县|