Java 8

新的日期和時間 API

為什麼需要新的

Date API ?

Date date = new Date(114, 2, 18);
package com.balicanta.onlyfocus;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SimpleDateFormatThreadUnsafetyExample {

    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");

    public static void main(String[] args) {
        String dateStr = "2018-06-22T10:00:00";

        ExecutorService executorService = Executors.newFixedThreadPool(10);
        Runnable task = new Runnable() {
            @Override
            public void run() {
                parseDate(dateStr);
            }
        };

        for(int i = 0; i < 100; i++) {
            executorService.submit(task);
        }

        executorService.shutdown();
    }

    private static void parseDate(String dateStr) {
        try {
            Date date = simpleDateFormat.parse(dateStr);
            System.out.println("Successfully Parsed Date " + date);
        } catch (ParseException e) {
            System.out.println("ParseError " + e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

想一下幾個問題

  • 輸入 2019/09/21 字串,回傳 30 天後的 Date

  • 給你兩個 Date Object 中間差幾天?

  • 資料庫裡面存 Timestamp 頁面上顯示 幾天前上傳

  • 使用者輸入一個日期,回傳該日期月份的最後一天

為什麼需要新的

Date API ?

  • 可讀性
  • 易用性
  • Thread Safe

本地日期 Local Date

Local Date

// 取得現在的日期
LocalDate localDate = LocalDate.now();

// 傳入數字,取得日期
LocalDate.of(2015, 02, 20);
 
// 透過字串轉換成日期
LocalDate.parse("2015-02-20");

Local Date

// 現在日期加一天
LocalDate tomorrow = LocalDate.now().plusDays(1);

// 現在的日期減一個月
LocalDate previousMonthSameDay = LocalDate.now().minus(1, ChronoUnit.MONTHS);


// 取得今天是星期幾?
DayOfWeek sunday = LocalDate.parse("2016-06-12").getDayOfWeek();

// 取得今天是一個月的第幾天?
int twelve = LocalDate.parse("2016-06-12").getDayOfMonth();

// 是否為閏年
boolean leapYear = LocalDate.now().isLeapYear();

Local Date


// 兩兩日期的比較
boolean notBefore = LocalDate.parse("2016-06-12").isBefore(LocalDate.parse("2016-06-11"));
 
boolean isAfter = LocalDate.parse("2016-06-12").isAfter(LocalDate.parse("2016-06-11"));

Local Date


// 透過現在的 Local Date 取得一個 LocalDate Time 的時間
LocalDateTime beginningOfDay = LocalDate.parse("2016-06-12").atStartOfDay();

// 透過現在的日期,平移到這個月的第一天
LocalDate firstDayOfMonth = 
	LocalDate.parse("2016-06-12").with(TemporalAdjusters.firstDayOfMonth());

本地時間 Local Time

Local Time

// 取得現在時間,只有時間,沒有日期
LocalTime now = LocalTime.now();

// 透過字串取得時間
LocalTime sixThirty = LocalTime.parse("06:30");

// 透過數字取得時間
LocalTime sixThirty = LocalTime.of(6, 30);

Local Time

// 加一個小時
LocalTime sevenThirty = LocalTime.parse("06:30").plus(1, ChronoUnit.HOURS);

// 取得小時
int six = LocalTime.parse("06:30").getHour();

// 兩者時間的比較
boolean isbefore = LocalTime.parse("06:30").isBefore(LocalTime.parse("07:30"));

本地日期與時間

LocalDateTime

本地日期與時間

LocalDateTime

// 取得本地日期時間
LocalDateTime.now();

// 透過數字取得
LocalDateTime.of(2015, Month.FEBRUARY, 20, 06, 30);

// 透過文字取得
LocalDateTime.parse("2015-02-20T06:30:00");

// 日期、時間的運算
localDateTime.plusDays(1);

localDateTime.minusHours(2);

有時區概念的時間

有時區概念的時間

// 透過字串取得 ZoneId
ZoneId zoneId = ZoneId.of("Europe/Paris");

// 取得所有的 ZoneId
Set<String> allZoneIds = ZoneId.getAvailableZoneIds();

// 透過字串,轉換一個具有 Zone ID 的字串
ZonedDateTime.parse("2015-05-03T10:15:30+01:00[Europe/Paris]");

Duration & Period

Period


// 取得兩個日期
LocalDate initialDate = LocalDate.parse("2007-05-10");

LocalDate finalDate = initialDate.plus(Period.ofDays(5));


// 取得兩者的差距天數
int five = Period.between(initialDate, finalDate).getDays();

Duration


ocalTime initialTime = LocalTime.of(6, 30, 0);
 
LocalTime finalTime = initialTime.plus(Duration.ofSeconds(30));

long thirty = Duration.between(initialTime, finalTime).getSeconds();

時間與日期的格式化

時間與日期的格式化

LocalDateTime localDateTime = LocalDateTime.of(2015, Month.JANUARY, 25, 6, 30);

// 透過內建的 Formatter 完成
String localDateString = localDateTime.format(DateTimeFormatter.ISO_DATE);

時間與日期的格式化

localDateTime
  .format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM))
  .withLocale(Locale.UK);

時間與日期的格式化

DateTimeFormatter italianFormatter = new DateTimeFormatterBuilder()
        .appendText(ChronoField.DAY_OF_MONTH)
        .appendLiteral(". ")
        .appendText(ChronoField.MONTH_OF_YEAR)
        .appendLiteral(" ")
        .appendText(ChronoField.YEAR)
        .parseCaseInsensitive()
        .toFormatter(Locale.ITALIAN);

今天要記得什麼?

今天要記得什麼?

  • Java 8 針對 Date API 有全面性增強
  • 把過去的 Date 分成
    • LocalDate, LocalTime... TimeZoneDateTime
  • 日期的移動變的很簡單
  • 增加了 Duration & Period
  • 相容於舊的 java.util.date & java.util.TimeStamp
    • 但 Redick  沒有分享

Java 8新的日期和時間 API

By Balicanta Yao

Java 8新的日期和時間 API

  • 182