前言:
用過(guò)java1.8之前原生的日期處理api,你就會(huì)知道用起來(lái)非常麻煩,而且要注意的地方有點(diǎn)多(例如月份是由0開(kāi)始,而且api使用有的不統(tǒng)一,線程不安全等等...),所以在java1.8之前的日期api都不值得去使用,雖然說(shuō)現(xiàn)在都有強(qiáng)大的日期處理的第三方庫(kù),但是會(huì)有兼容性問(wèn)題,那么現(xiàn)在jdk8有了新的時(shí)間處理類,為何不去嘗試一下呢
java.time包下有5個(gè)包組成(大部分人用到基礎(chǔ)包和format包就足夠了)
java.time – 包含值對(duì)象的基礎(chǔ)包
java.time.chrono – 提供對(duì)不同的日歷系統(tǒng)的訪問(wèn)
java.time.format – 格式化和解析時(shí)間和日期
java.time.temporal – 包括底層框架和擴(kuò)展特性
java.time.zone – 包含時(shí)區(qū)支持的類
先看看對(duì)這個(gè)包的概述:
java.time 包是在JDK8新引入的,提供了用于日期签舞、時(shí)間裸准、實(shí)例和周期的主要API谋逻。
java.time包定義的類表示了日期-時(shí)間概念的規(guī)則阀圾,包括instants, durations, dates, times, time-zones and periods潦牛。這些都是基于ISO日歷系統(tǒng)泛领,它又是遵循 Gregorian規(guī)則的一喘。
所有類都是不可變的酝豪、線程安全的涛碑。
再看看對(duì)這些類的介紹:
LocalDateTime:只存儲(chǔ)了日期和時(shí)間,如:2017-03-21T14:02:43.455孵淘。(后面的.455表示毫秒值的最后三位,使用.withNano(0)可把毫秒值設(shè)為0)
LocalDate:只存儲(chǔ)了日期蒲障,如:2017-03-21。
LocalTime:只存儲(chǔ)了時(shí)間瘫证,如:14:02:43.455揉阎。(后面的.455表示毫秒值的最后三位,使用.withNano(0)可把毫秒值設(shè)為0)
Year:只表示年份。
Month:只表示月份背捌。
YearMonth:只表示年月余黎。
MonthDay:只表示月日。
DayOfWeek:只存儲(chǔ)星期的一天载萌。
Instant 相當(dāng)于java.util的Date
Clock 它通過(guò)指定一個(gè)時(shí)區(qū)惧财,然后就可以獲取到當(dāng)前的時(shí)刻巡扇,日期與時(shí)間。Clock可以替換System.currentTimeMillis()與TimeZone.getDefault()垮衷。
ZonedDateTime 可以得到特定時(shí)區(qū)的日期/時(shí)間
Duration 是用來(lái)計(jì)算兩個(gè)日期的時(shí)間差
然后再看看它與java.util.Calendar的api比較:
可以看到在java.time當(dāng)中,星期一的值為1,星期日的值為7,而在Calendar當(dāng)中星期日的值為1,而且java.time中一月份的值為1,Calendar一月份的值為0(多么反人類的設(shè)計(jì),多多少少讓人不自在),如果你會(huì)使用Calendar的話,那么你要上手java.time包也是很快的.
還有一些方法前綴的含義,統(tǒng)一了api:
of:靜態(tài)工廠方法(用類名去調(diào)用)厅翔。
parse:靜態(tài)工廠方法,關(guān)注于解析(用類名去調(diào)用)搀突。
now: 靜態(tài)工廠方法刀闷,用當(dāng)前時(shí)間創(chuàng)建實(shí)例(用類名去調(diào)用)
get:獲取某些東西的值。
is:檢查某些東西的是否是true仰迁。
with:返回一個(gè)部分狀態(tài)改變了的時(shí)間日期對(duì)象拷貝(單獨(dú)一個(gè)with方法,參數(shù)為TemporalAdjusters類型)
plus:返回一個(gè)時(shí)間增加了的甸昏、時(shí)間日期對(duì)象拷貝(如果參數(shù)是負(fù)數(shù)也能夠有minus方法的效果)
minus:返回一個(gè)時(shí)間減少了的、時(shí)間日期對(duì)象拷貝
to:把當(dāng)前時(shí)間日期對(duì)象轉(zhuǎn)換成另外一個(gè)徐许,可能會(huì)損失部分狀態(tài).
at:把這個(gè)對(duì)象與另一個(gè)對(duì)象組合起來(lái)施蜜,例如: date.atTime(time)。
format :根據(jù)某一個(gè)DateTimeFormatter格式化為字符串
新時(shí)間API類都實(shí)現(xiàn)了一系列方法用以完成通用的任務(wù)雌隅,如:加翻默、減、格式化恰起、解析修械、從日期/時(shí)間中提取單獨(dú)部分,等等
time包里面的類實(shí)例如果用了上面的方法而被修改了,那么會(huì)返回一個(gè)新的實(shí)例過(guò)來(lái),而不像Calendar那樣可以在同一個(gè)實(shí)例進(jìn)行不同的修改,體現(xiàn)了不可變
java.time.temporal.ChronoField枚舉類
此枚舉類是作為get方法的參數(shù)獲取時(shí)間的值
它里面的屬性含義有的跟Calendar的成員變量含義差不多,想要了解一下可以看我的關(guān)于Calendar類詳解的文章 ,如果要看很詳細(xì)的講解可以去查看ChronoField類的官方api文檔
演示一下判斷當(dāng)前時(shí)間是屬于上午還是下午:
LocalDateTime now = LocalDateTime.now();
switch (now.get(ChronoField.AMPM_OF_DAY)) {
case 0:
System.out.println("上午");
case 1:
System.out.println("下午");
}
//打印 下午
java.time.temporal.TemporalAdjusters類
此類配合java.time基礎(chǔ)包中類的with方法:
LocalDate now = LocalDate.now();
//當(dāng)前月份的第一天的日期,2017-03-01
System.out.println(now.with(TemporalAdjusters.firstDayOfMonth()));
//下一個(gè)月的第一天的日期,2017-04-01
System.out.println(now.with(TemporalAdjusters.firstDayOfNextMonth()));
//當(dāng)前月份的最后一天,2017-03-31 --再也不用計(jì)算是28检盼,29肯污,30還是31
System.out.println(now.with(TemporalAdjusters.lastDayOfMonth()));
java.time.format.DateTimeFormatter
此類的功能與SimpleDateFormat類的功能類似,此類也是線程安全的,在寫成時(shí)間處理工具類時(shí),可作為靜態(tài)成員變量,而不用每次都new一個(gè)SimpleDateFormat實(shí)例,此類是用來(lái)創(chuàng)建日期顯示的模板,然后對(duì)于日期的格式化和解析還是使用LocalDateTime等類的parse靜態(tài)方法和format方法,其模板屬性格式是和SimpleDateFormat一樣的,請(qǐng)看:
G 年代標(biāo)志符
y 年
M 月
d 日
h 時(shí) (12小時(shí)制)
H 時(shí) (24小時(shí)制)
m 分
s 秒
S 毫秒
E 星期幾
D 一年中的第幾天
F 一月中第幾個(gè)星期(以每個(gè)月1號(hào)為第一周,8號(hào)為第二周為標(biāo)準(zhǔn)計(jì)算)
w 一年中第幾個(gè)星期
W 一月中第幾個(gè)星期(不同于F的計(jì)算標(biāo)準(zhǔn),是以星期為標(biāo)準(zhǔn)計(jì)算星期數(shù),例如1號(hào)是星期三,是當(dāng)月的第一周,那么5號(hào)為星期日就已經(jīng)是當(dāng)月的第二周了)
a 上午 / 下午 標(biāo)記符
k 時(shí) (24小時(shí)制,其值與H的不同點(diǎn)在于,當(dāng)數(shù)值小于10時(shí),前面不會(huì)有0)
K 時(shí) (12小時(shí)值,其值與h的不同點(diǎn)在于,當(dāng)數(shù)值小于10時(shí),前面不會(huì)有0)
z 時(shí)區(qū)
對(duì)于此類使用先來(lái)個(gè)簡(jiǎn)單的新舊api對(duì)比演示:
1 .Date轉(zhuǎn)String
//使用Date和SimpleDateFormat
SimpleDateFormat simpleDateFormat =
new SimpleDateFormat("G yyyy年MM月dd號(hào) E a hh時(shí)mm分ss秒");
String format = simpleDateFormat.format(new Date());
System.out.println(format);
//打印: 公元 2017年03月21號(hào) 星期二 下午 06時(shí)38分20秒
//使用jdk1.8 LocalDateTime和DateTimeFormatter
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter pattern =
DateTimeFormatter.ofPattern("G yyyy年MM月dd號(hào) E a hh時(shí)mm分ss秒");
String format = now.format(pattern);
System.out.println(format);
//打印: 公元 2017年03月21號(hào) 星期二 下午 06時(shí)38分20秒
2 .String轉(zhuǎn)Date
//使用Date和SimpleDateFormat
SimpleDateFormat simpleDateFormat =
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date = simpleDateFormat.parse("2017-12-03 10:15:30");
System.out.println(simpleDateFormat.format(date));
//打印 2017-12-03 10:15:30
//使用jdk1.8 LocalDateTime和DateTimeFormatter
DateTimeFormatter pattern =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//嚴(yán)格按照ISO yyyy-MM-dd驗(yàn)證,03寫成3都不行
LocalDateTime dt = LocalDateTime.parse("2017-12-03 10:15:30",pattern);
System.out.println(dt.format(pattern));
下面演示一次java.time基礎(chǔ)包中的類的使用:
1. java.time.LocalDateTime
此類顯示的是年月日時(shí)分秒(默認(rèn)的格式為:2017-01-01T01:01:01.555)
LocalDateTime now = LocalDateTime.now();
System.out.println(now.toString());
System.out.println(now.getYear());
System.out.println(now.getMonthValue());
System.out.println(now.getDayOfMonth());
System.out.println(now.getHour()); //24小時(shí)制
System.out.println(now.getMinute());
System.out.println(now.getSecond());
System.out.println(now.getNano()); //毫秒值的后三位作為前三位后面補(bǔ)6個(gè)零
打印的結(jié)果為:
2017-03-21T20:26:18.317
2017
3
21
20
26
18
317000000
//能夠自定義時(shí)間
LocalDateTime time = LocalDateTime.of(2017, 1, 1, 1, 1,1);
System.out.println(time); //2017-01-01T01:01:01
//使用plus方法增加年份
LocalDateTime time = LocalDateTime.of(2017, 1, 1, 1, 1,1);
//改變時(shí)間后會(huì)返回一個(gè)新的實(shí)例nextYearTime
LocalDateTime nextYearTime = time.plusYears(1);
System.out.println(nextYearTime); //2018-01-01T01:01:01
//使用minus方法減年份
LocalDateTime time = LocalDateTime.of(2017, 1, 1, 1, 1,1);
LocalDateTime lastYearTime = time.minusYears(1);
System.out.println(lastYearTime); //2016-01-01T01:01:01
//使用with方法設(shè)置月份
LocalDateTime time = LocalDateTime.of(2017, 1, 1, 1, 1,1);
LocalDateTime changeTime = time.withMonth(12);
System.out.println(changeTime); //2017-12-01T01:01:01
//判斷當(dāng)前年份是否閏年
System.out.println("isLeapYear :" + time.isLeapYear());
//判斷當(dāng)前日期屬于星期幾
LocalDateTime time = LocalDateTime.now();
DayOfWeek dayOfWeek = time.getDayOfWeek();
System.out.println(dayOfWeek); //WEDNESDAY
2. java.time.LocalDate
此類顯示的是年月日(默認(rèn)的格式為:2017-01-01)
用法與LocalDateTime類大致一樣
3. java.time.LocalTime
此類顯示的是時(shí)分秒和毫秒值的后三位(21:26:35.693)
用法與LocalDateTime類大致一樣
3. java.time.Instant
此類功能和java.util.Date類類似
Instant now = Instant.now();
System.out.println(now.toEpochMilli());//獲取當(dāng)前時(shí)間的毫秒值
System.out.println(now.isAfter(now)); //當(dāng)前時(shí)間是否在參數(shù)中的時(shí)間之后
System.out.println(now.isBefore(now));//當(dāng)前時(shí)間是否在參數(shù)中的時(shí)間之前
//當(dāng)前時(shí)間與參數(shù)中的時(shí)間進(jìn)行對(duì)比,在參數(shù)的時(shí)間之前,相同,之后的值分別是(-1,0,1)
System.out.println(now.compareTo(now));
//用一個(gè)時(shí)間戳去創(chuàng)建一個(gè)Instance實(shí)例,用法和new Date(時(shí)間戳)創(chuàng)建一個(gè)Date實(shí)例是一樣的
Instant ofEpochMilli = Instant.ofEpochMilli(System.currentTimeMillis());
System.out.println(now.getEpochSecond());//獲取當(dāng)前時(shí)間的秒
4.java.time.Instant和java.time.LocalDateTime互轉(zhuǎn)
4.1 Instance轉(zhuǎn)LocalDateTime
Instant instant = Instant.ofEpochMilli(System.currentTimeMillis());
ZoneId systemDefault = ZoneId.systemDefault();
LocalDateTime now = LocalDateTime.ofInstant(instant, systemDefault);
System.out.println(now); //2017-03-22T13:44:34.979
4.2 LocalDateTime轉(zhuǎn)Instance
LocalDateTime now = LocalDateTime.now();
ZoneId systemDefault = ZoneId.systemDefault();
Instant instant = now.atZone(systemDefault).toInstant();
System.out.println(instant.toEpochMilli()); //1490163685578
4. java.time.Duration
此類用來(lái)計(jì)算兩同類型日期的時(shí)間差,看演示:
LocalDateTime start = LocalDateTime.of(2017, 1, 1, 1, 1);
LocalDateTime end = LocalDateTime.of(2017, 2, 1, 1, 1);
Duration result = Duration.between(start, end);
System.out.println(result.toDays()); //31
System.out.println(result.toHours()); //744
System.out.println(result.toMinutes()); //44640
System.out.println(result.toMillis()); //2678400000
System.out.println(result.toNanos()); //2678400000000000
其中between方法計(jì)算兩日期時(shí)間差,兩參數(shù)都是Temporal接口類型的日期,來(lái)看看Temporal的實(shí)現(xiàn)類:
HijrahDate, Instant, JapaneseDate, LocalDate, LocalDateTime, LocalTime, MinguoDate, OffsetDateTime, OffsetTime, ThaiBuddhistDate, Year, YearMonth, ZonedDateTime
java.util.Date或java.util.Calendar到新庫(kù)類的轉(zhuǎn)換
轉(zhuǎn)換可通過(guò)下面的方法進(jìn)行吨枉。
Date.toInstant()
Date.from(Instant)
Calendar.toInstant()
JDBC
最新JDBC映射將把數(shù)據(jù)庫(kù)的日期類型和Java 8的新類型關(guān)聯(lián)起來(lái):
date -> LocalDate
time -> LocalTime
timestamp -> LocalDateTime