Java8 日期、時間騷操作

在Java8之前,日期時間API一直被開發者詬病,包括:java.util.Date是可變類型,SimpleDateFormat非線程安全等問題。故此,Java8引入了一套全新的日期時間處理API,新的API基於ISO標準日曆系統。

常用的API類如下:

LocalDate       //只包含日期,比如:2018-09-24
LocalTime       //只包含時間,比如:10:32:10
LocalDateTime   //包含日期和時間,比如:2018-09-24 10:32:10
java.time.format.DateTimeFormatter      //時間格式化類
Instant         //時間戳
Peroid          //時間段
Duration        //持續時間、時間差
ZoneOffset      //時區偏移量,比如:+8:00
ZonedDateTime   //帶時區的日期時間
Clock           //時鐘,可用於獲取當前時間戳

LocalDate和LocalTime

從類名就可以看出,LocalDate是表示年月日,而LocalTime是表示時分秒

LocalDate

LocalDate 一般使用場景如下:

LocalDate date = LocalDate.of(2019,6,20);
int year = date.getYear();  //2019
Month month = date.getMonth(); // NOVEMBER
int mon = date.getMonthValue();//6
int dayOfMonth = date.getDayOfMonth(); //20
DayOfWeek dayOfWeek = date.getDayOfWeek();  //SUNDAY
int i = date.lengthOfMonth();   //30
boolean leapYear = date.isLeapYear();  //false
//獲取現在時間
LocalDate now = LocalDate.now();  //2019-06-20
boolean dateEqual =  now.equals(LocalDate.of(year,mon,dayOfMonth));//true

除了getxxx方法,還可以使用TemporalField參數給get方法獲取相同的信息(ChronoField是TemporalField的實現)

//獲取現在時間
LocalDate now = LocalDate.now();  //2019-06-20

int year = now.get(ChronoField.YEAR); //2019
int month = now.get(ChronoField.MONTH_OF_YEAR);//6
int dayOfMonth = now.get(ChronoField.DAY_OF_MONTH);//20
int dayOfWeek = now.get(ChronoField.DAY_OF_WEEK);//4

LocalTime

LocalTime now = LocalTime.now();//14:37:26.142
LocalTime time = LocalTime.of(18,18,18);//18:18:18.0
int hour = time.getHour();  //18
int minute = time.getMinute();  //18
int second = time.getSecond();  //18
int nano = time.getNano();  //0

LocalDateTime

LocalDateTime類,結合了上面兩個類,可以同時表示年月日和時分秒

//LocalDateTime基本使用
LocalDateTime localDateTime = LocalDateTime.of(2019,6,20,18,18,18);
//創建LocalDate對象
LocalDate localDate = LocalDate.now();
//調用atTime可以傳入具體時分秒,構成LocalDateTime
LocalDateTime time1 = localDate.atTime(18, 18,18);
//創建LocalTime對象
LocalTime localTime = LocalTime.now();
//調用atDate,傳入具體年月日對象,構成LocalDateTime
LocalDateTime localDateTime1 = localTime.atDate(localDate);
localDateTime.equals(time1); //true

//從LocalDateTime中可以獲取LocalDate和LocalTim
LocalDate date = localDateTime.toLocalDate();
LocalTime time = localDateTime.toLocalTime();

int year = localDateTime.get(ChronoField.YEAR); //localDateTime.getYear() 2019
int month = localDateTime.get(ChronoField.MONTH_OF_YEAR);//localDateTime.getMonthValue() 6
int dayOfMonth = localDateTime.get(ChronoField.DAY_OF_MONTH);//localDateTime.getDayOfMonth() 20
int hour = localDateTime.getHour();  //18
int minute = localDateTime.getMinute();  //18
int second = localDateTime.getSecond();  //18
int nano = localDateTime.getNano();  //0

日期解析與格式化

java.time.format包就是解析日期格式化日期的,最重要的是DateTimeFormatter類,支持以下標記佔位符。

 * <pre>
 *  Symbol  Meaning                     Presentation      Examples
 *  ------  -------                     ------------      -------
 *   G       era                         text              AD; Anno Domini; A
 *   u       year                        year              2004; 04
 *   y       year-of-era                 year              2004; 04
 *   D       day-of-year                 number            189
 *   M/L     month-of-year               number/text       7; 07; Jul; July; J
 *   d       day-of-month                number            10
 *
 *   Q/q     quarter-of-year             number/text       3; 03; Q3; 3rd quarter
 *   Y       week-based-year             year              1996; 96
 *   w       week-of-week-based-year     number            27
 *   W       week-of-month               number            4
 *   E       day-of-week                 text              Tue; Tuesday; T
 *   e/c     localized day-of-week       number/text       2; 02; Tue; Tuesday; T
 *   F       week-of-month               number            3
 *
 *   a       am-pm-of-day                text              PM
 *   h       clock-hour-of-am-pm (1-12)  number            12
 *   K       hour-of-am-pm (0-11)        number            0
 *   k       clock-hour-of-am-pm (1-24)  number            0
 *
 *   H       hour-of-day (0-23)          number            0
 *   m       minute-of-hour              number            30
 *   s       second-of-minute            number            55
 *   S       fraction-of-second          fraction          978
 *   A       milli-of-day                number            1234
 *   n       nano-of-second              number            987654321
 *   N       nano-of-day                 number            1234000000
 *
 *   V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
 *   z       time-zone name              zone-name         Pacific Standard Time; PST
 *   O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00;
 *   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
 *   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
 *   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;
 *
 *   p       pad next                    pad modifier      1
 *
 *   '       escape for text             delimiter
 *   ''      single quote                literal           '
 *   [       optional section start
 *   ]       optional section end
 *   #       reserved for future use
 *   {       reserved for future use
 *   }       reserved for future use
 * </pre>

他有一些預定義常量

LocalDateTime localDateTime = LocalDateTime.of(2019,6,20,18,18,18,999);
String format = localDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);//2019-06-20T18:18:18.000000999
String format1 = localDateTime.format(DateTimeFormatter.ISO_DATE_TIME);//2019-06-20T18:18:18.000000999
String format2 = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSSSSSSSS"));//2019-06-20T18:18:18.000000999

LocalDateTime localDateTime1 = LocalDateTime.parse("2019-06-20T18:18:18");
LocalDateTime localDateTime2 = LocalDateTime.parse("2019-06-20 18:18:18",DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

當然也可以創建一個更加複雜的解析器

DateTimeFormatter builder = new DateTimeFormatterBuilder()
        .appendText(ChronoField.DAY_OF_MONTH)   //首先解析的是一個月的第幾天
        .appendLiteral("/")   //分隔符
        .appendText(ChronoField.MONTH_OF_YEAR)  //一年的第幾個月
        .appendLiteral(" ")   //分隔符
        .appendText(ChronoField.YEAR)  //年份
        .parseCaseInsensitive()  //開始解析,不區分大小寫
        .toFormatter(Locale.CHINA);  //按照哪個國家的方言開始解析
LocalDate date = LocalDate.of(2019, 6, 20);
String format = date.format(builder);// 20/六月 2019

時間調整

Java8提供了新的plusXxx()方法用於計算日期時間增量值,minusXxx()方法用於日期時間的減量值,withXxx()方法指定日期時間指標。

LocalDateTime localDateTime = LocalDateTime.of(2019,6,20,18,18,18);
//2020-03-28 18:06:18
LocalDateTime localDateTime1 
                = localDateTime.plusYears(1).minusMonths(3).plusDays(8).withHour(18).with(ChronoField.MINUTE_OF_HOUR,6);

TemporalAdjuster

當我們遇到複雜情況的時候,比如調整時間到下個週日之類的要求,我們就需要自定義一個TemporalAdjuster對象,更加靈活的處理日期
java8已經預定義好一些TemporalAdjuster了,可以通過工廠類訪問他們

LocalDateTime localDateTime = LocalDateTime.of(2019,6,20,18,18,18);
LocalDateTime localDateTime2 = localDateTime.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));//2019-06-23 18:18:18
LocalDateTime localDateTime3 = localDateTime.with(TemporalAdjusters.lastDayOfMonth());//2019-06-30 18:18:18

定製TemporalAdjuster

創建類實現TemporalAdjuster接口

/**
 * 需求:返回下一個工作日,如果日期在週一到週五之間,就返回下一天就好,如果是週五六日就需要返回下週一的日期
 */
public class NextWorkingDay implements TemporalAdjuster {
    @Override
    public Temporal adjustInto(Temporal temporal) {
        //得到參數中是這周的第幾天
        int day = temporal.get(ChronoField.DAY_OF_WEEK);
        //根據第幾天構造出DayOfWeek枚舉類,容易觀察,當然也可以不用構造
        //如果不夠再下面的判斷相等直接改成上面的day就行了
        DayOfWeek dayOfWeek = DayOfWeek.of(day);
        //需要在參數的基礎上增加幾天
        int dayNeedAdd = 1;
        //如果是週五,就需要推後三天才是週一
        if (dayOfWeek == DayOfWeek.FRIDAY){
            dayNeedAdd = 3;
        }
        //如果是週六,就需要推後兩天才是週一
        if (dayOfWeek == DayOfWeek.SATURDAY){
            dayNeedAdd = 2;
        }
        //如果是週日或者當天就是在週一到週五之間的,直接加一就可以,即返回下一天
        return temporal.plus(dayNeedAdd, ChronoUnit.DAYS);
    }
}

上面說此接口是函數式接口,當然就可以使用Lmabda傳入了,使用如下

LocalDate date = LocalDate.of(2018, 11, 25);//週日
LocalDate nextWorkDay = date.with(new NextWorkingDay());  //2018-11-26

使用lambda

LocalDate date = LocalDate.of(2018, 11, 25);//週日
LocalDate nextWorkDay = date.with(temporal -> {
    //具體實現是把上面的實現類NextWorkingDay內實現的方法體貼進來就行了
});

也可以這樣

LocalDate date = LocalDate.of(2018, 11, 25);//週日
TemporalAdjuster nextWorkDay = TemporalAdjusters.ofDateAdjuster(temporal -> {
    //具體實現是把上面的實現類NextWorkingDay內實現的方法體貼進來就行了
});
LocalDate date1 = date.with(nextWorkDay);

如上是一個靜態方法,傳入一個UnaryOperator函數式接口的實現即可,就能夠返回一個TemporalAdjuster對象,然後傳入with方法即可

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章