Java 日期時間處理

MuhammadJor 8年前發布 | 20K 次閱讀 Java Java開發

來自: http://www.importnew.com/17921.html

Date

java.util.Date對象表示一個精確到毫秒的瞬間; 但由于Date從JDK1.0起就開始存在了,歷史悠久,而且功能強大(既包含日期,也包含時間),所以他的大部分構造器/方法都已Deprecated,因此就不再推薦使用(如果貿然使用的話,可能會出現性能/安全方面的問題);下面我僅介紹它還剩下的為數不多的幾個方法(這些方法的共同點是Date與毫秒值的轉換):

  • 構造器
  • Date(): 在底層調用System.currentTimeMillis()作為日期參數.
  • Date(long date): 根據指定的long整數(從1970-1-1 00:00:00以來經過的毫秒數)來生成Date對象.
  • 方法
  • boolean after(Date when): 測試this日期是否在指定日期when之后;
  • boolean before(Date when): 測試this日期是否在指定日期when之前;
  • long getTime(): 獲取從1979-01-01 00:00:00 到Date對象之間經過的毫秒值;
  • void setTime(long time): 設置時間,time含義上同.

/**

  • Created by jifang on 15/12/30. */ public class DateTest { @Test public void test() { Date dateBefore = new Date(); Date dateAfter = new Date(System.currentTimeMillis() + 1); System.out.println("before: " + dateBefore.getTime()); System.out.println("after: " + dateAfter.getTime()); System.out.println(dateBefore.before(dateAfter)); System.out.println(dateAfter.after(dateBefore)); dateBefore.setTime(System.currentTimeMillis()); System.out.println(dateBefore.getTime()); System.out.println(dateBefore.before(dateAfter)); } }</pre>

    Calendar

    由于Date存在缺陷,所以JDK又提供了java.util.Calendar來處理日期和時間.Calendar是一個抽象類,是所有日歷類的模板,因此,我們可以繼承Calendar來實現其他的歷法(比如陰歷);

    Java中提供了一種Calendar的默認實現java.util.GregorianCalendar格里高利日歷(其實JDK還默認提供了一款日本歷法java.util.JapaneseImperialCalendar),也就是我們所說的公歷. 使用Calendar.getInstance();獲取的就是默認的GregorianCalendar,getInstance()方法的內部會調用cal = new GregorianCalendar(zone, aLocale);來生成一個格里高利日歷實例.

    • Calendar還可以和Date自由轉換.

    public class CalendarTest {
    @Test
    public void test() {
    Calendar calendar = Calendar.getInstance();
    Date date = calendar.getTime();
    Calendar newCalendar = Calendar.getInstance();
    newCalendar.setTime(date);
    System.out.println(calendar.get(Calendar.DATE));
    }
    }

    • Calendar類提供了大量訪問/修改日期/時間的方法, 常用的方法如下:
    Method Description
    void add(int field, int amount) Adds or subtracts the specified amount of time to the given calendar field, based on the calendar’s rules.
    int get(int field) Returns the value of the given calendar field.
    int getActualMaximum(int field) Returns the maximum value that the specified calendar field could have, given the time value of this Calendar.
    int getActualMinimum(int field) Returns the minimum value that the specified calendar field could have, given the time value of this Calendar.
    void roll(int field, int amount) Adds the specified (signed) amount to the specified calendar field without changing larger fields.
    void set(int field, int value) Sets the given calendar field to the given value.
    void set(int year, int month, int date) Sets the values for the calendar fields YEAR, MONTH, and DAY_OF_MONTH.
    void set(int year, int month, int date, int hourOfDay, int minute, int second) Sets the values for the fields YEAR, MONTH, DAY_OF_MONTH, HOUR, MINUTE, and SECOND.
    void setTimeInMillis(long millis) Sets this Calendar’s current time from the given long value.
    long getTimeInMillis() Returns this Calendar’s time value in milliseconds.

    上面的很多方法都需要一個int類型的field參數, field是Calendar類的類變量, 如:Calendar.DATE Calendar.MONTH Calendar.HOUR Calendar.DAY_OF_WEEK, 但需要指出的是Calendar.MONTH月份的起始值不是1, 而是0(一月:0, 二月:1 …), Calendar.DAY_OF_WEEK代表的星期, 起始值是周日(周日:1, 周一:2 …)(其他細節請參考JDK文檔).

    注意:

    • 如果Calendar沒有設置相關的值, 就以當前系統時間來設置.
    • add(int field, int amount)的功能非常強大, 如果需要增加某字段, 則讓amount為正數, 如果要減少某字段的值, 讓amount為負數. 且當超出他的允許范圍時, 會發生進位.
    • roll()的含義與用法和add()的類似,但是當被修改的字段超出它允許的范圍時, 他不會進位.
    • set(int field, int value)方法具有延遲修改的功能:他內部設置了一個成員變量,以指示日歷字段field已經被修改,但是該Calendar所代表的時間不會立即修改, 他會直到下次調用get/getTime/getTimeInMillis/add/roll時才會重新計算日歷時間.

    public int get(int field)
    {
    complete();
    return internalGet(field);
    }
    public long getTimeInMillis() {
    if (!isTimeSet) {
    updateTime();
    }
    return time;
    }

    測試

    public class CalendarTest {
    @Test
    public void test() {
    Calendar calendar = Calendar.getInstance();
    calendar.set(2011, Calendar.JULY, 31);
    calendar.set(Calendar.MONTH, Calendar.SEPTEMBER);
    // 將下面注釋放開, 再測試
    // System.out.println(calendar.get(Calendar.MONTH) + 1 + "月" + calendar.get(Calendar.DATE) + "日");
    calendar.set(Calendar.DATE, 5);
    System.out.println(calendar.get(Calendar.MONTH) + 1 + "月" + calendar.get(Calendar.DATE) + "日");
    }
    }

    日期格式化

    完成字符串與日期對象的轉化(format/parse)

    DateFormat

    java.text.DateFormat是一個抽象類, 他提供了如下幾個方法獲取DateFormat對象.

    方法 描述
    static DateFormat getDateInstance() Gets the date formatter with the default formatting style for the default locale.
    static DateFormat getDateTimeInstance() Gets the date/time formatter with the default formatting style for the default locale.
    static DateFormat getTimeInstance() Gets the time formatter with the default formatting style for the default locale.

    其實上面三個方法還可以指定日期/時間的樣式, 如FULL/LONG/MEDIUM/SHOT, 通過這四個樣式參數可以控制生成的格式化字符串. 但由于在我們的實際開發中很少直接用DateFormat類,因此就不對其做過多的介紹.而我們比較常用的是其子類SimpleDateFormat(其實上面幾個getXxxInstance方法返回的也是SimpleDateFormat實例)

    DateFormat dateFormat = DateFormat.getTimeInstance();
    System.out.println(dateFormat.getClass().getName());

    SimpleDateFormat

    java.text.SimpleDateFormat可以非常靈活的格式化Date, 也可以用于解析各種格式的日期字符串.創建SimpleDateFormat對象時需要傳入一個pattern字符串,這個pattern不是正則表達式,而是一個日期模板字符串.

    /**

  • Created by jifang on 15/12/30. */ public class FormatTest { @Test public void client() throws ParseException { DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); // Date -> String Date date = new Date(System.currentTimeMillis()); System.out.println(format.format(date)); // String -> Date String timeString = "2015-12-30 08:53:21"; Date newDate = format.parse(timeString); System.out.println(newDate); } }</pre>

    在時間日期格式化時, 有下面幾個方法是最常用的:

    方法 描述 小結
    String format(Date date) Formats a Date into a date/time string. Date -> String
    Date parse(String source) Parses text from the beginning of the given string to produce a date. String -> Date

    當然, pattern我們還可以根據我們的需求有其他的定制形式:

    @Test
    public void client() throws ParseException {
    DateFormat format = new SimpleDateFormat("yy年MM月dd日 hh時mm分ss秒");
    // Date -> String
    Date date = new Date(System.currentTimeMillis());
    System.out.println(format.format(date));
    // String -> Date
    String timeString = "15年12月30日 09時00分29秒";
    Date newDate = format.parse(timeString);
    System.out.println(newDate);
    }

    可以看出SimpleDateFormat把日期格式化成怎樣的字符串以及能把怎樣的字符串解析成Date, 完全取決于創建對象時指定的pattern參數,其他的pattern參數以及SimpleDateFormat的方法可以參考JDK文檔.

    數據庫存儲時間實戰

    由于時間存儲會涉及到跨時區的問題(同一個UTC時間在各個時區顯示的是不同的數值).因此,在我們向數據庫中插入時間是需要小心謹慎,不能簡單單單的使用數據庫提供的TIMESTAMP或是DATETIME 類型,比較推薦的是選用一個整數類型(如BIGINT64位與Java的Long類型相同),來存儲從`1970-01-01 00:00:00到時間點所經過的毫秒數(具體原因詳見:如何正確地處理時間).

    • 這樣做的優點是:讀取時間時(一個Long類型整數),只需要按照用戶的時區格式化為字符串就能正確地顯示出來.
    • 當然這樣做也存在缺陷,那就是當我們開發人員/DB直接查看數據庫時,看到的只是一串數字,并不能清楚的知曉其對應的時間日期.

    上面講完了數據庫該如何存儲時間值,下面我們再聊一聊時間[存入/讀出]數據庫的轉化問題:

    • 從Date轉換成Long 很簡單:

    Date date = new Date();
    long time = date.getTime();

    • 從Long轉換成一個時間的String我們需要SimpleDateFormat的一個方法:

    // Formats an object to produce a string.| Object -> String
    String format(Object obj);
    // 當然pattern字符串可以指定為其他值
    String time = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(System.currentTimeMillis());

    配置單例Formatter

    由于在一個項目中時間格式化和解析的格式一般只有一種(我們應該不希望格式化之后的time到最后反而解析不出來),因此我們沒有必要每次使用時都new出一個Formatter來,這樣不光會造成性能下降還有可能造成時間形式不統一而出錯.因此,我們可以在Sring的容器中裝載一個Formatter Bean,使用時@Autowired就可以了:

    <!-- 配置時間格式化器 -->
    <bean id="dateFormatter" class="java.text.SimpleDateFormat">
    <constructor-arg value="yyyy-MM-dd HH:mm:ss"/>
    </bean>
    @Autowired
    private DateFormat dateFormatter;
    ...
    String time = dateFormatter.format(System.currentTimeMillis());
    </div>

 本文由用戶 MuhammadJor 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!