Java中日期時間API小結

Java中爲處理日期和時間提供了大量的API,確實有把一件簡單的事情搞複雜的嫌疑,各類類:Date Time Timestamp Calendar...,可是若是可以看到時間處理的本質就能夠輕鬆hold住這堆東西了。
java

經常使用的類

表示類

  • java.util.Date :可以準確記錄到毫秒級別的時間表示類,可是其中的各類get set(修改時間或者獲取時間中某一個特殊參數)都已經被廢棄。
  • java.sql.Date :爲數據庫提供的日期類,繼承自util包中的Date,可是這個類只可以操做日期,不能讀取或者修改時間。sql和util中Date內部進行存儲的long,均可以保存到毫秒級別
  • java.sql.Time :爲數據庫提供的時間類,和Date相反,它只能獲取和操做時間相關的信息。
  • java.sql.Timestamp:時間戳,繼承util.Date,它不只可以完美支持util.Date的功能,並且能夠支持到納秒級別(10^-9 s)。

工具類

  • Calendar:主要用來操做一個Date類型,提供了一系列接口來獲取或修改其中的信息。
  • TimeZone:用來配合Calendar 操做Date,主要是考慮時區的問題,值得注意的是,在Date中存儲的信息是一個絕對標準時間(稍後說明),而若是須要進行時區的轉化,那麼只須要配合此類便可。
  • SimpleDateFormat:經常使用的格式化Date的工具,主要是進行String和日期之間的互換。

基本概念

時間的來源

注意,這裏並非討論一個哲學的問題,在大部分的編程語言中,咱們都是採用從1970-01-01 00:00:00.000 開始至今的毫秒差做爲表示時間的數值,這個時間是絕對公立的,它和時區沒有任何關係。在Java中任什麼時候間的表示類的底層存儲的毫秒數都是一個這樣的標準時間。git

在java中獲取當前時間接口是System.currentTimeMillis()github

值得一提的是Java還提供了一個更加精確的時間:System.nanoTime(),獲取一個時間精確到納秒,可是它並非一個當前的精確時間,而是JVM提供的一個時間,它的主要用途是來精確衡量兩個時間段之間的時間,如計算一段代碼的執行時間:sql

long startTime = System.nanoTime();
   // ... the code being measured ...
   long estimatedTime = System.nanoTime() - startTime;

能夠比較兩個接口返回的內容:
System.currentTimeMillis():1429108246639
System.nanoTime():1429108246640(ms)089000------->多了6位數據庫

UTC和GMT

這兩個標準惟一不一樣之處在於UTC是基於GMT進行微調以後的一個時間,本文不去深究這二者的差異,在此認爲這二者是一個東西。編程

初中地理教過咱們,地球是24個時區,東部和西部各12個,時區的基準點是倫敦(基準UTC),往東,會領先UTC,往西,會落後UTC。api

如北京屬於東八區,那麼咱們的時間會領先基準,也就是咱們在早上9點時,倫敦是早上1點。若是咱們在不一樣時區接發郵件的時候,能夠發現這個問題。編程語言

這個時間是我收到一份來自華盛頓的郵件的時間:工具

2014年1月23日(星期四) 晚上7:29 (UTC-05:00 華盛頓、多倫多、古巴、智利時間)google

這裏咱們能夠在郵件時間後面發現UTC-05:00,說明這裏是落後UTC基準5個小時。注意,前面的時間是發件人的本地時間,若是轉化成北京所在時區的時間應該是加上13h,那我收到這封郵件的本地時間是:2014-01-24 星期五早上8:29。

再談TimeStamp

前面說了,TimeStamp可以精確到納秒,那它是怎麼作到的呢?因爲TimeStamp繼承自Date,它把整數秒存儲在超類中,而在子類中專門用一個long類型存儲零的秒數:nanos

須要注意,除非你顯示去調用TimeStamp的這個構造器:
public Timestamp(int year, int month, int date, int hour, int minute, int second, int nano)

顯示去指定nano的值,不然這個構造器的參數
public Timestamp(long time)

的單位其實是毫秒。

API的使用

最後再來講說日期時間的操做接口,過程基本以下圖:

SimpleDateFormat <------>  Date   <---------> Calendar

Date負責存儲一個絕對時間,並對兩邊提供操做接口。Calendar負責對Date中特定信息,好比這個時間是改年的第幾個星期,此外,還能夠經過set,add,roll接口來進行日期時間的增減。SimpleDateFormat主要做爲一些格式化的輸入輸出。

SimpleDateFormat

SimpleDateFormat的構造器接受一個String pattern,其中的pattern是預約義的:

G 年代標誌符
y 年
M 月
d 日
h 時 在上午或下午 (1~12)
H 時 在一天中 (0~23)
m 分
s 秒
S 毫秒
E 星期
D 一年中的第幾天
F 一月中第幾個星期幾
w 一年中第幾個星期
W 一月中第幾個星期
a 上午 / 下午 標記符 
k 時 在一天中 (1~24)
K 時 在上午或下午 (0~11)
z 時區

例子1:

SimpleDateFormat DATETIME_FORMATER_WITHWEEK = new SimpleDateFormat(
            "yyyy-MM-dd E HH:mm");

    java.util.Date date = new java.util.Date();
    System.out.println(DATETIME_FORMATER_WITHWEEK.format(date));
    
    //output: 2015-04-15 星期三 23:59 
    //固然,反過來,我也可使用這個format將output的字符串轉化成Date

Calendar

Calendar中主要須要瞭解的各類操做域,感受這也是Java在作這個API時的一個敗筆,靈活有餘,可控性不足,初學者若是亂用域,將會產生各類bug。至於每個域對應的時間份量,請自行google。

一些經常使用的filed:

  • YEAR:年
  • MONTH:月(從0 開始,0 表示1月....11表示12月)
  • DAY_OF_MONTH :幾號(等同DATE)
  • DAY_OF_WEEK:星期幾
  • DAY_OF_YEAR:年裏面的天
  • DATE:幾號(等同DAY_OF_MONTH)

一個filed一般來講對應了日期時間中的某一個份量,在操做這個分類有些操做會向高位進位,而有的操做則不會【bug高發區域】。

例子2:

SimpleDateFormat DATETIME_FORMATER_WITHWEEK = new SimpleDateFormat(
     "yyyy-MM-dd E");
    Calendar calendarT = Calendar.getInstance(Locale.CHINA);
    System.out.println(DATETIME_FORMATER_WITHWEEK.format(calendarT.getTime()));
    calendarT.set(Calendar.MONTH,12);// 月份進位
    System.out.println(DATETIME_FORMATER_WITHWEEK.format(calendarT.getTime()));
    //output:   2015-04-16 星期四
                    2016-01-16 星期六

例子3:

SimpleDateFormat DATETIME_FORMATER_WITHWEEK = new SimpleDateFormat(
     "yyyy-MM-dd E");
    Calendar calendarT = Calendar.getInstance(Locale.CHINA);
    System.out.println("原始    :"+DATETIME_FORMATER_WITHWEEK.format(calendarT.getTime()));
    calendarT.set(Calendar.DAY_OF_MONTH,1);// 當月第一天
    System.out.println("當月第一天:"+DATETIME_FORMATER_WITHWEEK.format(calendarT.getTime()));
    //roll不會進位
    calendarT.roll(Calendar.DATE,-1);
    System.out.println("roll -1:"+DATETIME_FORMATER_WITHWEEK.format(calendarT.getTime()));
    calendarT.set(Calendar.DAY_OF_MONTH,1);// 當月第一天
    calendarT.add(Calendar.DATE,-1);
    //add產生進位
    System.out.println("add -1:"+DATETIME_FORMATER_WITHWEEK.format(calendarT.getTime()));
    
    //output:原始    :2015-04-16 星期四
                當月第一天:2015-04-01 星期三
                roll -1:2015-04-30 星期四
                add -1:2015-03-31 星期二

最後仍是須要說明一點,獲取當前時間指的是當前本地時間對應的UTC時間,和時區沒有關係!有點繞,不要緊看代碼:

例子4:

Calendar calendar1 = Calendar.getInstance(Locale.CHINA);
    Calendar calendar2 = Calendar.getInstance(Locale.GERMAN);
    System.out.println(calendar1.getTimeInMillis());
    System.out.println(calendar2.getTimeInMillis());
    
    //output:
        1429115150117
        1429115150117

最後貼一個日期處理開源庫:joda-time

相關文章
相關標籤/搜索