jdk8时间API
jdk8以前
之前与时间相关的API 是非线程安全的,设计很差且不在同一个包中,时区处理麻烦
多线程并发操作会出现问题
public class TestSimpleDateFormat { public static void main(String[] args) throws ExecutionException, InterruptedException { //规定格式 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Callable<Date> task = new Callable<Date>() { @Override public Date call() throws Exception { return sdf.parse("2020-10-24"); } }; //创建线程池 ExecutorService pool = Executors.newFixedThreadPool(10); //用list承载结果 List<Future<Date>> futures = new ArrayList<>(); //添加20个任务 for (int i = 0; i < 20; i++) { futures.add(pool.submit(task)); } //关闭线程池 pool.shutdown(); //遍历结果 for (Future<Date> future: futures) { System.out.println(future.get()); } } }
jdk8之前的解决方案:使用ThreadLocal
每个线程操作的是缓存在自己工作空间的副本值
public class ThreadLocalUse { private static final ThreadLocal<DateFormat> DATE_FORMAT_THREAD_LOCAL = new ThreadLocal<DateFormat>(){ @Override protected DateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd"); } }; public static Date convert(String source) throws ParseException { return DATE_FORMAT_THREAD_LOCAL.get().parse(source); } /** * @description Removes the current thread's value for this thread-local variable. */ public static void remove(){ DATE_FORMAT_THREAD_LOCAL.remove(); } }
ThreadLocal方式
public class OldResolver { public static void main(String[] args) throws ExecutionException, InterruptedException { //ThreadLocal 为每个线程分配一个SimpleDateFormat 来解决线程安全问题 Callable<Date> task = new Callable<Date>() { @Override public Date call() throws Exception { Date obtain = ThreadLocalUse.convert("2020-10-24"); //及时清理 防止内存泄漏 ThreadLocalUse.remove(); return obtain; } }; //创建线程池 ExecutorService pool = Executors.newFixedThreadPool(10); //用list承载结果 List<Future<Date>> futures = new ArrayList<>(); //添加20个任务 for (int i = 0; i < 20; i++) { futures.add(pool.submit(task)); } pool.shutdown(); //遍历结果 for (Future<Date> future: futures) { System.out.println(future.get()); } } }
jdk8以后
LocalDate(日期) 2020-10-2
LocalDateTime(日期和时间) 2020-10-25T09:17:50.482
LocalTime(时间)09:45:41.952
都是final修饰的不可变对象
有final修饰——实例是不可变对象
java.time Class LocalDateTime • java.lang.Object • java.time.LocalDateTime • All Implemented Interfaces: Serializable, Comparable<ChronoLocalDateTime<?>>, ChronoLocalDateTime<LocalDate>, Temporal, TemporalAccessor, TemporalAdjuster 来自 <https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html>
LocalDateTime 可以直接指定: LocalDateTime.of(2020, 10, 25, 16, 24, 30);
提供直接获取年月日的api:如getYear
@Test public void test1() { //获取当前日期时间 LocalDateTime dt1 = LocalDateTime.now(); LocalDate date = LocalDate.now(); LocalTime time = LocalTime.now(); System.out.println(dt1);//2020-10-25T09:17:50.482 System.out.println(date);//2020-10-2 System.out.println(time);//09:45:41.952 //指定日期时间 LocalDateTime dt2 = LocalDateTime.of(2020, 10, 25, 16, 24, 30); System.out.println(dt2);//2020-10-25T16:24:30 //加法 plus 运算 LocalDateTime dt3 = dt2.plusYears(10); System.out.println(dt3);//2030-10-25T16:24:30 System.out.println(dt2.plusDays(10));//2020-11-04T16:24:30 //获取时间 System.out.println(dt1.getYear());//年 2020 System.out.println(dt1.getMonth());//月(英文) OCTOBER System.out.println(dt1.getMonthValue());//月(数字) 10 System.out.println(dt1.getDayOfMonth());//日 25 System.out.println(dt1.getDayOfWeek());//星期 SUNDAY System.out.println(dt1.getDayOfWeek().getValue());//星期(数字) 7 System.out.println(dt1.getHour());//时 9 System.out.println(dt1.getMinute());//分 42 System.out.println(dt1.getSecond());//秒 45 }
Instant 时间戳
使用Unix元年1970年1月1日00:00:00所经历的毫秒
重写了toString
@Override public String toString() { return DateTimeFormatter.ISO_INSTANT.format(this); }
@Test public void test2() { Instant ins = Instant.now();//默认使用UTC时区 System.out.println(ins);//2020-10-25T01:47:37.815Z //使用时区偏移量 OffsetDateTime offsetDateTime = ins.atOffset(ZoneOffset.ofHours(8)); System.out.println(offsetDateTime);//2020-10-25T09:51:04.041+08:00 //获取纳秒 System.out.println(ins.getNano()); //获取历元后指定偏移秒的瞬间 即用秒表示的时间戳 Instant ins2 = Instant.ofEpochSecond(5); System.out.println(ins2);//1970-01-01T00:00:05Z }
Clock时钟
@Test public void test3() { //获取时钟,用最佳可用系统时钟返回当前时刻,并用UTC时区转换日期和时间 Clock utc = Clock.systemUTC(); System.out.println(utc.getZone());//Z System.out.println(utc.instant());//2020-10-25T12:16:48.798Z //获取一个时钟,返回的是系统时区表示的当前瞬间,并用默认时区转换日期和时间 Clock clock = Clock.systemDefaultZone(); System.out.println(clock);//SystemClock[Asia/Shanghai] System.out.println(clock.getZone());//Asia/Shanghai 获取时区 System.out.println(clock.millis());//1603627665781 毫秒时间戳 //通过Clock获取Instant 注意Instant默认使用的UTC时区 Instant instant = clock.instant();//返回clock记录的当前时刻 System.out.println(instant);//2020-10-25T12:21:40.364Z 因为Instant 默认使用UTC时区,所以Asia的日期和时间被转换了 System.out.println(instant.toEpochMilli());//1603627665782 毫秒时间戳 和上面一样的 //通过Clock获取LocalDateTime LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, clock.getZone()); System.out.println(localDateTime);//2020-10-25T20:21:40.364 //自定义Clock的创建 滴答间隔为3秒 逢3进1 通常时钟的滴答间隔为1s Clock tick = Clock.tick(clock, Duration.ofSeconds(3));//滴答时间间隔为3秒钟 for (int i = 0; i < 10; i++) { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(clock.instant().atZone(ZoneId.of("Asia/Shanghai")) + "\t对比自定义时钟\t" + tick.instant().atZone(ZoneId.of("Asia/Shanghai"))); } /* 2020-10-25T20:43:42.456+08:00[Asia/Shanghai] 对比自定义时钟 2020-10-25T20:43:42+08:00[Asia/Shanghai] 2020-10-25T20:43:43.462+08:00[Asia/Shanghai] 对比自定义时钟 2020-10-25T20:43:42+08:00[Asia/Shanghai] 2020-10-25T20:43:44.468+08:00[Asia/Shanghai] 对比自定义时钟 2020-10-25T20:43:42+08:00[Asia/Shanghai] 2020-10-25T20:43:45.469+08:00[Asia/Shanghai] 对比自定义时钟 2020-10-25T20:43:45+08:00[Asia/Shanghai] */ }
Duration时间段
用于计算两个时间的间隔
Duration.getSeconds()时间差转为秒
Duration.getSNacos()时间差转为纳秒
Duration.get(Temproral unit) 转化为指定单时间单元表示形式
ChronoUnit中是细时间颗粒,更常用
@Test public void test4() { // 时间的间隔 Instant ins1 = Instant.now(); System.out.println("-------------"); try { Thread.sleep(2000); } catch (Exception e) { e.printStackTrace(); } Instant ins2 = Instant.now(); Duration duration = Duration.between(ins1, ins2); System.out.println("间隔:" + duration);//间隔:PT2S System.out.println(duration.getSeconds());//间隔:2 (s) System.out.println("----------"); /* 日期的间隔 */ LocalDate date = LocalDate.now();//2020-10-25 LocalDate date2 = LocalDate.of(2011, 1, 1); Period period = Period.between(date, date2); System.out.println(period.getYears());//-9 九年 System.out.println(period.getMonths());//-9 九个月 System.out.println(period.getDays());//-24 24天 }
TemporalAdjuster校正器 可自定义
@Test public void test5() { LocalDateTime dateTime = LocalDateTime.now(); System.out.println(dateTime);//2020-10-25T10:57:11.455 //将day较正为 10号 LocalDateTime dateTime1 = dateTime.withDayOfMonth(10); System.out.println(dateTime1);//2020-10-10T10:57:11.455 //自定义校正,下一个工作日 LocalDateTime localDateTime = dateTime.with(date -> { //需要强转 LocalDateTime original = (LocalDateTime) date; //获取星期 DayOfWeek week = original.getDayOfWeek(); if (week.equals(DayOfWeek.FRIDAY)) { //周五 加上 3天 就是工作日 return original.plusDays(3); } else if (week.equals(DayOfWeek.SATURDAY)) { //周六 要加上 2天 return original.plusDays(2); } else { //其它 都只需要加上一天 return original.plusDays(1); } }); System.out.println(localDateTime);//2020-10-26T11:14:51.058 因为是周日所以只需加上一天 }
DateTimeFormatter:格式化器 格式化和解析日期或者时间
LocalDateTime等自带格式化与解析方法
@Test public void test6() { //使用已有日期时间格式 DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_LOCAL_DATE; //LocalDateTime now()默认的是当前系统的时区 LocalDateTime dateTime = LocalDateTime.now(); System.out.println(dateTime);//2020-10-25T11:25:22.070 String format = dateTime.format(dateTimeFormatter); System.out.println(format);//2020-10-25 String format1 = dateTimeFormatter.format(dateTime); System.out.println(format1);//2020-10-25 //格式化器格式化日期时间,日期时间调用格式化器都可以完成时间的转换,正反过来都行 //自定义日期时间格式 DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss"); //格式化 String custom = dateTime.format(ofPattern);//2020年10月25日 11:58:41 System.out.println(custom); //解析 //直接用格式化器解析 结果不易阅读 如果需要 可使用LocalDateTime的form方法转为LocalDateTime等 TemporalAccessor parse = ofPattern.parse(custom); System.out.println(parse);//{},ISO resolved to 2020-10-25T11:58:41 LocalDateTime parseResult = LocalDateTime.from(parse);//转化成LocalDateTime //将得到的TemporalAccessor转化为LocalDateTime:2020-10-25T12:16:30 System.out.println("将得到的TemporalAccessor转化为LocalDateTime:" + parseResult); ////LocalDateTime也提供了解析方法 也是调用格式化器 //实际执行的 parse(text, DateTimeFormatter.ISO_LOCAL_DATE_TIME) 默认的是系统格式 //2020年10月25日 11:35:56 用默认的会报错 解析不了 //LocalDateTime parse1 = LocalDateTime.parse(custom); //添加指定的格式化器就可以 比起直接用格式化器解析得到TemporalAccessor再调用form()转化为LocalDateTime简单点 LocalDateTime parse1 = LocalDateTime.parse(custom, ofPattern); System.out.println(parse1); }
ZonedDate ZonedTime ZonedDateTime:带时区的时间或日期
@Test public void test7() { //指定时区的LocalDateTime 本地日期时间 LocalDateTime dateTime = LocalDateTime.now(ZoneId.of("Asia/Shanghai")); System.out.println(dateTime);//2020-10-25T17:43:31.643 //指定时区的ZonedDateTime 时区日期时间 ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("US/Pacific")); System.out.println(zonedDateTime);//2020-10-25T02:44:48.612-07:00[US/Pacific] Set<String> availableZoneIds = ZoneId.getAvailableZoneIds(); System.out.println(availableZoneIds);//Asia/Aden, America/Cuiaba, Etc/GMT+9, Etc/GMT+8, Africa/Nairobi.... }
作者: deity-night
出处: https://www.cnblogs.com/deity-night/
关于作者:码农
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出, 原文链接 如有问题, 可邮件(***@163.com)咨询.