Jdk8为什么要加很多时间类非线程安全的java.util.Date不是线程安全的,全是日期类是可变的,这是Java日期类最大的问题之一。Datedate=newDate();for(inti=0;i<100;i++){newThread(newRunnable(){@Overridepublicvoidrun(){//示例inttime=newRandom().nextInt(100);date.setTime(time);System.out.println(Thread.currentThread().getId()+"="+time);System.out.println(Thread.currentThread().getId()+"="+date.getTime());}}).start();}SimpleDateFormat格式化工具也是如此。阿里巴巴协议建议将SimpleDateFormat放在ThreadLocal中。在java8中,日期时间基本都设计成final的,final修饰的类自然是线程安全的。设计糟糕的java.util.Date同时包含日期和时间,而java.sql.Date只包含日期,两个类同名,令人难以置信。java.util.Date表示时间轴上的一个时刻(包括从Unix纪元到现在的总毫秒数),但是如果调用Date的toString(),返回值会提示它有时区,会也迷惑了开发商。时区和日期计算很麻烦。date类不提供国际化,不支持时区,所以Java引入了java.util.Calendar和java.util.TimeZone类,但它们也存在以上所有问题,使用起来复杂,不直观//获取当前时间日历+8时区Calendarcalendar=Calendar.getInstance();//毫秒calendar.setTimeInMillis(1601186434000L);//时区到utc时间calendar.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));intdstOffset=calendar.get(java.util.Calendar.DST_OFFSET);intzoneOffset=calendar.get(Calendar.ZONE_OFFSET);calendar.add(java.util.Calendar.MILLISECOND,-(zoneOffset+dstOffset));//时区对应时区calendar.setTimeZone(TimeZone.getTimeZone("GMT+5:00"));intdstOffset1=calendar.get(java.util.Calendar.DST_OFFSET);intzoneOffset1=calendar.get(Calendar.ZONE_OFFSET);calendar.add(java.util.Calendar.MILLISECOND,(zoneOffset1+dstOffset1));//时间计算calendar.add(Calendar.HOUR,15);//日期计算calendar.add(Calendar.DAY_OF_MONTH,-1);//时区计算calendar.add(Calendar.ZONE_OFFSET,3);//星期几intweek=calendar.get(Calendar.DAY_OF_WEEK);基于以上原因,java8重新提供了一组时间类,我们来看看相关类java8日期、时间常用类ZoneId地区Asia/Shanghai、Europe/ParisZoneOffset偏移数据+8:00Instant表示时间戳Duration表示时间间隔秒或纳秒Period表示一段时间的年月日,使用between()方法获取之间的时间两个日期的差值作为Period对象返回,LocalDate不包含具体时间日期,比如2014-01-14可以用来存储生日、周年纪念日、入职日期等。LocalTime表示没有日期的时间LocalDateTime它包含日期和时间,但仍然没有偏移量信息或时区。ZonedDateTime这是一个完整的日期时间,包括时区,偏移量基于UTC/格林威治标准时间。OffsetDateTime类实际上包括LocalDateTime和ZoneOffsetDateTimeFormatter日期的格式化和解析。与SimpleDateFormat不同,它是不可变的和线程安全的。TemporalAdjusters类包含许多常用的静态方法,以避免编写工具。操作示例ZoneIdzoneId=ZoneId.systemDefault();System.out.println(zoneId);//Asia/ShanghaiZoneOffsetzoneOffset=ZoneOffset.ofHours(8);System.out.println(zoneOffset);//+08:00Instantinstant=Instant.ofEpochSecond(LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8)));System.out.println(instant.getEpochSecond());//1605596559Durationduration=Duration.between(LocalDateTime.now(),LocalDateTime.now().plusHours(1));System.out.println(duration.getSeconds());//3600Periodperiod=Period.between(LocalDate.now(),LocalDate.now().plusDays(1));System.out.println(period.getDays());//1LocalDatedate=LocalDate.now();System.out.println(date);//2020-11-17LocalTimetime=LocalTime.now();System.out.println(time);//15:02:39.067LocalDateTimenow=LocalDateTime.now();System.out.println(now);//2020-11-17T15:02:39.06ZonedDateTimezonedDateTime=ZonedDateTime.of(LocalDateTime.now(),zoneId);System.out.println(zonedDateTime);//2020-11-17T15:02:39.067+08:00[亚洲/上海]OffsetDateTimeoffsetDateTime=OffsetDateTime.of(LocalDateTime.now(),ZoneOffset.ofHours(8));System.out.println(offsetDateTime);//2020-11-17T15:02:39.068+08:00Stringformat=DateTimeFormatter.ofPattern("yyyy-MM-ddHH:mm:ss").format(offsetDateTime);System.out.println(format);//2020-11-1715:02:39TemporalAdjustertemporalAdjuster=TemporalAdjusters.firstDayOfMonth();System.out.println(temporalAdjuster.adjustInto(LocalDate.now()));//2020-11-01特别说明ZoneId和ZoneOffset主要表示时区和偏移量。Instant表示时间戳Duration,Period表示时间差。前者代表时间差,后者代表日期差。LocalDate,LocalTime和LocalDateTime表示date,Time,Date+TimeZonedDateTime,OffsetDateTime带时区信息的Time内置方法
