Java 8 日期時間API實戰

1、Date?Calendar?

  • Java 1.0中,對日期和時間的支持只能依賴java.util.Date類。因爲Date糟糕的易用性,Java 1.1中Date的不少方法被廢棄了,取而代之的是Calendar類。前端

  • 可是Calendar也並很差用,如月份從0開始,非線程安全,使得代碼很容易出錯。咱們最經常使用的SimpleDateFormat中相信每一個人項目中都有,不少人對這個SimpleDateFormat線程安全的問題沒有很直觀的認識,下面看這麼一個場景java

    //相信每一個人項目中都有這麼一個DateUtil、SimpleDateFormat
    public class DateUtil{
       private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd HH");
    }
    
    //調用方
    public class Test{
      //20191228 14
        System.out.println(DateUtil.simpleDateFormat.format(new Date()));
      
      //某個線程按照本身的時區,影響了全局的simpleDateFormat,其餘調用者就得出錯誤結果
      //20191228 06
        new Thread(() -> {
    				DateUtil.simpleDateFormat.setTimeZone(TimeZone.getTimeZone("+7"));
    	      System.out.println(DateUtil.simpleDateFormat.format(new Date()));
        }).start();
    
      //20191228 06
        new Thread(() -> {
          System.out.println(DateUtil.simpleDateFormat.format(new Date()));
        }).start();
    }
    複製代碼
  • 不只如此,代碼中同時存在Date和Calendar,廣大Java程序員更加困惑。所以涉及到日期時間大部分狀況下都是藉助於第三方庫來實現日期時間功能,如joda-time。其實Java 8 的日期時間API能看到不少joda-time的特性。程序員

  • 順應潮流,Java 8的大版本中提供了一系列日期和時間支持的API。本文主要介紹這些新增的API,讓你不用從上到下new Date()一把梭。後端

2、Java 8中日期、時間

  • 本文主要從Java 8中的日期、時間兩大塊來介紹這些新增的API。

LocalDate

  • LocalDate類實例是一個不可變對象,只包含日期,不含有時間信息,也不帶時區信息
//今天
LocalDate now = LocalDate.now();
System.out.println(now);
//年、月、日構造
LocalDate date = LocalDate.of(2018, 12, 12);
System.out.println(date);

複製代碼

LocalTime

  • LocalTime只包含時間信息,不包含日期信息。
LocalTime time = LocalTime.now();
LocalTime time1 = LocalTime.parse("12:4:20");
複製代碼

LocalDateTime

  • LocalDate和LocalTime的結合體,既有時間信息,又有日期信息。
//今天當前時間
LocalDateTime ltime1 = LocalDateTime.now();

//指定年、月、日、時、分、秒
LocalDateTime time = LocalDateTime.of(2019, 12, 26, 12, 11, 34);

//LocalDate + 時間信息
LocalDateTime ltime2= LocalDate.now().atTime(12,11,23);

//LocalTime + 日期信息
LocalTime.now().atDate(LocalDate.now());
複製代碼

Duration、Period

  • Duration/Period均不是一個時間點,而是時間間隔。Period類表示年、月、日時間間隔,Duration是一個表示秒/納秒的時間間隔。即Period基於日期值,而Duration基於時間值。
  • 這兩個類是爲了日期、時間的度量服務的。
//幾天前的實現
LocalDate date1 =LocalDate.now();
LocalDate date2 = LocalDate.of(2019, 12, 11);
Period period = Period.between(date1, date2);

//-17
System.out.println(period.getDays());

複製代碼

TemporalAdjuster

  • Java 8 中內置的一個工具類,能夠更加靈活處理日期。
  • Java 8中提供了大量預約義的TemporalAdjuster,在一些複雜的時間操做下很是好用。
//能夠看出這個類的做用是將一個Temporal轉成另外一個Temporal
//LocalDate、LoclaTime、LocalDateTime等都實現了Temporal接口
@FunctionInterface
public function TemporalAdjuster{
  Temporal adjustInto(Temporal temporal);
}
複製代碼
方法名 描述
dayOfWeekInMonth 返回同一個月中每週第幾天
firstDayOfMonth 返回當月第一天
firstDayOfNextMonth 返回下月第一天
firstDayOfNextYear 返回下一年的第一天
firstDayOfYear 返回本年的第一天
firstInMonth 返回同一個月中第一個星期幾
lastDayOfMonth 返回當月的最後一天
lastDayOfNextMonth 返回下月的最後一天
lastDayOfNextYear 返回下一年的最後一天
nextOrSame / previousOrSame 返回後一個/前一個給定的星期幾,若是這個值知足條件,直接返回

DateTimeFormatter

  • 主要用於日期格式化操做,format()/parse()。
//format
LocalDateTime dateTime = LocalDateTime.now();
String strDate1 = dateTime.format(DateTimeFormatter.BASIC_ISO_DATE);    // 20170105
String strDate2 = dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE);    // 2017-01-05
String strDate3 = dateTime.format(DateTimeFormatter.ISO_LOCAL_TIME);    // 14:20:16.998
String strDate4 = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));// 2017-01-05


//parse
String strDate6 = "2017-01-05";
String strDate7 = "2017-01-05 12:30:05";

LocalDate date = LocalDate.parse(strDate6, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDateTime dateTime1 = LocalDateTime.parse(strDate7, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

複製代碼

3、經常使用功能

LocalDate、LocalTime

//今天12:00:00時間戳
LocalDate.now().atTime(12,0,0).toInstant(ZoneOffset.of("+8")).getEpochSecond());

//今天0:10:00時間戳
LocalDate.now().atTime(0,10,0).toInstant(ZoneOffset.of("+8")).getEpochSecond());


//幾天/周/年前、後
//5天前
LocalDate.now().minusDays(5);

//1天后
LocalDate.now().plusDays(1);

//2周後
LocalDate.now().plusWeeks(2);


//幾小時/分鐘前、後
//2小時前
LocalTime.now().minusHours(2);

//5分鐘後
LocalTime.now().plusMinutes(5);

複製代碼

Date、LocalDate、LocalTime、LocalDateTime

//Date轉LocalDateTime
Date date = new Date();
LocalDateTime time1 = LocalDateTime.ofInstant(date.toInstant(),ZoneOffset.of("+8"))
  								
//Date轉LocalDate
LocalDate date1 = LocalDateTime.ofInstant(date.toInstant(),ZoneOffset.of("+8"))
  								.toLocalate()

//LocalDate沒法直接轉Date,由於LocalDate不含時間信息

//LocalDateTime轉Date
LocalDateTime localDateTime3 = LocalDateTime.now();
Instant instant3 = LocalDateTime3.atZone(ZoneId.systemDefault()).toInstant();
Date date3 = Date.from(instant);
複製代碼

DateTimeFormatter的使用

//前端傳遞過來的字符串20191212,後端須要 2019-12-12
//除了replace(),更優雅的方式

DateTimeFormatter formatter = DateTimeFormatter.BASIC_ISO_DATE;
LocalDate formatted = LocalDate.parse("20191212",formatter);
//2019-12-12
System.out.println(formatted);

//前端傳遞過來的字符串2019-12-12,後端須要 20191212
LocalDate.parse("2019-12-12").format(DateTimeFormatter.BASIC_ISO_DATE));



//前端傳遞過來的字符串2019年12月12日,後端須要 2019-12-12
System.out.println(LocalDate.parse("2019年12月12日",DateTimeFormatter.ofPattern("yyyy年MM月dd日")));

複製代碼

TemporalAdjuster

//場景中須要使用距當前最近的週一
//返回上一個週一,若是今天是週一則返回今天
LocalDate date1 =LocalDate.now().with(previousOrSame(DayOfWeek.MONDAY));

//下一個週一/當天
LocalDate date1 =LocalDate.now().with(nextOrSame(DayOfWeek.MONDAY));


//本月最後一天
System.out.println(LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()));


//明年第一天
System.out.println(LocalDate.now().with(TemporalAdjusters.firstDayOfNextYear()));



複製代碼

4、小結

  • 本文主要介紹了Java 8中的日期時間API中經常使用的LocalDate、LocalTime、LocalDateTime、DateTimeFormatter、TemporalAdjuster,以及與Date之間的互轉。極大地豐富了咱們在日期時間開發中的選擇,並且解決了Date、SimpleDateFormat等線程安全的問題。
  • 在複雜日期時間場景下善於使用TemporalAdjuster,真香。
相關文章
相關標籤/搜索