來到新公司工作也有一個多月了, 陸陸續續做了一些簡單的項目. 今天做一個新東西的時候發現了 Joda Time的這個東西, 因為以前用的都是JDK原生的時間處理API, 大家都知道Java原生的時間處理的API一直都是不太好用, 所以這個有必要去學習下, 去總結下.
來到新公司學到的東西挺多的, 比如我們用了Guava, ElasticSearch, kafka/mns/ons, GuavaCache/Ehcache/Memcahe .... 等很多東西都是我以前沒有接觸過的. 所以待我學習的東西還有很多. 每天都是懷着激動的心情, 去汲取更多的知識. 說了這么多屁話, 開始總結了.
一: 使用示例
因為雙十一就快到了, 所以接觸了一個秒殺的活動, 其中有這么一塊代碼:
1 /**
2 * 檢查抽獎時間 3 * 4 * @return true 可以抽獎 false 不能抽獎 5 */
6 private boolean checkDrawTime() { 7 return DateTime.parse("2016-11-11 11:11:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).isBeforeNow(); 8 }
這個方法很簡單, 就是檢查現在的時間是不是2016/11/11 11:11:00 之前. 當然這里的DateTime是Jode Time里的類.
查看源碼可以知道, DateTime.parse就是將輸入的時間轉換為后面的格式, 轉換的結果為:
然后再用isBeforeNow方法來比較, 下面看下這個方法具體的做法:
1 public boolean isBeforeNow() { 2 return this.isBefore(DateTimeUtils.currentTimeMillis()); 3 } 4
5 public boolean isBefore(long var1) { 6 return this.getMillis() < var1; 7 }
這樣看過來是不是很清楚了, 當然Java 自帶的JDK也是可以完成的, 但是Joda Time都給我封裝好了, 用起來就更加簡單了.
接下來看看更多的例子:
1、創建任意時間對象
1 //jdk
2 Calendar calendar=Calendar.getInstance();
3 calendar.set(2012, Calendar.NOVEMBER, 15, 18, 23,55); 4 5 //Joda-time 6 DateTime dateTime=new DateTime(2012, 12, 15, 18, 23,55);
2、計算兩日期相差的天數
1 //jdk
2 Calendar start = Calendar.getInstance();
3 start.set(2012, Calendar.NOVEMBER, 14); 4 5 Calendar end = Calendar.getInstance(); 6 end.set(2012, Calendar.NOVEMBER, 15); 7 8 long startTim = start.getTimeInMillis(); 9 long endTim = end.getTimeInMillis(); 10 long diff = endTim-startTim; 11 int days=(int) (diff/1000 / 3600 / 24); 12 13 14 //joda-time 15 LocalDate start=new LocalDate(2012, 12,14); 16 LocalDate end=new LocalDate(2012, 12, 15); 17 int days = Days.daysBetween(start, end).getDays();
3、獲取18天之后的某天在下個月的當前周的第一天日期
1 //jdk
2 Calendar current = Calendar.getInstance();
3 current.add(Calendar.DAY_OF_MONTH, 18); 4 current.add(Calendar.MONTH, 1); 5 ...... 6 DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 7 Date date = current.getTime(); 8 String dateStr = dateFormat.format(date); 9 System.out.println(dateStr); 10 11 //joda-time 12 String dateStr = new DateTime().plusDays(18).plusMonths(1) 13 .dayOfWeek().withMinimumValue().toString("yyyy-MM-dd HH:mm:ss"); 14 System.out.println(dateStr);
4、時間格式化
1 DateTimeFormatter format = DateTimeFormat .forPattern("yyyy-MM-dd HH:mm:ss");
2
3 //時間解析
4 DateTime dateTime = DateTime.parse("2012-12-21 23:22:45", format); 5 6 //時間格式化,輸出==> 2012/12/21 23:22:45 Fri 7 String string_u = dateTime.toString("yyyy/MM/dd HH:mm:ss EE"); 8 System.out.println(string_u); 9 10 //格式化帶Locale,輸出==> 2012年12月21日 23:22:45 星期五 11 String string_c = dateTime.toString("yyyy年MM月dd日 HH:mm:ss EE",Locale.CHINESE); 12 System.out.println(string_c);
5、與JDK互操作
1 //通過jdk時間對象構造
2 Date date = new Date();
3 DateTime dateTime = new DateTime(date); 4 5 Calendar calendar = Calendar.getInstance(); 6 dateTime = new DateTime(calendar); 7 8 // Joda-time 各種操作..... 9 dateTime = dateTime.plusDays(1) // 增加天 10 .plusYears(1)// 增加年 11 .plusMonths(1)// 增加月 12 .plusWeeks(1)// 增加星期 13 .minusMillis(1)// 減分鍾 14 .minusHours(1)// 減小時 15 .minusSeconds(1);// 減秒數 16 17 // 計算完轉換成jdk 對象 18 Date date2 = dateTime.toDate(); 19 Calendar calendar2 = dateTime.toCalendar(Locale.CHINA)
二: api簡介
Maven項目組中引入Joda Time坐標地址:
<!-- joda -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.3</version>
</dependency>
1, 日期和時間:
Joda-time里面的時間全都是不可變的,也就是不可變性。
DateTime :類似於JDK中的Calendar,提供了更多的方法。
DateMidnight :這個概念稍微復雜,封裝某個時區(通常為默認時區)在特定年/月/日的午夜時分的時刻。它基本上類似於
DateTime,不同之處在於時間部分總是為與該對象關聯的特定
DateTimeZone 時區的午夜時分。
LocalDate :無時間的類,只包含年月日。(不包含時區)
LocalTime :無日期的類,只包含時間。(不包含時區)
LocalDateTime :包含日期和時間。(不包含時區)
下面舉一些簡單的例子說明Joda-time的強大之處:
1 //獲取當前月份: 2 DateTime dt = new DateTime(); 3 int month = dt.getMonthOfYear(); 4 //設定2000年/獲取當前小時+2的小時: 5 DateTime dt = new DateTime(); 6 DateTime year2000 = dt.withYear(2000); 7 DateTime twoHoursLater = dt.plusHours(2); 8 System.out.println(year2000.getYear()); 9 System.out.println(twoHoursLater.getHourOfDay()); 10 //以及下面的一些操作: 11 String monthName = dt.monthOfYear().getAsText(); 12 String frenchShortName = dt.monthOfYear().getAsShortText(Locale.FRENCH); 13 boolean isLeapYear = dt.year().isLeap(); 14 DateTime rounded = dt.dayOfMonth().roundFloorCopy(); 15 System.out.println(monthName); // 本地月份名稱 16 System.out.println(frenchShortName); // 法語月份簡稱 17 System.out.println(isLeapYear); // 是否閏年 18 System.out.println(rounded); // 獲取當天0:0:0的DateTime對象
2, 日歷系統及時區
Joda-time支持多種年表(即日歷系統)及所有時區。主要的兩個類如下:
Chronology :年表,Joda-time支持很多年表。就像JDK有Calendar,也有GregorianCalendar。
DateTimeZone :時區。
示例如下,一般系統都沒有這個需求。
1 Chronology coptic = CopticChronology.getInstance(); 2 System.out.println(coptic); // CopticChronology[Asia/Shanghai] 3 4 DateTimeZone zone = DateTimeZone.forID("Asia/Tokyo"); 5 Chronology gregorianJuian = GJChronology.getInstance(zone); 6 System.out.println(gregorianJuian); // GJChronology[Asia/Tokyo]
3, 時間跨度
Joda-time支持的時間跨度有三個,分別如下:
Interval :根據開始、結束時間表示一個特定的時間跨度。其為半開區間,即包括起始時刻,不包含結束時刻。
Period :Period設定了一些特定的時間跨度,比如小時、天、月。
Duration :表示絕對的精准跨度,以毫秒為單位。
使用示例如下:
1 DateTime beginDateTime = new DateTime(2010, 1, 1, 0, 0, 0); 2 DateTime endDateTime = new DateTime(2015, 1, 1, 0, 0, 0); 3 Interval interval = new Interval(beginDateTime, endDateTime); 4 System.out.println(interval.containsNow()); // 是否包含當前時間 5 System.out.println(interval.toDurationMillis()); // 時間間隔毫秒數 6 7 DateTime dt = new DateTime(2005, 3, 26, 12, 0, 0, 0); 8 DateTime plusPeriod = dt.plus(Period.days(1)); 9 System.out.println(plusPeriod); // Period的方式+1天 10 DateTime plusDuration = dt.plus(new Duration(24L * 60L * 60L * 1000L)); 11 System.out.println(plusDuration); // Duration的方式+1天
三: Joda-time使用的理念
不可變性(Immutability)
瞬間性(Instant)
局部性(Partial)
年表(Chronology)
時區(Time zone)
不可變
Joda-time的類具有不可變性,因此它們的實例無法被修改。(不可變類的一個優點就是它們是線程 安全 的)。用於處理日期計算的 API 方法全部返回一個對應 Joda-time 類的新實例,同時保持原始實例不變。當我們通過一個 API 方法操作 Joda 類時,我們必須捕捉該方法的返回值,因為我們正在處理的實例不能被修改。你可能對這種模式很熟悉,這正是 java.lang.String 的各種操作方法的工作 方式。
瞬間性
Instant 表示時間上的某個精確的時刻,使用從 epoch 開始計算的毫秒表示。這一定義與 JDK 相同,這就是為什么任何 Joda Instant 子類都可以與 JDK Date 和 Calendar 類兼容的原因。
更通用一點的定義是:一個瞬間 就是指時間線上只出現一次且唯一的一個時間點,並且這種日期結構只能以一種有意義的方式出現一次。
局部性
一個局部時間,正如我將在本文中將其稱為局部時間片段一樣,它指的是時間的一部分片段。瞬間性指定了與 epoch 相對的時間上的一個精確時刻,與此相反,局部時間片段指的是在時間上可以來回 “移動” 的一個時刻,這樣它便可以應用於多個實例。比如,6 月 2 日 可以應用於任意一年的 6 月份(使用 Gregorian 日歷)的第二天的任意瞬間。同樣,11:06 p.m. 可以應用於任意一年的任意一天,並且每天只能使用一次。即使它們沒有指定一個時間上的精確時刻,局部時間片段仍然是有用的。
我喜歡將局部時間片段看作一個重復周期中的一點,這樣的話,如果我正在考慮的日期構建可以以一種有意義的方式出現多次(即重復的),那么它就是一個局部時間。
年表
Joda 本質——以及其設計核心——的關鍵就是年表(它的含義由一個同名抽象類捕捉)。從根本上講,年表是一種日歷系統——種計算時間的特殊方式——並且是一種在其中執行日歷 算法 的框架。受 Joda 支持的年表的例子包括:ISO(默認)、Coptic、Julian、Islamic等。
時區
時區是值一個相對於英國格林威治的地理位置,用於計算時間。要了解事件發生的精確時間,還必須知道發生此事件的位置。任何嚴格的時間計算都必須涉及時區(或相對於 GMT),除非在同一個時區內發生了相對時間計算(即時這樣時區也很重要,如果事件對於位於另一個時區的各方存在利益關系的話)。
DateTimeZone 是 Joda 庫用於封裝位置概念的類。許多日期和時間計算都可以在不涉及時區的情況下完成,但是仍然需要了解 DateTimeZone 如何影響 Joda 的操作。默認時間,即從運行代碼的機器的系統時鍾檢索到的時間,在大部分情況下被使用。
好了, 我所了解的就是這么多, 我主要還是從如何使用的角度去學習這個東西, 最后總結了它的幾個特性, 當然Joda-Time的強大之處遠不止這些, 大家在以后的工作中可以嘗試着去使用它.