Java8-日期类型

Java8-日期类型

传统日期类的缺陷

传统的日期类存在着线程安全问题:

@Test
public void test1()  throws Exception {
  SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

  Callable<Date> task = new Callable<Date>() { // 创建一个任务对象
    @Override
    public Date call() throws Exception {
      return sdf.parse("20180322");
    }
  };

  // 创建一个又是个线程的线程池
  List<Future<Date>> results = new ArrayList<>();
  ExecutorService pool = Executors.newFixedThreadPool(10);
  for (int i = 0; i < 10; i++) {
    results.add(pool.submit(task));
  }

  // 遍历输出
  for(Future<Date> future : results) {
    System.out.println(future.get());
  }

}

输出:

java.util.concurrent.ExecutionException: 
     java.lang.NumberFormatException: multiple points
     Caused by: java.lang.NumberFormatException: multiple points

出现并发异常。

解决方法

使用ThreadLocal绑定SimpleDateFormat

创建自定义的ThreadLocal类

class MyThreadLocal {   
    private static final ThreadLocal<SimpleDateFormat> tl = new ThreadLocal<SimpleDateFormat>() {
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat("yyyyMMdd");
        }
    };  
    static Date convert(String v) throws Exception {
        return tl.get().parse(v);
    }   
}

测试自定义的ThreadLocal:

@Test
public void test2()  throws Exception {
  Callable<Date> task = new Callable<Date>() { // 创建一个任务对象
    @Override
    public Date call() throws Exception {
      return MyThreadLocal.convert("20180322");
    }
  };
  // 创建一个又是个线程的线程池
  List<Future<Date>> results = new ArrayList<>();
  ExecutorService pool = Executors.newFixedThreadPool(10);
  for (int i = 0; i < 10; i++) {
    results.add(pool.submit(task));
  }
  pool.shutdown(); //关闭线程池 
  // 遍历输出
  for(Future<Date> future : results) {
    System.out.println(future.get());
  }
}

输出:

Thu Mar 22 00:00:00 CST 2018
Thu Mar 22 00:00:00 CST 2018
Thu Mar 22 00:00:00 CST 2018
Thu Mar 22 00:00:00 CST 2018
Thu Mar 22 00:00:00 CST 2018
Thu Mar 22 00:00:00 CST 2018

使用Java8的新特性

在Java8中,使用java.time.* 包下面的类即可解决多线程造成的并发问题。

使用 DateTimeFormatterLocalDate

@Test
public void test3() throws Exception {

  DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");

  Callable<LocalDate> task = new Callable<LocalDate>() { // 创建一个任务对象
    @Override
    public LocalDate call() throws Exception {
      return LocalDate.parse("20180322", dtf);
    }
  };

  // 创建一个又是个线程的线程池
  List<Future<LocalDate>> results = new ArrayList<>();
  ExecutorService pool = Executors.newFixedThreadPool(10);
  for (int i = 0; i < 10; i++) {
    results.add(pool.submit(task));
  }

  pool.shutdown(); //关闭线程池 

  // 遍历输出
  for(Future<LocalDate> future : results) {
    System.out.println(future.get());
  }
}

Java8的日期类型

LocalDateTime、LocalDate、LocalTime

替代了之前的Date

LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt.getYear());//2018
System.out.println(ldt.getMonthValue());//3
System.out.println(ldt.getDayOfMonth());//23
System.out.println(ldt.getDayOfYear());//82 一年中的第几天
System.out.println(ldt.getDayOfWeek());//FRIDAY
System.out.println(ldt.getHour());//0
System.out.println(ldt.getMinute());//8
System.out.println(ldt.getSecond());//13

System.out.println("--------- 年、月、日、时、分、秒 的相加 ---------");
System.out.println(ldt.plusYears(1).getYear());//2019
System.out.println(ldt.plusMonths(1).getMonthValue());//4
System.out.println(ldt.plusDays(1).getDayOfMonth());//24
System.out.println(ldt.plusHours(1).getHour());//1
System.out.println(ldt.plusMinutes(1).getMinute());//13
System.out.println(ldt.plusSeconds(1).getSecond());//47

System.out.println("--------- 自定义时间 ---------");
LocalDateTime ldt2 = LocalDateTime.of(2018, 5, 1, 0, 0);
System.out.println(ldt2);// 2018-05-01T00:00

Instant 时间戳

时间戳,以Unix元年,即: 1970年1月1日 00时:00分:00秒

Instant i = Instant.now();
// 获得秒
System.out.println(i.getEpochSecond());//1521736686 
// 获得毫秒
System.out.println(i.toEpochMilli());//1521736686 272
// 获得纳秒,即获得的是toEpochMilli()之后的纳秒数
System.out.println(i.getNano());//272000000

//getEpochSecond() = toEpochMilli() + getNano() 

// 从1970开始加 60 秒
System.out.println(Instant.ofEpochMilli(60));//1970-01-01T00:00:00.060Z

Duration、Period 求间隔

Instant start = Instant.now();
Thread.sleep(1000);
Instant end = Instant.now();

// 间隔毫秒
System.out.println(Duration.between(start, end).toMillis());//1000
//间隔纳秒
System.out.println(Duration.between(start, end).toNanos());//1000000000

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

LocalTime ldt1 = LocalTime.now();
Thread.sleep(1000);
LocalTime ldt2 = LocalTime.now();
System.out.println(Duration.between(ldt1, ldt2).toMillis());//1002

System.out.println("--------------");
LocalDate ld1 = LocalDate.of(2017, 10, 10);
LocalDate ld2 = LocalDate.now();
System.out.println(Period.between(ld1, ld2).getYears());//0
System.out.println(Period.between(ld1, ld2).getMonths());//5
System.out.println(Period.between(ld1, ld2).getDays());//13

时间矫正器

TemporalAdjuster (函数式接口) TemporalAdjusters(工具类)

LocalDateTime ldt1 = LocalDateTime.now();

//修改日期为30号
LocalDateTime ldt2 = ldt1.withDayOfMonth(30);

System.out.println(ldt1);//2018-03-23T00:53:14.718
System.out.println(ldt2);//2018-03-30T00:53:14.718

// 修改日期为下一个周五
LocalDateTime ldt3 = ldt1.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
System.out.println(ldt3);//2018-03-30T00:59:19.393

// 自定义日期修改器:获得下一个工作日: 1~5
LocalDateTime ldt4 = ldt1.with((ldt) -> {
  LocalDateTime ldt5 = (LocalDateTime) ldt; // 强转为 LocalDateTime 类型
  DayOfWeek dow = ldt5.getDayOfWeek(); // 得到当前的日期
  if(dow.equals(DayOfWeek.FRIDAY)) {
    return ldt5.plusDays(3); //当前为周五加三天
  }else if(dow.equals(DayOfWeek.SATURDAY)) {
    return ldt5.plusDays(2); //当前为周六加两天
  }else {
    return ldt5.plusDays(1); //当前为周一到周天的话加一天
  }
});

System.out.println(ldt4);//2018-03-26T01:13:40.563

格式化时间

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd");
System.out.println(dtf.parse("2018/03/23"));//{},ISO resolved to 2018-03-23
System.out.println(LocalDateTime.now().format(dtf));//2018/03/23

时区相关

ZoneIdZoneDateZoneTimeZoneDateTime

ZoneId.getAvailableZoneIds()
  .parallelStream()
  .limit(5)
  .forEach(System.out::println);
//Asia/TehranWETEurope/AstrakhanAfrica/JubaAmerica/Campo_Grande

//创建指定时区的 LocalDateTime 对象
LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Vientiane"));
System.out.println(ldt);//2018-03-23T00:28:23.965

更多Java8的日期特性参考官方文档

    原文作者:Bart_G
    原文地址: https://blog.csdn.net/rocky_03/article/details/79662159
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞