2012年4月6日 星期五

Android上日期與時間的處理 - Calendar

在Android系統裡面可以使用到關於時間的類別有三種


主要使用Calendar類別,Date類別在Android中不建議使用然而我們會用到java.text.SimpleDateFormat這個類別來處理DateString間的轉換所以Data類別常用來當作Calendar類別和String類別轉換的中介類別。

Timestamp類別在Android當中有兩個同名類別,分別是java.sql.Timestamp以及java.security.Timestamp。使用的時候要注意不要import錯誤的package。Timestamp類別使用在SQLite資料庫中。SQLite對於記錄日期時間的方式有兩種欄位宣告的程式撰寫方式,一種是將欄位宣告成為long,直接記錄Calendar.getTimeInMillis()後的數值;另一種則是宣告成為Timestamp,預設值是使用yyyy-MM-dd hh:mm:ss.SSS的字串型式儲存。

整理一些常用的寫法如下:

  • 建立一個新的Calendar物件,預設初值為系統現在時間
    Calendar c = Calendar.getInstance();

    這是一個隱式的敘述,如果追蹤程式碼可以發現它創立了一個新的物件而不是和別人共用物件。Calendar所建立的時間是以197011日開始計算到目前為止的格林威治標準時間的milliseconds,所以不管在哪一個時區所儲存的時間都是一樣的。如果要顯示出不同時區和不同地區的時間則需要在輸出的時候由SimpleDateFormat擔任轉換的工作。
  • 設定Calendar物件到特定的時間
    Calendar c = Calendar.getInstance();
    c.set(2012, 11, 12);        
    //設定日期為20121212日,
                                 //Calendar
    類別中月份的編號是由0~11

    c.set(calendar.YEAR, 2013);                        //將年改成2013 
    c.set(Calendar.MONTH, Calendar.JANUARY);   //
    將月份改成1
    c.set(Calendar.DAY_OF_MONTH, 31);            //
    將日改成31

    c.set(Calendar.HOUR_OF_DAY, 18);               //hour改成下午六點

    c.set(Calendar.AM_PM, Calendar.PM);             //hour改成下午六點 
    c.set(Calendar.HOUR, 6);
    *** 有上面這些範例,其他時間的設定應該可以找出規律來了。
  • 取得Calendar物件資訊
    Calendar c = Calendar.getInstance();
    int year = c.get(Calendar.YEAR);                      //取出年
    int month = c.get(Calendar.MONTH) + 1;           //取出月,月份的編號是由0~11 故+1
    int day = c.get(Calendar.DAY_OF_MONTH);        //取出日

    int weekday = c.get(Calendar.DAY_OF_WEEK);  
    //取出星期幾,編號由Sunday(1)~Saturday(7)


  • CalendarDate間的互轉
    Calendar類別提供getTime()setTime()兩個方法和Date類別互轉,由函式原型來看

    public final Date getTime ()

    public final void setTime (Date date)

    要記得c.getTime()所傳回的型別就是Date類別了,在使用上要稍微留意一下。
    • Calendar to Date
      Date date = c.getTime();
    • Date to Calendar
      c.setTime(date);
  • CalendarTimestamp間的互轉
    CalendarTimestamp之間是利用milliseconds來轉換,利用getTimeInMillis()

    public long getTimeInMillis ()

    • Calendar to Timestamp
      Timestamp time = new Timestamp(c.getTimeInMillis());
    • Timestamp to Calendar
      c.setTime(time)

  • CalendarString間的互轉
    SimpleDateFormat可以用來在StringDate間互轉,透過Date做中介使得Calendar和String間可以互相轉換。
    SimpleDateFormat的樣式表可以由這裡查到,基本用法如下:
    • Calendar to String:
      SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 
      Calendar c = Calendar.getInstance();
      String str = df.format(c.getTime());
    • String to Calendar:
      SimpleDateFormat df2 = new SimpleDateFormat("yyyy/MM/dd");
      Calendar cc = Calendar.getInstance();
      try {
          cc.setTime(df2.parse("2012/12/12"));
      } catch (ParseException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
      }

      simpleDateFormat
      的模板裡面用大寫的"MM"表示月份,小寫的"mm"表示分鐘;大寫的"HH"表示24小時制的hour (0~23),小寫的"hh"表示12小時制的hour (1~12),大寫的"KK"表示
      12小時制的hour (0~11),小寫的"kk"表示24小時制的hour (1~24)。
  • 常用的SimpleDateFormat格式
    • 取出日期
      SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd");
      String str = df.format(c.getTime());
    • 取出時間(24 hr)
      SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
      String str = df.format(c.getTime());
    • 取出時間(12 hr am/pm)
      SimpleDateFormat df = new SimpleDateFormat("hh:mm:ss a");
      String str = df.format(c.getTime());

      這個型式會輸出類似:10:25:30 上午 的格式,如果想要輸出成為 10:25:30 AM則需要使用地區設定來幫忙
      SimpleDateFormat df = new SimpleDateFormat("hh:mm:ss a", Locale.US);
      String str = df.format(c.getTime());
    • 模板中如果使用超過3個字符表示需要用全名來印出
      取出月份,以文字模式
      SimpleDateFormat df = new SimpleDateFormat("MMMM dd yy, EEEE");
      會印出 "4月 06 12, 星期五"


  • Calendar常用計算
    • 加減日期 (使用add())
      Calendar c = Calendar.getInstance();
      c.add(Calendar.DAY_OF_MONTH, 2);          //加上兩天
      c.add(Calendar.MONTH, -1);
                               // 減一個月
      在加減日期運算時不需要考慮到是否有跨月份或是跨年度的問題,Calendar會幫我們處理好。
    • 只針對特別欄位作加減運算(使用roll())
      Calendar c = Calendar.getInstance();
      c.roll(Calendar.MONTH, 10); 
         // 若目前日期是2012/6/12
                                                        // 運算過後會變成 2012/4/12
                                                        // 表示只會更改月份,不會影響其他欄位 ( 6 + 10 - 12 = 4)
    • 計算兩個日期間的間隔 ( I )
      Calendar c1 = Calendar.getInstance(); 
      Calendar c2 = Calendar.getInstance(); 
      c1.set(2012, Calendar.JANUARY, 31);
      c2.set(2012, Calendar.MAY, 5);  

      int day1 = c1.get(Calendar.DAY_OF_YEAR);
      int day2 = c2.get(Calendar.DAY_OF_YEAR); 
      int dayDiff = day2 - day1;

      上面的運算中,如果兩個日期不在同一年度則需要先判斷年度再進行日期計算
    • 計算兩個日期間的間隔 ( II )利用millisecond來計算。
      Calendar c1 = Calendar.getInstance(); 
      Calendar c2 = Calendar.getInstance(); 
      c1.set(2012, Calendar.JANUARY, 31);
      c2.set(2012, Calendar.MAY, 5);
       

      long aDayInMilliSecond = 60 * 60 * 24 * 1000;     //一天的毫秒數
      long dayDiff = (c2.getTimeInMillis() - c1.getTimeInMillis()) / aDayInMilliSecond;
    • 取得這個月有幾天
      c.set(Calendar.MONTH, Calendar.FEBRUARY);
      int daysInMonth = c.getActualMaximum(Calendar.DAY_OF_MONTH);

      這個函式會傳回特定欄位的最大值,可以用來傳回一個月有幾天。包含閏年的2月有29天都可以正確的回傳。
  • 利用cursor取得SQLite內的Timestamp內容

    Timestamp c = Timestamp.valueOf(cursor.getString(ColumnIndex);

3 則留言:

  1. 請問在 計算兩個日期間的間隔 ( I ) 之中
    您所說的「如果兩個日期不在同一年度則需要先判斷年度再進行日期計算」是用什麼樣的方式去判斷呢

    回覆刪除
  2. 請問setDate()及setTime()無作用, 執行之後, 系統時間無變化, log也無error訊息, 我的App是在 /system下, 也加了permission SET_TIME, 是否還有什麼地方要修改才能把時間設進系統?

    回覆刪除
    回覆
    1. 這個範例沒有設定系統時間。
      一般來說APP不能設定系統時間,不管你有沒有加上permission SET_TIME。可以參考這個討論串
      https://stackoverflow.com/questions/1332269/how-to-set-mobile-system-time-and-date-in-android

      刪除