今天總結下Java 8 新的時間日期 API使用

1. 概述

1.1 簡介

Java 8 引入了一套全新的時間日期API,操作起來更簡便。簡單介紹下,LocalDate和LocalTime和LocalDateTime的使用;

java.util.Date月份從0開始,java.time.LocalDate月份從1開始並且提供了枚舉。

java.util.Date和SimpleDateFormatter都不是線程安全的,而LocalDate和LocalTime和最基本的String一樣,是不變類型,不但線程安全,而且不能修改,它們分別使用 ISO-8601 日曆系統的日期和時間,它們提供了簡單的日期或時間,並不包含當前的時間信息,也不包含與時區相關的信息。

注 : ISO-8601 日曆系統是國際標準化組織制定的現代公民的日期和時間的表示法

1.3 環境

2. LocalDate、LocalTime、LocalDateTime

LocalDate、LocalTime、LocalDateTime 三者的使用方式基本一致,所以我們這裡就以 LocalDateTime 為例進行索命

2.1 實例


@Test

public void test1() {
// 獲取當前時間
LocalDateTime ldt1 = LocalDateTime.now();
System.out.println(ldt1);

// 獲取指定的時間
LocalDateTime ldt2 = LocalDateTime.of(2018, 12, 10, 10, 10, 10);
System.out.println(ldt2);

// 加兩年
LocalDateTime ldt3 = ldt1.plusYears(2);
System.out.println(ldt3);

// 減兩個月
LocalDateTime ldt4 = ldt1.minusYears(2);
System.out.println(ldt4);

// 獲取年月日時分秒
System.out.println(ldt1.getYear());
System.out.println(ldt1.getMonthValue());
System.out.println(ldt1.getDayOfMonth());
System.out.println(ldt1.getHour());
System.out.println(ldt1.getMinute());
System.out.println(ldt1.getSecond());
}

2.2 Instant : 時間戳

使用 Unix 元年 1970年1月1日 00:00:00 所經歷的毫秒值


@Test
public void test2() {
Instant ins = Instant.now(); //默認使用 UTC 時區
System.out.println(ins);

// 時間偏移量
OffsetDateTime odt = ins.atOffset(ZoneOffset.ofHours(8));
System.out.println(odt);

// 獲取毫秒值

System.out.println(ins.getNano());

// 對於元年開始進行運算
Instant ins2 = Instant.ofEpochSecond(60);
System.out.println(ins2);
}

2.3 Duration : 用於計算兩個“時間”間隔


@Test
public void test3() throws InterruptedException {
// 時間戳
Instant ins1 = Instant.now();

Thread.sleep(1000);

Instant ins2 = Instant.now();
Duration duration = Duration.between(ins1, ins2);
System.out.println("所耗費時間為:" + duration.toMillis());

System.out.println("--------------------------------");

// LocalTime
LocalTime lt1 = LocalTime.now();

Thread.sleep(1000);

LocalTime lt2 = LocalTime.now();

System.out.println("所耗費時間為:" + Duration.between(lt1, lt2).toMillis());
}

2.4 Period : 用於計算兩個“日期”間隔


@Test
public void test5() {
LocalDate ld1 = LocalDate.of(2017, 1, 1);

LocalDate ld2 = LocalDate.now();
Period period = Period.between(ld1, ld2);
System.out.println("相差" + period.getYears() + "年" + period.getMonths() + "月" + period.getDays() + "天");
}

2.5 日期的操作

TemporalAdjuster 時間校正器,有時我們可能需要獲取例如:將日期調整到下個週日等操作。

TemporalAdjusters 該類通過靜態方法提供了大量的常用 TemporalAdjuster 的實現。


@Test
public void test6() {
LocalDateTime ldt = LocalDateTime.now();

// 指定這個月的一個固定日期
LocalDateTime ldt2 = ldt.withDayOfMonth(10);
System.out.println(ldt2);

// 獲取下個週日
LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println("獲取下個週日 : " + ldt3);

// 自定義:獲取下個工作日
LocalDateTime ldt5 = ldt.with((l) -> {
LocalDateTime ldt6 = (LocalDateTime) l;
DayOfWeek dayOfWeek = ldt6.getDayOfWeek();

if (dayOfWeek.equals(DayOfWeek.FRIDAY)) {
return ldt6.plusDays(3);
} else if (dayOfWeek.equals(DayOfWeek.SATURDAY)) {
return ldt6.plusDays(2);
} else {
return ldt6.plusDays(1);
}
});
System.out.println("獲取下個工作日 : " + ldt5);

}

3. DateTimeFormatter

3.1 簡介

在 JDK 1.8 中可以使用 DateTimeFormatter 來代替 SimpleDateFormat 進行日期的格式化,而且 DateTimeFormatter 是線程安全的

3.2 實例


@Test
public void test8() {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime ldt = LocalDateTime.now();

// 將日期格式化為字符串,兩種方式否可以
String dtfDate = dtf.format(ldt);
String ldtDate = ldt.format(dtf);
System.out.println("dtfDate : " + dtfDate);
System.out.println("ldtDate : " + ldtDate);

// 將字符串格式化為 LocalDateTime
LocalDateTime ldt2 = LocalDateTime.parse(dtfDate, dtf);
System.out.println("時間為 : " + ldt2);
}

3.3 線程安全

在多線程使用 SimpleDateFormat 進行格式化日期的時候會有線程安全問題。

 

@Test
public void test1() throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

Callable<date> task = new Callable<date>() {
@Override
public Date call() throws Exception {
return sdf.parse("2018-12-10");
}
};

ExecutorService executor = Executors.newFixedThreadPool(10);
List<future>> results = new ArrayList<>();
for (int i = 0; i < 10; i++) {
results.add(executor.submit(task));
}

for (Future<date> future : results) {
System.out.println(future.get());
}
executor.shutdown();
}
/<date>/<future>/<date>/<date>

可以使用 ThreadLocal 的鎖解決 SimpleDateFormat 的線程安全問題


import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateFormatThreadLocal {
private static final ThreadLocal<dateformat> df = new ThreadLocal<dateformat>() {
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");
}
};

public static final Date convert(String source) throws ParseException {
return df.get().parse(source);
}
}
/<dateformat>/<dateformat>

測試方法


@Test

public void test2() throws Exception {
Callable<date> task = new Callable<date>() {
@Override
public Date call() throws Exception {
return DateFormatThreadLocal.convert("2018-12-10");
}
};

ExecutorService executor = Executors.newFixedThreadPool(10);
List<future>> results = new ArrayList<>();
for (int i = 0; i < 10; i++) {
results.add(executor.submit(task));
}

for (Future<date> future : results) {
System.out.println(future.get());
}
executor.shutdown();
}
/<date>/<future>/<date>/<date>

使用 DateTimeFormatter 進行格式化,DateTimeFormatter 是線程安全的


@Test
public void test3() throws Exception {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");

Callable<localdate> task = new Callable<localdate>() {
@Override
public LocalDate call() throws Exception {
return LocalDate.parse("2018-12-10",dtf);
}
};

ExecutorService executor = Executors.newFixedThreadPool(10);
List<future>> results = new ArrayList<>();
for (int i = 0; i < 10; i++) {
results.add(executor.submit(task));
}

for (Future<localdate> future : results) {
System.out.println(future.get());
}
executor.shutdown();
}
/<localdate>/<future>/<localdate>/<localdate>

4. 時區設置


@Test
public void test2() {
LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println(ldt);

// 帶時區的時間
ZonedDateTime zdt = ldt.atZone(ZoneId.of("Asia/Shanghai"));
System.out.println(zdt);
}


分享到:


相關文章: