java程式碼之美(17) —Java8 LocalDateTime

Java8 LocalDateTime

在java8之前我們在處理時間的時候都是用的Date,但它其實有很明顯的缺點。

1.我們也會對日期做一些操作,比如加幾天、加幾分,當月的最後一天等等。有些計算實現比較複雜。
2.也會用SimpleDateFormat來格式化日期。但SimpleDateFormat是執行緒不安全的。

所以現在一般都推薦使用LocalDateTime 它是執行緒安全的,並且性能更好,程式碼更簡潔。

一、示例

新時間日期API常用、重要對象主要有下面三個:

LocalDate : 只含年月日的日期對象
LocalTime :只含時分秒的時間對象
LocalDateTime : 同時含有年月日時分秒的日期對象

下面會通過示例來一一理解它們。

1、創建實例

    public static void main(String[] args) {
        //1、獲取當前日期
        LocalDate now = LocalDate.now();
        System.out.println("當前時間 = " + now);
        //輸出: 當前時間 = 2020-07-06

        //2、獲取指定日期(參數依次 年、月、日)
        LocalDate localDate = LocalDate.of(2020, 6, 30);
        System.out.println("年月日 = " + localDate);
        //輸出: 年月日 = 2020-06-30

        //3、獲取當前時間
        LocalTime localTime = LocalTime.now();
        System.out.println("localTime = " + localTime);
        //輸出: localTime = 22:32:45.994

        //4、獲取指定時間(參數依次 時、分、秒、納秒
        LocalTime localTimeOf = LocalTime.of(12, 24, 12, 4444);
        System.out.println("localTimeOf = " + localTimeOf);
        //輸出: localTimeOf = 12:24:12.000004444

        //5、獲取當前年月日,時分秒都有的日期
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println("localDateTime = " + localDateTime);
        //輸出: localDateTime = 2020-07-06T22:32:45.994

        //6、獲取指定年月日,時分秒都有的日期(參數依次 年、月、日、時、分)
        LocalDateTime localDateTimeOf = LocalDateTime.of(2020, 7, 30, 12, 12);
        System.out.println("localDateTimeOf = " + localDateTimeOf);
        //輸出: localDateTimeOf = 2020-07-30T12:12

         //7、日期+時間 組成 包含年月日,時分秒都有的日期
        LocalDateTime of = LocalDateTime.of(LocalDate.now(), LocalTime.now());
        System.out.println("of = " + of);
        //輸出: of = 2020-07-06T22:32:45.995
    }

2、計算日期和時間

日期時間的加減
  • 對於LocalDate,只有精度大於或等於日的加減,如年、月、日;
  • 對於LocalTime,只有精度小於或等於時的加減,如時、分、秒、納秒;
  • 對於LocalDateTime,則可以進行任意精度的時間相加減;

加法操作

public static void main(String[] args) {
            
        //獲取當前時間
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println("當前時間 = " + localDateTime);

        //1、加1年
        LocalDateTime plusYears = localDateTime.plusYears(1L);
        System.out.println("plusYears = " + plusYears);
        //輸出: plusYears = 2021-07-06T22:46:49.196
        
        //2、加1個月
        LocalDateTime plusMonths = localDateTime.plusMonths(1L);
        System.out.println("plusMonths = " + plusMonths);
        //輸出: plusMonths = 2020-08-06T22:46:49.196
        
        //3、加一天
        LocalDateTime plusDays = localDateTime.plusDays(1L);
        System.out.println("plusDays = " + plusDays);
        //輸出: plusDays = 2020-07-07T22:46:49.196
        
        //4、加1個小時
        LocalDateTime plusHours = localDateTime.plusHours(1L);
        System.out.println("plusHours = " + plusHours);
        //輸出: plusHours = 2020-07-06T23:46:49.196
        
        //5、加10分
        LocalDateTime plusMinutes = localDateTime.plusMinutes(10L);
        System.out.println("plusMinutes = " + plusMinutes);
        //輸出: plusMinutes = 2020-07-06T22:56:49.196
        
        //6、加200毫秒
        LocalDateTime plusSeconds = localDateTime.plusSeconds(200L);
        System.out.println("plusSeconds = " + plusSeconds);
        //輸出: plusSeconds = 2020-07-06T22:50:09.196
    }

也可以用另外一種方式

     LocalDateTime nextMonth = localDateTime.plus(1, ChronoUnit.MONTHS);
     LocalDateTime nextYear = localDateTime.plus(1, ChronoUnit.YEARS);
     LocalDateTime nextWeek = localDateTime.plus(1, ChronoUnit.WEEKS);

減法操作

    public static void main(String[] args) {
        //獲取當前時間
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println("當前時間 = " + localDateTime);
        //輸出: 當前時間 = 2020-07-06T22:53:38.264

        //1、減1年
        LocalDateTime minusYears = localDateTime.minusYears(1L);
        System.out.println("minusYears = " + minusYears);
        //輸出: minusYears = 2019-07-06T22:53:38.264

        //2、減1個月
        LocalDateTime minusMonths = localDateTime.minusMonths(1L);
        System.out.println("minusMonths = " + minusMonths);
        //輸出: minusMonths = 2020-06-06T22:53:38.264

        //3、減一天
        LocalDateTime minusDays = localDateTime.minusDays(1L);
        System.out.println("minusDays = " + minusDays);
        //輸出: minusDays = 2020-07-05T22:53:38.264

        //4、減1個小時
        LocalDateTime minusHours = localDateTime.minusHours(1L);
        System.out.println("minusHours = " + minusHours);
        //輸出: minusHours = 2020-07-06T21:53:38.264

        //5、減10分
        LocalDateTime minusMinutes = localDateTime.minusMinutes(10L);
        System.out.println("minusMinutes = " + minusMinutes);
        //輸出: minusMinutes = 2020-07-06T22:43:38.264

        //6、減200毫秒
        LocalDateTime minusSeconds = localDateTime.minusSeconds(200L);
        System.out.println("minusSeconds = " + minusSeconds);
        //輸出: minusSeconds = 2020-07-06T22:50:18.264
    }

也可以用另外一種方式

        LocalDateTime lastMonth = localDateTime.minus(1, ChronoUnit.MONTHS);
        LocalDateTime lastYear = localDateTime.minus(1, ChronoUnit.YEARS);
        LocalDateTime lastWeek = localDateTime.minus(1, ChronoUnit.WEEKS);

注意從程式碼中可以看到,這些 plus()minus() 方法,是不會改變原date和time的實例的,返回的是新的實例。

3、比較日期和時間

當我們想知道給定的時間或日期是在另一個時間/日期之前還是之後,我們就可以用到isBefore()isAfter()方法,如下所示:

 public static void main(String[] args) {
       public static void main(String[] args) {
        LocalDate ld1 = LocalDate.of(2020, 7, 6);
        LocalDate ld2 = LocalDate.of(2020, 7, 7);

        boolean after = ld1.isAfter(ld2);
        System.out.println("ld1是否在ld2之後 = " + after);
        //輸出:  ld1是否在ld2之後 = false

        boolean before = ld1.isBefore(ld2);
        System.out.println("ld1是否在ld2之前 = " + before);
        //輸出:  ld1是否在ld2之前 = true

        LocalDateTime ldt1 = LocalDateTime.of(2020, 7, 7, 12, 12);
        LocalDateTime ldt2 = LocalDateTime.of(2020, 7, 7, 14, 12);

        boolean after1 = ldt1.isAfter(ldt2);
        System.out.println("ldt1是否在ldt2之後 = " + after1);
        //輸出:  ldt1是否在ldt2之後 = false

        boolean before1 = ldt1.isBefore(ldt2);
        System.out.println("ldt1是否在ldt2之後 = " + before1);
        //輸出:  ldt1是否在ldt2之後 = true

        //時間相減
        Duration duration = Duration.between(ldt1, ldt2);
        //兩個時間差的天數
        long days = duration.toDays();
        System.out.println("days = " + days);
        //輸出: days = 0

        //小時數差
        long hours = duration.toHours();
        System.out.println("hours = " + hours);
        //輸出: hours = 2

        //分鐘數差
        long minutes = duration.toMinutes();
        System.out.println("minutes = " + minutes);
        //輸出: minutes = 120

        //毫秒數差
        long millis = duration.toMillis();
        System.out.println("millis = " + millis);
        //輸出: millis = 7200000

        //納秒數差
        long nanos = duration.toNanos();
        System.out.println("nanos = " + nanos);
        //輸出: nanos = 7200000000000
    }

4、在String和日期之間轉換

在以前使用java.util.Date的時候,我們一般使用 SimpleDateFormat 去完成日期/時間和字元串的轉換,在新的日期時間API中,我們使用全新的 DateTimeFormatter

如果你遵循ISO標準在日期/時間和字元串之間進行轉換,那麼這個事情會變得很容易,因為在 DateTimeFormatter 中,已經內置了ISO標準的格式。我們來看看程式碼

日期轉時間

public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println("ldt = " + ldt);
        //輸出: ldt = 2020-07-07T18:32:34.757

        String format1 = ldt.format(DateTimeFormatter.ISO_DATE);
        System.out.println("format1 = " + format1);
        //輸出: format1 = 2020-07-07

        String format2 = ldt.format(DateTimeFormatter.BASIC_ISO_DATE);
        System.out.println("format2 = " + format2);
        //輸出:  format2 = 20200707
        
        String format3 = ldt.format(DateTimeFormatter.ISO_DATE_TIME);
        System.out.println("format3 = " + format3);
        //輸出: format3 = 2020-07-07T18:32:34.757

        String format4 = ldt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
        System.out.println("format4 = " + format4);
        //輸出: format4 = 2020-07-07T18:32:34.757

        String format = ldt.format(DateTimeFormatter.ofPattern("d-M-y"));
        System.out.println("format = " + format);
        //輸出: format = 7-7-2020

        String format5 = ldt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        System.out.println("format5 = " + format5);
        //輸出: format5 = 2020-07-07 18:32:34
        
        String format6 = ldt.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日HH時mm分ss秒"));
        System.out.println("format6 = " + format6);
        //輸出: format6 = 2020年07月07日18時32分34秒
      }

String轉日期

public static void main(String[] args) {
        LocalDate ld = LocalDate.parse("2020-07-07");
        System.out.println("ld = " + ld);
        //輸出: ld = 2020-07-07

        String str = "2020-07-07 22:24:33";
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime ldt = LocalDateTime.parse(str,dateTimeFormatter);
        System.out.println("ldt = " + ldt);
        //輸出: ldt = 2020-07-07T22:24:33
      }

5、其它

有的時候,你需要進行一些更加複雜的操作,比如,將日期調整到下個周日、下個工作日,或者是本月的最後一天。這時,你可以使用重載版本的with方法,向其傳遞一個提供了更多訂製化選擇的TemporalAdjuster對象,更 加 靈 活 地 處 理 日 期。

日期處理

  public static void main(String[] args) {
        LocalDate date = LocalDate.parse("2020-07-07");
        //獲取這個月的第一個周末的時間
        System.out.println(date.with(TemporalAdjusters.dayOfWeekInMonth(1, DayOfWeek.SUNDAY)));
        //輸出: 2020-07-05

        //獲取上個月的最後一周末的時間
        System.out.println(date.with(TemporalAdjusters.dayOfWeekInMonth(0, DayOfWeek.SUNDAY)));
        //輸出: 2020-06-28

        //獲取這個月的倒數第一個周末的時間
        System.out.println(date.with(TemporalAdjusters.dayOfWeekInMonth(-1, DayOfWeek.SUNDAY)));
        //輸出: 2020-07-26

        //獲取這個月的第一個周末的時間,上面的dayOfWeekInMonth更靈活,可以定義第幾周
        System.out.println(date.with(TemporalAdjusters.firstInMonth(DayOfWeek.SUNDAY)));
        //輸出: 2020-07-05

        //明年的第一天
        System.out.println(date.with(TemporalAdjusters.firstDayOfNextYear()));
        //輸出: 2021-01-01
        
        //獲取下個周5的時間
        System.out.println(date.with(TemporalAdjusters.next(DayOfWeek.FRIDAY)));
        //輸出: 2020-07-10
        
        //獲取本月最後一天
        System.out.println(date.with(TemporalAdjusters.lastDayOfMonth()));
        //輸出: 2020-07-31

        //獲取本月第一天
        System.out.println(date.with(TemporalAdjusters.firstDayOfMonth()));
        //輸出: 2020-07-01
      }

其它還有許多,具體查看api

時間處理

public static void main(String[] args) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        //一天開始時間
        LocalDateTime todayStart = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        String format = todayStart.format(dateTimeFormatter);
        System.out.println("format = " + format);
        //輸出: format = 2020-07-07 00:00:00
        
        //一天結束時間
        LocalDateTime todayEnd = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
        String format1 = todayEnd.format(dateTimeFormatter);
        System.out.println("format1 = " + format1);
        //輸出: format1 = 2020-07-07 23:59:59

        //一天中午時間
        LocalDateTime todayMid = LocalDateTime.of(LocalDate.now(), LocalTime.NOON);
        String format2 = todayMid.format(dateTimeFormatter);
        System.out.println("format2 = " + format2);
        //輸出: format2 = 2020-07-07 12:00:00
      }

舉了這麼多例子,在實際開發中應該足夠用了。

參考

1、JDK8新特性之:Optional

2、Optional類包含的方法介紹及其示例

別人罵我胖,我會生氣,因為我心裡承認了我胖。別人說我矮,我就會覺得好笑,因為我心裡知道我不可能矮。這就是我們為什麼會對別人的攻擊生氣。
攻我盾者,乃我內心之矛(23)