深入了解Java 8 新特性-日期時間API之LocalDate類
LocalDate
Java 8的LocalDate類是Java日期和時間API的一部分,沒有時間和時區(qū)的概念,是線程安全的,用于表示不包含時間的日期,位于java.time包下。
核心方法
now()
按系統(tǒng)默認(rèn)的時區(qū)來獲取當(dāng)前日期,返回代表當(dāng)前日期的 LocalDate 實(shí)例。
@Test
public void test() {
LocalDate now = LocalDate.now();//當(dāng)前日期
String format = now.format(DateTimeFormatter.ISO_DATE);
System.out.println(format);//輸出結(jié)果:2023-11-23 }
of(...)
接受一個年份(int)和兩個日期(int)作為參數(shù),返回一個表示該年某一天的 LocalDate 實(shí)例。日期的第一個參數(shù)范圍是1到31,第二個參數(shù)范圍是0到23。
public void test2() {
LocalDate localDate = LocalDate.of(2023, 2, 1);//定義一個日期:2023-02-01
LocalDate localDate1 = LocalDate.of(2023, Month.FEBRUARY, 1);//定義一個日期:2023-02-01
boolean equals = localDate1.equals(localDate);
System.out.println(equals);//輸出結(jié)果:true
}
ofEpochDay(...)
用于將給定的Unix時間戳(自1970年1月1日以來的天數(shù))轉(zhuǎn)換為 LocalDate 對象。這個方法返回一個表示該日期的 LocalDate 實(shí)例
@Test
public void test3() {
LocalDate localDate2 = LocalDate.ofEpochDay(1);// 假設(shè)給定的Unix時間戳為1天
String format = localDate2.format(DateTimeFormatter.ISO_DATE);
System.out.println(format);//輸出結(jié)果:1970-01-02
}
ofInstant(...)
Instant 是 Java 中的一個時間類,表示一個瞬時的時間點(diǎn),精確到納秒。Instant.ofEpochSecond()用于根據(jù)秒數(shù)(從1970年1月1日00:00:00 UTC開始)創(chuàng)建一個新的 Instant 對象。LocalDate.ofInstant() 可以將給定的 Instant 對象轉(zhuǎn)換為 LocalDate 對象。
@Test
public void test4() {
Long seconds = 24 * 60 * 60L;//一天的秒數(shù)
LocalDate localDate = LocalDate.ofInstant(Instant.ofEpochSecond(seconds), ZoneId.systemDefault());
String format = localDate.format(DateTimeFormatter.ISO_DATE);
System.out.println(format);//輸出結(jié)果:1970-01-02
}
ofYearDay(...)
LocalDate.ofYearDay() 用于創(chuàng)建一個表示某一年中特定天數(shù)的 LocalDate 對象。方法接受兩個參數(shù):年份和一年中的天數(shù)。年份表示自1970年以來的年數(shù),天數(shù)表示一年中的第幾天。例如,1月1日是第1天,2月15日是第46天。需要注意的是,這個方法并不會對輸入的天數(shù)進(jìn)行有效性檢查,因此如果輸入的天數(shù)超出了給定年份的范圍(例如,在2月輸入了30),那么創(chuàng)建出來的 LocalDate 對象可能不準(zhǔn)確。
@Test
public void test5() {
LocalDate localDate = LocalDate.ofYearDay(2023, 2);
String format = localDate.format(DateTimeFormatter.ISO_DATE);
System.out.println(format);//輸出結(jié)果:2023-01-02
}
get(...)
LocalDate.get(...) 可以獲取給定日期的特定部分,如年份、月份或日期。具體來說,如果你調(diào)用 LocalDate.get(ChronoField),其中 ChronoField 是 java.time.temporal.ChronoField 的實(shí)例,那么就會返回該日期對應(yīng)的特定部分。ChronoField 是一個枚舉類型,包含如 YEAR、MONTH_OF_YEAR、DAY_OF_MONTH 等各種表示時間的字段。
@Test
public void test6() {
LocalDate localDate = LocalDate.now();
int year = localDate.get(ChronoField.YEAR);//得到年份
int month = localDate.get(ChronoField.MONTH_OF_YEAR);//得到月份
int day = localDate.get(ChronoField.DAY_OF_MONTH);//得到當(dāng)月中第幾天
int weekOfMonth = localDate.get(ChronoField.ALIGNED_WEEK_OF_MONTH);//得到當(dāng)月的第幾周
System.out.println("year:"+year+",month:"+month+",day:"+day+",weekOfMonth:"+weekOfMonth);
}
getYear()、getMonthValue() 、getDayOfMonth()、getDayOfWeek()、getDayOfYear()
- getYear(): 獲取該日期的年份部分。例如,對于日期 "2023-06-24",該方法將返回2023。
- getMonthValue(): 獲取該日期的月份部分。例如,對于日期 "2023-06-24",該方法將返回6。
- getDayOfMonth(): 獲取該日期中的月份中的日期部分。例如,對于日期 "2023-06-24",該方法將返回24。
- getDayOfWeek(): 獲取該日期是星期幾的信息。該方法將返回一個枚舉類型的值,如MONDAY、TUESDAY等。
- getDayOfYear(): 獲取該日期是當(dāng)年的第幾天。例如,對于日期 "2023-06-24",該方法將返回175。
@Test
public void test13() {
LocalDate d1 = LocalDate.of(2023, 11, 23);
int year = d1.getYear();//年份:023
int monthValue = d1.getMonthValue();//月份:11
int dayOfMonth = d1.getDayOfMonth();//當(dāng)月第幾天:23
int dayOfWeek = d1.getDayOfWeek().getValue();//當(dāng)前周第幾天:4
int dayOfYear = d1.getDayOfYear();//當(dāng)前年第幾天:327
}
parse(...)
LocalDate的parse()用于從字符串值創(chuàng)建LocalDate的實(shí)例。這個方法需要一個參數(shù),即要解析的字符串。該字符串不能為空。此方法返回的是從作為參數(shù)傳遞的字符串值獲得的LocalDate實(shí)例。
@Test
public void test7() {
LocalDate parse = LocalDate.parse("2023-11-23", DateTimeFormatter.ISO_DATE);
LocalDate parse1 = LocalDate.parse("2023-11-23");
System.out.println(parse1.equals(parse));//輸出結(jié)果:true
}
format(...)
LocalDate的format()方法的功能是將日期進(jìn)行格式化,使用指定的格式化程序。具體來說,這個方法接受一個DateTimeFormatter對象作為參數(shù),這個對象定義了一個日期時間的格式。然后,這個方法會返回一個字符串,該字符串表示按照指定格式化程序格式化的日期。例如,如果我們有一個LocalDate對象代表著2019年5月8日的日期,我們可以使用format方法將它格式化為"MMM dd, yyyy"的格式,即"May 08, 2019"。
@Test
public void test8() {
LocalDate now = LocalDate.now();
String format = now.format(DateTimeFormatter.ISO_DATE);
String format1 = now.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
System.out.println(format);//輸出結(jié)果:2023-11-23
System.out.println(format1);//輸出結(jié)果:2023/11/23
}
atTime(...)
LocalDate.atTime(hour, minute)的功能是將給定的日期與特定時間進(jìn)行組合,生成一個LocalDateTime對象。具體來說,這個方法可以將日期部分和時間部分進(jìn)行組合。例如,如果你有一個LocalDate對象表示今天的日期,并且你想在下午3點(diǎn)鐘添加30分鐘的時間,你可以使用atTime方法來實(shí)現(xiàn)這個功能。
@Test
public void test9(){
LocalDate now = LocalDate.now();
LocalDateTime localDateTime = now.atTime(13, 30,59);
String format = localDateTime.format(DateTimeFormatter.ISO_DATE_TIME);
System.out.println(format);//輸出結(jié)果:2023-11-23T13:30:59
}
compareTo(...)
LocalDate.compareTo() 用于比較兩個日期對象。具體來說,這個方法將此日期與另一個日期進(jìn)行比較。如果此日期在時間上大于、等于或小于指定日期,則分別返回正整數(shù)、零或負(fù)整數(shù)。
@Test
public void test10() {
LocalDate t1 = LocalDate.of(2023, 2, 1);//定義一個日期:2023-02-01
LocalDate t2 = LocalDate.of(2023, Month.FEBRUARY, 2);//定義一個日期:2023-02-02
int i = t2.compareTo(t1);//如果t2>t1,,返回正數(shù);如果t2=t1,返回0;如果t2<t1,返回負(fù)數(shù);System.out.println(i);//
}
datesUntil(...)
LocalDate.datesUntil(...) 用于計(jì)算從當(dāng)前日期到指定日期之間的日期范圍。該方法返回一個表示該日期范圍的流(Stream)。具體來說,datesUntil(LocalDate endExclusive) 重載形式接受一個終止日期參數(shù),并返回從調(diào)用 datesUntil() 方法的 LocalDate 對象(起始日期)到終止日期之前的所有日期的流。
@Test
public void test11() {
LocalDate d1 = LocalDate.of(2023, 2, 26);
LocalDate d2 = LocalDate.of(2023, 3, 26);
Stream<LocalDate> stream = d1.datesUntil(d2);
stream.forEach(System.out::println);//注意:輸出結(jié)果不包含結(jié)束日期
Stream<LocalDate> stream1 = d1.datesUntil(d2, Period.ofDays(5));//輸出的日期之間的間隔是5天
stream1.forEach(System.out::println);
}
from(...)
LocalDate.from(...) 用于從給定的 TemporalAccessor 對象創(chuàng)建 LocalDate 的實(shí)例。TemporalAccessor 是Java時間日期API中的一個接口,它提供了對日期和時間信息的訪問權(quán)限,LocalDate、LocalDateTime等都實(shí)現(xiàn)了該接口;
@Test
public void test12(){
LocalDateTime nowTime = LocalDateTime.now();
LocalDate from = LocalDate.from(nowTime);
String format = from.format(DateTimeFormatter.ISO_DATE);
System.out.println(format);
}
isAfter(...)、isBefore(...)
LocalDate類的isAfter()和isBefore()方法分別用于檢查一個日期是否在另一個日期之后或之前。
具體來說:
- isAfter(ChronoLocalDate other): 此方法檢查此日期是否在給定日期之后。如果當(dāng)前日期在給定日期之后,它將返回true,否則返回false。
- isBefore(ChronoLocalDate other): 此方法檢查此日期是否在給定日期之前。如果當(dāng)前日期在給定日期之前,它將返回true,否則返回false。
@Test
public void test14() {
LocalDate d1 = LocalDate.of(2023, 11, 23);
LocalDate d2 = LocalDate.of(2023, 11, 24);
boolean after = d1.isAfter(d2);
System.out.println(after);//輸出結(jié)果:false
boolean before = d1.isBefore(d2);
System.out.println(before);//輸出結(jié)果:true
}
isLeapYear()
LocalDate.isLeapYear() 用于判斷給定的年份是否為閏年。閏年的判斷規(guī)則是這樣的:如果年份能被4整除但不能被100整除,或者能被400整除,那么這個年份就是閏年。
@Test
public void test15() {
LocalDate d1 = LocalDate.of(2020, 11, 23);
LocalDate d2 = LocalDate.of(2023, 11, 24);
boolean after = d1.isLeapYear();
System.out.println(after);//輸出結(jié)果:true
boolean before = d2.isLeapYear();
System.out.println(before);//輸出結(jié)果:false
}
lengthOfMonth()、lengthOfYear()
LocalDate的lengthOfMonth()方法用于獲取此LocalDate表示的月份的長度,即該月份的天數(shù)。而lengthOfYear()方法則用于獲取此LocalDate表示的年份的長度,即該年份的總天數(shù)。這兩個方法都是用于計(jì)算日期時間的長度,方便進(jìn)行日期的計(jì)算和比較。
@Test
public void test16() {
LocalDate d1 = LocalDate.of(2020, 2, 23);
int i = d1.lengthOfYear();
System.out.println(i);//輸出結(jié)果:366
int j = d1.lengthOfMonth();
System.out.println(j);//輸出結(jié)果:29
}
minus(...)、minusDays(...)、minusMonths(...)、minusWeeks(...)、minusYears(...)
這些方法都是Java中LocalDate類的方法,用于進(jìn)行日期減法操作,返回一個新的LocalDate對象,表示減去指定時間間隔后的日期。
- minus(...):此方法用于減去給定的時間間隔。它接受一個TemporalAmount參數(shù),可以是時間單位(如小時,分鐘,天,月,年等)。
- minusDays(int n):此方法用于減去給定數(shù)量的天數(shù)。參數(shù)n是一個整數(shù),表示要減去的天數(shù)。
- minusMonths(int n):此方法用于減去給定數(shù)量的月份。參數(shù)n是一個整數(shù),表示要減去的月份數(shù)。
- minusWeeks(int n):此方法用于減去給定數(shù)量的周數(shù)。參數(shù)n是一個整數(shù),表示要減去的周數(shù)。
- minusYears(int n):此方法用于減去給定數(shù)量的年數(shù)。參數(shù)n是一個整數(shù),表示要減去的年數(shù)。
@Test
public void test17() {
LocalDate d1 = LocalDate.of(2023, 11, 23);
LocalDate minus = d1.minus(Period.ofDays(3));//當(dāng)前日期+3天
String format = minus.format(DateTimeFormatter.ISO_DATE);
System.out.println(format);//輸出結(jié)果:2023-11-20
LocalDate minus2 = d1.minusDays(3);//當(dāng)前日期減去3天
String format2 = minus2.format(DateTimeFormatter.ISO_DATE);
System.out.println(format2);//輸出結(jié)果:2023-11-20
LocalDate minus3 = d1.minusMonths(1);//當(dāng)前日期減去1月
String format3 = minus3.format(DateTimeFormatter.ISO_DATE);
System.out.println(format3);//輸出結(jié)果:2023-10-23
LocalDate minus4 = d1.minusWeeks(1);//當(dāng)前日期減去1周
String format4 = minus4.format(DateTimeFormatter.ISO_DATE);
System.out.println(format4);//輸出結(jié)果:2023-11-16
LocalDate minus5 = d1.minusYears(1);//當(dāng)前日期減去1年
String format5 = minus5.format(DateTimeFormatter.ISO_DATE);
System.out.println(format5);//輸出結(jié)果:2022-11-23
}
plus(...)、plusDays(...)、plusMonths(...)、plusWeeks(...)、plusYears(...)
LocalDate類的plus(...)方法是一個通用方法,用于在給定時間單位上增加日期。具體的單位可以通過傳遞一個ChronoUnit對象來指定,例如plusDays(int days)、plusMonths(int months)、plusWeeks(int weeks)、plusYears(int years)等。
這些方法用于增加LocalDate對象的日期。例如:
- plusDays(int days):增加給定天數(shù)。
- plusMonths(int months):增加給定月數(shù)。
- plusWeeks(int weeks):增加給定周數(shù)。
- plusYears(int years):增加給定年數(shù)。
需要注意的是,這些方法返回的是一個新的LocalDate對象,而不是修改原有的對象。因此,需要將結(jié)果賦值給一個變量來使用增加后的日期。
@Test
public void test17() {
LocalDate d1 = LocalDate.of(2023, 11, 23);
LocalDate plus = d1.plus(Period.ofDays(3));//當(dāng)前日期+3天
String format = plus.format(DateTimeFormatter.ISO_DATE);
System.out.println(format);//輸出結(jié)果:2023-11-26
LocalDate plus2 = d1.plusDays(3);//當(dāng)前日期+3天
String format2 = plus2.format(DateTimeFormatter.ISO_DATE);
System.out.println(format2);//輸出結(jié)果:2023-11-26
LocalDate plus3 = d1.plusMonths(1);//當(dāng)前日期+1月
String format3 = plus3.format(DateTimeFormatter.ISO_DATE);
System.out.println(format3);//輸出結(jié)果:2023-12-23
LocalDate plus4 = d1.plusWeeks(1);//當(dāng)前日期+1周
String format4 = plus4.format(DateTimeFormatter.ISO_DATE);
System.out.println(format4);//輸出結(jié)果:2023-11-30
LocalDate plus5 = d1.plusYears(1);//當(dāng)前日期+1年
String format5 = plus5.format(DateTimeFormatter.ISO_DATE);
System.out.println(format5);//輸出結(jié)果:2024-11-23
}
toEpochDay()、toEpochSecond(...)
LocalDate.toEpochDay()的功能是將LocalDate對象轉(zhuǎn)換為自1970年1月1日以來的天數(shù)。這個方法返回的是一個長整型(long)的值,它將此本地日期與指定的時間和作為參數(shù)傳遞的偏移量相結(jié)合,以計(jì)算epoch-second值,該值是從1970-01-01T00:00:00Z開始經(jīng)過的秒數(shù)。
LocalDate.toEpochSecond(LocalTime time, ZoneOffset offset)的功能是將此本地日期與指定的時間和作為參數(shù)傳遞的偏移量相結(jié)合,以計(jì)算epoch-second值。這個方法接受兩個參數(shù),time和offset,它們是本地時間和區(qū)域偏移。該方法返回一個長整型(long)的值,表示自1970-01-01T00:00:00Z以來的秒數(shù)。
@Test
public void test19() {
LocalDate d1 = LocalDate.of(2023, 11, 23);
long epochDay = d1.toEpochDay();//自1970-01-01年到當(dāng)前日期的天數(shù)
System.out.println(epochDay);
long epochSecond = d1.toEpochSecond(LocalTime.now(), ZoneOffset.ofHours(8));//自1970-01-01到當(dāng)前日期的秒數(shù);中國位于東8區(qū),區(qū)域偏移量為+8
LocalDate localDate = LocalDate.ofInstant(Instant.ofEpochSecond(epochSecond), ZoneId.systemDefault());//把得到秒數(shù)再轉(zhuǎn)換為locaDate
System.out.println(localDate.equals(d1));//輸出結(jié)果為true
}
with(...)
LocalDate.with(...)參數(shù)是一個 TemporalAdjuster,那么 with 方法會使用傳遞的調(diào)整器作為參數(shù)來調(diào)整此日期時間,并在調(diào)整后,返回調(diào)整后的日期時間的副本。
TemporalAdjuster是一個Java 8中引入的日期時間API,用于執(zhí)行復(fù)雜的日期操作。它是一個函數(shù)式接口,可以在Temporal對象上執(zhí)行操作,例如獲得下一個星期日、當(dāng)月的最后一天或下一年的第一天。
TemporalAdjuster有幾個預(yù)定義的實(shí)現(xiàn)類,包括LocalDate、LocalDateTime和TemporalAdjuster接口本身。這些實(shí)現(xiàn)類可以用于調(diào)整Temporal對象的日期和時間。
使用TemporalAdjuster可以非常方便地執(zhí)行各種日期操作,例如:
獲取下一個星期日的日期。
獲取當(dāng)月的最后一天的日期。
獲取下一年的第一天的日期。
獲取某個日期之后的第N天、第N個星期或第N個月之后的日期。
獲取某個日期和時間之后的下一個工作日、下一個周末或下一個公眾假日。
@Test
public void test20() {
UnaryOperator<LocalDate> unaryOperator = item -> item.minusDays(1);//日期調(diào)節(jié)邏輯:減去1天
TemporalAdjuster temporalAdjuster = TemporalAdjusters.ofDateAdjuster(unaryOperator);//構(gòu)造日期調(diào)節(jié)器類
LocalDate localDate1 = LocalDate.of(2023, 11, 22);//日期:2023-11-22
LocalDate localDate2 = localDate1.with(temporalAdjuster);//執(zhí)行調(diào)節(jié)邏輯,并返回調(diào)節(jié)后結(jié)果
String dateStr2 = localDate2.format(DateTimeFormatter.ISO_DATE);
System.out.println(dateStr2);//輸出結(jié)果:2023-11-21
}
withDayOfMonth(...)、withDayOfYear(...)
LocalDate類中的withDayOfMonth(...)和withDayOfYear(...)方法用于調(diào)整日期的天數(shù)。
withDayOfMonth(int dayOfMonth)方法接受一個整數(shù)參數(shù),表示月份中的某一天。該方法將此日期調(diào)整為給定日期的月份中的指定天數(shù),并返回一個新的日期對象。例如,如果當(dāng)前日期是2023年3月10日,調(diào)用withDayOfMonth(15)將返回一個新的日期對象,表示2023年3月15日。
withDayOfYear(int dayOfYear)方法接受一個整數(shù)參數(shù),表示一年中的某一天。該方法將此日期調(diào)整為給定年份中的指定天數(shù),并返回一個新的日期對象。例如,如果當(dāng)前日期是2023年3月10日,調(diào)用withDayOfYear(150)將返回一個新的日期對象,表示2023年7月10日(因?yàn)?月有31天,所以150減去3月的剩余天數(shù))。
這兩個方法都返回一個新的日期對象,不會修改原始的LocalDate對象。這些方法可以用于執(zhí)行各種日期調(diào)整操作,例如計(jì)算下個月的第一天或上個月的最后一天等。
@Test
public void test21() {
LocalDate d1 = LocalDate.of(2023, 11, 22);//日期:2023-11-22
LocalDate d2 = d1.withDayOfMonth(1);
String format = d2.format(DateTimeFormatter.ISO_DATE);
System.out.println(format);//輸出結(jié)果:2023-11-01
LocalDate localDate3 = d1.withDayOfYear(1);
String format2 = localDate3.format(DateTimeFormatter.ISO_DATE);
System.out.println(format2);//輸出結(jié)果:2023-01-01
}
atStartOfDay()
LocalDate.atStartOfDay() 返回一個 LocalDateTime 實(shí)例,該實(shí)例表示給定日期的午夜時分。具體來說,它會把日期部分設(shè)為當(dāng)前日期的開始時間(24小時制),時間部分設(shè)為 00:00:00。例如,如果今天是2023年6月24日,那么 LocalDate.now().atStartOfDay() 將返回一個表示2023年6月24日00:00:00的 LocalDateTime 對象。
@Test
public void test22() {
LocalDate d= LocalDate.of(2023, 11, 22);
LocalDateTime localDateTime = d.atStartOfDay();
String format = localDateTime.format(DateTimeFormatter.ISO_DATE_TIME);
System.out.println(format);//輸出結(jié)果:2023-11-22T00:00:00
}
適用場景
- 日期處理:LocalDate類適用于只需要處理日期的場景,而不考慮時間部分。例如,記錄生日、紀(jì)念日、賬單日等。
- 日期計(jì)算:可以使用LocalDate類進(jìn)行日期的加減運(yùn)算,例如計(jì)算兩個日期之間的天數(shù)、月數(shù)或年數(shù)。
- 日期格式化:可以使用LocalDate類和DateTimeFormatter類進(jìn)行日期的格式化操作,將日期轉(zhuǎn)換為指定的字符串格式。
- 日期時間轉(zhuǎn)換:可以將帶有時間的日期轉(zhuǎn)換為不帶時間的LocalDate對象,或者將LocalDate對象轉(zhuǎn)換為帶有時間的日期時間對象(如LocalDateTime)。