1. 程式人生 > 程式設計 >Java8的LocalDate LocalTime LocalDateTime家族

Java8的LocalDate LocalTime LocalDateTime家族

前言

最近做了很多統計方面的功能,基本是要和日期這個東西打交道,各種,前移多少天,前移幾個小時,前移幾分鐘的操作,雖然Java的Calendar這個日曆操作類能搞定,但是還是感覺寫起來有點費勁.果不其然,讓我發現了LocalDate LocalTime LocalDateTime這個JAVA8新增的時間類

介紹

java.util.Date和java.sql.Date是jdk1就開始提供了,java.sql.Date繼承了java.util.Date,我們和資料庫互動,一般是採用java.util.Date這個類,因為java.sql.Date的getHours,getMinutes,gitSeconds這三個方法都是這麼寫的:

    @Deprecated
    public int getHours() {
        throw new java.lang.IllegalArgumentException();
    }
    
    @Deprecated
    public int getMinutes() {
        throw new java.lang.IllegalArgumentException();
    }
    
     @Deprecated
    public int getSeconds() {
        throw new java.lang.IllegalArgumentException();
    }
    
    對應的set
XXXX方法也是如出一轍的丟擲IllegalArgumentException異常 例如: @Deprecated public void setHours(int i) { throw new java.lang.IllegalArgumentException(); } 並且還帶有@Deprecated(廢棄)這個註解,看來,java.sql.Date只能顯示到:年月日這個級別了,也就是:2019-11-22這種形式的資料 複製程式碼

LocalDate,LocalTime,LocalDateTime的介紹

LocalDate,LocalDateTIme這三個類是java8新提供的時間操作類,在java.time包下面.這三個類是從org.joda.time吸收過來的(地方武裝的工具類被提成標準部隊了).
1.LocalDate是主管:yyyy-MM-dd(2019-11-22)這種形式,也就是隻管:年-月-日
2.LocalTime是主管:HH:mm:ss (14:56:23)這種形式,也就是隻管:時:分:秒
3.LocalDateTime是主管:yyyy-MM-dd HH:mm:ss 這種形式,也就是隻管:年-月-日 時:分:秒(LocalDateTime是由LocalDate和LocalTime組成的)
複製程式碼

1.構造物件方法

LocalDate,LocaTime,LocalDateTime提供了基本上一致,有以下集中:
now()系列:
    //預設時區
    public static LocalDate now() {
        return now(Clock.systemDefaultZone());
    }
    //自定義時區,例如你可以通過ZoneId.of("America/New_York")使用紐約的時區
    public static LocalDate now(ZoneId zone) {
        return now(Clock.system(zone));
    }
    //自定義時鐘,這個有點高深,還沒使用過
    public static LocalDate now(Clock clock) {
        Objects.requireNonNull(clock,"clock");
        // inline to avoid creating object and Instant checks
        final Instant now = clock.instant();  // called once
        ZoneOffset offset = clock.getZone().getRules().getOffset(now);
        long epochSec = now.getEpochSecond() + offset.getTotalSeconds();  // overflow caught later
        long epochDay = Math.floorDiv(epochSec,SECONDS_PER_DAY);
        return LocalDate.ofEpochDay(epochDay);
    }

of系列:(這裡只列舉LocalDate的of)
    //根據年月日構造LocalDate物件,這個地方的dayOfMonth是1-31的取值
    public static LocalDate of(int year,Month month,int dayOfMonth) {
        YEAR.checkValidValue(year);
        Objects.requireNonNull(month,"month");
        DAY_OF_MONTH.checkValidValue(dayOfMonth);
        return create(year,month.getValue(),dayOfMonth);
    }
    //同上,只是都是使用int型別來傳遞引數了
    public static LocalDate of(int year,int month,int dayOfMonth) {
        YEAR.checkValidValue(year);
        MONTH_OF_YEAR.checkValidValue(month);
        DAY_OF_MONTH.checkValidValue(dayOfMonth);
        return create(year,month,dayOfMonth);
    }
    //這個是定位到一年當中的第幾天
    public static LocalDate ofYearDay(int year,int dayOfYear) {
        YEAR.checkValidValue(year);
        DAY_OF_YEAR.checkValidValue(dayOfYear);
        boolean leap = IsoChronology.INSTANCE.isLeapYear(year);
        if (dayOfYear == 366 && leap == false) {
            throw new DateTimeException("Invalid date 'DayOfYear 366' as '" + year + "' is not a leap year");
        }
        Month moy = Month.of((dayOfYear - 1) / 31 + 1);
        int monthEnd = moy.firstDayOfYear(leap) + moy.length(leap) - 1;
        if (dayOfYear > monthEnd) {
            moy = moy.plus(1);
        }
        int dom = dayOfYear - moy.firstDayOfYear(leap) + 1;
        return new LocalDate(year,moy.getValue(),dom);
    }
複製程式碼

2.具體的使用例子(這個才是上手的好東西)

獲取現在的時間物件:

//時間是:2019-11-22
LocaDate now = LocalDate.now();

//時間是:14:43:56
LocalTime now = LocalTime.now();

//時間是:2019-11-22 14:43:56
LocalDateTime now = LocalDateTime.now();
複製程式碼

使用of來具體定製時間

//時間是:2015-12-20
LocalDate localDate = LocalDate.of(2015,12,20);

//時間是:15:36:48
LocalTime localTime = LocalTime.of(15,36,48);

//時間是:2013-09-21 05:56:24
LocalDateTime localDateTime = LocalDateTime.of(2013,9,21,5,58,24);
複製程式碼

各種條件的定位時間

老鐵們一定要注意:凡是LocalDate各種操作之後,他都返回一個新的LocalDate物件,所以,你要接著這個新物件啊,你要是不用物件接著,那麼就會看到不起作用,這樣子好鏈式程式設計

我們在開發中可能遇到各種條件的定位時間:本月的第一天,本月的最後一天,本月每週的週一,本月每週的週三,本年度的第9月的第二天,或者哪一年的上述各種情況:

//我們隨便拿個時間做實驗,以求做到一般化處理,就拿2019-10-22日來處理吧
LocalDate localDate = LocalDate.of(2019,10,22);
//**老鐵們一定要注意:凡是LocalDate各種操作之後,他都返回一個新的LocalDate物件,所以,你要接著這個新物件啊,你要是不用物件接著,那麼就會看到不起作用,這樣子好鏈式程式設計**

//1.獲取本月的第一天,輸出:2019-10-01
localDate = localDate.with(TemporalAdjusters.firstDayOfMonth())

//2.獲取本月的最後一天,輸出:2019-10-31
localDate = localDate.with(TemporalAdjusters.lastDayOfMonth());

//3.本年第一天,輸出:2019-01-01
localDate = localDate.with(TemporalAdjusters.firstDayOfYear());

//4.本年最後一天,輸出:2019-12-31
localDate = localDate.with(TemporalAdjusters.lastDayOfYear());

//5.下一個周幾的操作,輸出:2019-10-24
//注意,2019-10-22是週二,所以下一個週四就是2019-10-24,如果是下一個週一,那就是:2019-10-28了
//當然也有對應的previes方法,就是上一個周幾
localDate = localDate.with(TemporalAdjusters.next(DayOfWeek.THURSDAY));
localDate = localDate.with(TemporalAdjusters.previes(DayOfWeek.THURSDAY));

//6.本月第2周的週五,輸出是:2019-10-11
localDate = localDate.with(TemporalAdjusters.dayOfWeekInMonth(2,DayOfWeek.FRIDAY));

//7.還有下一個月的第一天,輸出是:2019-11-01,當然還有下一年
localDate = localDate.with(TemporalAdjusters.firstDayOfNextMonth());

//8.加一天,輸出是:2019-10-23
localDate = localDate.plusDays(1L);

//9.加一週,輸出是:2019-10-29(即使是跨年和跨月,也會正確加的,不用擔心)
localDate = localDate.plusWeeks(1L);

//10.加一個月,輸出是:2019-11-22(下一月沒有31號這種情況,他們會幫我們處理的),例如:2019-10-31加一個月,返回:2019-11-30(放心,JDK都是進過各種驗證的,不會出現人不能理解的錯誤的)
localDate = localDate.plusMonths(1L);
複製程式碼

同理,LocalTime和LocalDateTime也可以按照上面的方法來加減小時,分鐘,秒等操作

3.時間的比較

這個之前比較時間都是getTime然後比較一下就行,現在LocalDate,LocalDateTime提供了isBefore,isAfter方法

LocalDate first = LocalDate.now();
LocalDate second = LocalDate.of(2015,25);
first.isBefore(second);//返回:false
first.isAfter(second);//返回:true
複製程式碼

4.日期的字串格式化

我們避免不了經常需要格式化日期字串,這方面Local系列做的也很好

//輸出為:2019-10-22
localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
不用像之前還要一個SimpleDateFormatter了
複製程式碼

5.扯到最後,有點不適應,就是java.util.Date和LocalDate,LocalDateTime沒有直接互轉的方法,沒辦法,自己補充一個了

    //java.util.Date型別轉LocalDateTime
    public static LocalDateTime dateToLocalDateTime(Date date) {
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        return instant.atZone(zoneId).toLocalDateTime();
    }
    
    //java.time.LocalDateTime轉java.util.Date
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        return Date.from(zdt.toInstant());
    }
    
    有了LocalDateTime,你就可以操作獲取LocalDate,LocalTime了,當然也有轉Date<-->LocalDate  Date<-->LocalTime的操作,
    在這個地方就不一一列舉了!,其實就是instant.atZone(zoneId).toLocalDateTime()修改這句話就行
複製程式碼

6.貼出來我操作的一個例子

        String sqlFormat = "drop table gsms_phone_detection_0101";

        LocalDate startDate = LocalDate.of(2012,1,1);
        LocalDate endDate = LocalDate.of(2012,31);
        List<String> result = Stream.iterate(startDate,localDate -> localDate.plusDays(1L))
                .limit(ChronoUnit.DAYS.between(startDate,endDate) + 1)
                .map(localDate -> localDate.format(DateTimeFormatter.ofPattern("MMdd")))
                .map(tableSuffix -> sqlFormat.replaceAll("0101",tableSuffix))
                .collect(Collectors.toList());
        Files.write(Paths.get("/home/liuxu/Pictures/gsms_ded_red_det_verify_xxxx.sql"),result);
        
        這是我生成刪除按照日分表的sql語句,(不會寫儲存過程或者函式,也沒有功夫探索了)
複製程式碼