話說Java一連設計了兩套時間工具,分別是日期類型Date,以及日曆類型Calendar,按理說用在編碼開發中綽綽有餘了。然而隨着Java的日益普遍使用,人們仍是發現了它們的種種弊端。且不說先天不良的Date類型,單說後起之秀的Calendar類型,這個日曆工具在實際開發中仍然存在如下毛病:
一、日曆工具獲取當前月份的時候,與Date同樣都是從0開始計數,好比經過get方法得到的一月份數值爲0;
二、日曆工具獲取當天是星期幾的時候,星期日是排在最前面的,經過get方法得到的星期日數值爲1,而星期一數值竟然是2!
三、日曆工具可以表達的最小時間單位是毫秒,使得時間精度不夠高,難以用在更加精密的科學運算場合。
四、日曆工具沒有提供閏年的判斷方法。
五、日曆工具缺少本身的格式化工具,竟然還得藉助於Date類型那邊的格式化工具SimpleDateFormat,方能將日期時間按照指定格式輸出爲字符串。
總而言之,不論是Date仍是Calendar,在解決複雜問題之時的編碼都很彆扭,故而每一個Java工程基本要從新編寫一個日期處理工具DateUtil,在新工具內部封裝常見的日期處理操做,這樣才能知足實際業務的開發要求。因而Date和Calendar兩個難兄難弟從JDK1.1開始並肩做戰,一路走到Java五、Java6乃至Java7,後來估摸着無可救藥了,乾爹Oracle一不作、二不休,終於在Java8推出了全新的日期時間類型,意圖經過新類型一勞永逸治好Date和Calendar的沉痾宿疾。
全新的日期時間類型不僅僅是一個類型,而是一個家族,它的成員主要有LocalDate、LocalTime、LocalDateTime等等,接下來分別介紹這幾個日期時間類型:html
一、本地日期類型LocalDate
獲取本地日期的實例很簡單,調用該類型的now方法便可,而且顧名思義獲得的是當前日期。經過本地日期獲取年月日的數值,就是平常生活中的習慣數字,例如一月份對應的數值是1,十二月份對應的數值是12,星期一對應的數值是1,星期日對應的數值是7等等。此外,本地日期額外提供了幾個經常使用的統計方法,包括:該日期所在的年份一共有多少天、該日期所在的月份一共有多少天、該日期所在的年份是否爲閏年等。下面的代碼便演示瞭如何從本地日期獲取各類數值的例子:java
// 得到本地日期的實例 LocalDate date = LocalDate.now(); System.out.println("date=" + date.toString()); // 得到該日期所在的年份 int year = date.getYear(); System.out.println("year=" + year); // 得到該日期所在的月份。注意getMonthValue方法返回的是數字月份,而getMonth方法返回的是英文月份 int month = date.getMonthValue(); System.out.println("month=" + month + ", english month=" + date.getMonth()); // 得到該日期所在的日子 int dayOfMonth = date.getDayOfMonth(); System.out.println("dayOfMonth=" + dayOfMonth); // 得到該日期在一年當中的序號 int dayOfYear = date.getDayOfYear(); System.out.println("dayOfYear=" + dayOfYear); // 得到該日期是星期幾。注意getDayOfWeek方法返回的是英文的星期幾,後面跟着的getValue方法才返回數字的星期幾 int dayOfWeek = date.getDayOfWeek().getValue(); System.out.println("dayOfWeek=" + dayOfWeek + ", english weekday=" + date.getDayOfWeek()); // 得到該日期所在的年份一共有多少天 int lengthOfYear = date.lengthOfYear(); System.out.println("lengthOfYear=" + lengthOfYear); // 得到該日期所在的月份一共有多少天 int lengthOfMonth = date.lengthOfMonth(); System.out.println("lengthOfMonth=" + lengthOfMonth); // 判斷該日期所在的年份是否爲閏年 boolean isLeapYear = date.isLeapYear(); System.out.println("isLeapYear=" + isLeapYear);
除了建立處於當前日期的本地實例,LocalDate還支持建立指定日期的本地實例,就像如下代碼示範的那樣:工具
// 構造一個指定年月日的日期實例 LocalDate dateManual = LocalDate.of(2018, 11, 22); System.out.println("dateManual=" + dateManual.toString());
至於針對某個單位的數值,LocalDate也提供了專門的修改方法,例如以plus打頭的系列方法用來增長日期數值,以minus打頭的系列方法用來減小日期數值,以with打頭的系列方法用來設置日期數值,這些日期修改的具體用法示例以下:編碼
dateManual = dateManual.plusYears(0); // 增長若干年份 dateManual = dateManual.plusMonths(0); // 增長若干月份 dateManual = dateManual.plusDays(0); // 增長若干日子 dateManual = dateManual.plusWeeks(0); // 增長若干星期 dateManual = dateManual.minusYears(0); // 減小若干年份 dateManual = dateManual.minusMonths(0); // 減小若干月份 dateManual = dateManual.minusDays(0); // 減小若干日子 dateManual = dateManual.minusWeeks(0); // 減小若干星期 dateManual = dateManual.withYear(2000); // 設置指定的年份 dateManual = dateManual.withMonth(12); // 設置指定的月份 dateManual = dateManual.withDayOfYear(1); // 設置當年的日子 dateManual = dateManual.withDayOfMonth(1); // 設置當月的日子
此外,做爲一種日期類型,LocalDate一如既往地支持判斷兩個日期實例的遲早關係,好比equals方法用於判斷兩個日期是否相等,isBefore方法用於判斷A日期是否在B日期以前,isAfter方法用於判斷A日期是否在B日期以後等。具體的本地日期校驗代碼以下所示:spa
// 判斷兩個日期是否相等 boolean equalsDate = date.equals(dateManual); System.out.println("equalsDate=" + equalsDate); // 判斷A日期是否在B日期以前 boolean isBeforeDate = date.isBefore(dateManual); System.out.println("isBeforeDate=" + isBeforeDate); // 判斷A日期是否在B日期以後 boolean isAfterDate = date.isAfter(dateManual); System.out.println("isAfterDate=" + isAfterDate); // 判斷A日期是否與B日期相等 boolean isEqualDate = date.isEqual(dateManual); System.out.println("isEqualDate=" + isEqualDate);
二、本地時間類型LocalTime
前面介紹的LocalDate只能操做年月日,若要操做時分秒則需經過本地時間類型LocalTime。獲取本地時間的實例依然要調用該類型的now方法,接着就能經過該實例分別獲取對應的時分秒乃至納秒(一秒的十億分之一),下面便演示瞭如何調用LocalTime的基本方法:設計
// 得到本地時間的實例 LocalTime time = LocalTime.now(); System.out.println("time=" + time.toString()); // 得到該時間所在的時鐘 int hour = time.getHour(); System.out.println("hour=" + hour); // 得到該時間所在的分鐘 int minute = time.getMinute(); System.out.println("minute=" + minute); // 得到該時間所在的秒鐘 int second = time.getSecond(); System.out.println("second=" + second); // 得到該時間秒鐘後面的納秒單位。一秒等於一千毫秒,一毫秒等於一千微秒,一微秒等於一千納秒,算下來一秒等於十億納秒 int nano = time.getNano(); System.out.println("nano=" + nano);
如同本地日期LocalDate那樣,LocalTime也容許建立指定時分秒的時間實例,還支持單獨修改時鐘、分鐘、秒鐘和納秒。固然修改時間的途徑包括plus系列方法、minus系列方法、with系列方法等等,它們的調用方式示例以下:orm
// 構造一個指定時分秒的時間實例 LocalTime timeManual = LocalTime.of(14, 30, 25); System.out.println("timeManual=" + timeManual.toString()); timeManual = timeManual.plusHours(0); // 增長若干時鐘 timeManual = timeManual.plusMinutes(0); // 增長若干分鐘 timeManual = timeManual.plusSeconds(0); // 增長若干秒鐘 timeManual = timeManual.plusNanos(0); // 增長若干納秒 timeManual = timeManual.minusHours(0); // 減小若干時鐘 timeManual = timeManual.minusMinutes(0); // 減小若干分鐘 timeManual = timeManual.minusSeconds(0); // 減小若干秒鐘 timeManual = timeManual.minusNanos(0); // 減小若干納秒 timeManual = timeManual.withHour(0); // 設置指定的時鐘 timeManual = timeManual.withMinute(0); // 設置指定的分鐘 timeManual = timeManual.withSecond(0); // 設置指定的秒鐘 timeManual = timeManual.withNano(0); // 設置指定的納秒
另外,LocalTime依然提供了equals、isBefore、isAfter等方法用於判斷兩個時間的前後關係,具體的方法調用以下所示:htm
// 判斷兩個時間是否相等 boolean equalsTime = time.equals(timeManual); System.out.println("equalsTime=" + equalsTime); // 判斷A時間是否在B時間以前 boolean isBeforeTime = time.isBefore(timeManual); System.out.println("isBeforeTime=" + isBeforeTime); // 判斷A時間是否在B時間以後 boolean isAfterTime = time.isAfter(timeManual); System.out.println("isAfterTime=" + isAfterTime);
三、本地日期時間類型LocalDateTime
如今有了LocalDate專門處理年月日,又有了LocalTime專門處理時分秒,還須要一種類型可以同時處理年月日和時分秒,它就是本地日期時間類型LocalDateTime。LocalDateTime基本等價於LocalDateTime與LocalTime的合集,它同時擁有兩者的絕大部分方法,故這裏再也不贅述。下面是建立該類型實例的代碼片斷,讀者可參考以前LocalDateTime與LocalTime的調用代碼,嘗試補齊LocalDateTime的方法調用過程。blog
// 演示LocalDateTime的各類方法 private static void showLocalDateTime() { // 得到本地日期時間的實例 LocalDateTime datetime = LocalDateTime.now(); System.out.println("datetime=" + datetime.toString()); // LocalDateTime的方法是LocalDate與LocalTime的合集, // 也就是說LocalDate與LocalTime的大部分方法能夠直接拿來給LocalDateTime使用, // 於是下面再也不演示LocalDateTime的詳細方法如何調用了。 // 注意LocalDateTime不提供lengthOfYear、lengthOfMonth、isLeapYear這三個方法。 }
更多Java技術文章參見《Java開發筆記(序)章節目錄》開發