一套新的时间API,放在java.time包下面
比之前的更加规范,并且解决了线程安全问题(最大区别)
线程安全问题
public class SimpleDateFormatTest { public static void main(String[] args) throws Exception { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); Callable<Date> task = new Callable<Date>() { @Override public Date call() throws Exception { return sdf.parse("20190105"); } }; ExecutorService pool = Executors.newFixedThreadPool(10); List<Future<Date>> results = new ArrayList<>(); for (int i = 0; i < 10; i++) { results.add(pool.submit(task)); } for (Future<Date> future : results) { System.out.println(future.get()); } } }
旧版本解决方案
public class DateFormatThreadLocal { private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>(){ @Override protected DateFormat initialValue() { return new SimpleDateFormat("yyyyMMdd"); } }; public static Date convert(String source) throws ParseException { return df.get().parse(source); } } public class SimpleDateFormatTest { public static void main(String[] args) throws Exception { Callable<Date> task = new Callable<Date>() { @Override public Date call() throws Exception { return DateFormatThreadLocal.convert("20190105"); } }; ExecutorService pool = Executors.newFixedThreadPool(10); List<Future<Date>> results = new ArrayList<>(); for (int i = 0; i < 10; i++) { results.add(pool.submit(task)); } for (Future<Date> future : results) { System.out.println(future.get()); } pool.shutdown(); } }
Java8 解决方案
使用LocalDate日期处理类
public class SimpleDateFormatTest { public static void main(String[] args) throws Exception { // Java8:DateTimeFormatter DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd"); // Java8:LocaleData Callable<LocalDate> task = new Callable<LocalDate>() { @Override public LocalDate call() throws Exception { return LocalDate.parse("20190105", dtf); } }; ExecutorService pool = Executors.newFixedThreadPool(10); List<Future<LocalDate>> results = new ArrayList<>(); for (int i = 0; i < 10; i++) { results.add(pool.submit(task)); } for (Future<LocalDate> future : results) { System.out.println(future.get()); } pool.shutdown(); } }
人读的时间
LocalDate、LocalTime、LocalDateTime的实例是不可变的的对象,分别表示ISO-8601日历系统(国际化标准组织制定的现代公民的日期和时间的表示法)的日期、时间、日期和时间,它们提供了简单的日期或时间,并不包含当前的时间和信息,和时区相关的信息。
这三者使用方法一样,LocalDateTime涵盖前两个
static void test1(){ // 使用LocalDateTime获取点前时间 LocalDateTime ldt = LocalDateTime.now(); // 输出当前时间 System.out.println(ldt); // 指定时间 LocalDateTime ldt2 = LocalDateTime.of(2019, 01, 05, 16, 07, 33); System.out.println(ldt2); // 日期运算,改变都会产生新实例 // 加两年 LocalDateTime ldt3 = ldt.plusYears(2); System.out.println(ldt3); // 减两年 LocalDateTime ldt4 = ldt.minusMonths(2); System.out.println(ldt4); // get方法,获取年月日等…… System.out.println(ldt.getYear()); System.out.println(ldt.getMonthValue()); System.out.println(ldt.getMonth().getValue()); }
机器读的时间
Instant时间戳:以UNIX元年:1970年1月1日00时00分00秒到某个时间之间的毫秒值
默认获取的时间是UTC时区的时间
static void test2(){ //Instant时间戳:以UNIX元年:1970年1月1日00时00分00秒到某个时间之间的毫秒值 Instant ins1 = Instant.now(); // 默认获取的是UTC时区 System.out.println(ins1); // 偏移运算 // ZoneOffset.ofHours(8) UTC-8相差8个时区 OffsetDateTime odt = ins1.atOffset(ZoneOffset.ofHours(8)); System.out.println(odt); // 转成毫秒时间 System.out.println(ins1.toEpochMilli()); // 偏移60秒 Instant ins2 = Instant.ofEpochSecond(60); System.out.println(ins2); }
计算间隔
Duration:计算两个“时间”之间的间隔
static void test3(){ // Duration:计算两个“时间”之间的间隔 Instant ins1 = Instant.now(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Instant ins2 = Instant.now(); Duration dration = Duration.between(ins1, ins2); // 毫秒输出 System.out.println(dration.toMillis()); System.out.println("--------------------"); LocalTime lt1 = LocalTime.now(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } LocalTime lt2 = LocalTime.now(); Duration dration2 = Duration.between(lt1, lt2); System.out.println(dration2.toMillis()); }
Period:计算两个“日期之间的间隔”
static void test4(){ // Period: 计算两个“日期”之间的间隔 LocalDate ld1 = LocalDate.of(2015, 1, 1); LocalDate ld2 = LocalDate.now(); Period period = Period.between(ld1, ld2); System.out.println(period); // 相差几年 System.out.println(period.getYears()); }
日期操纵
TemporalAdjuster:时间校正器。将时间调整到“下个周日”的操作,支持lambda语法
TemporalAdjusters:为TemporalAdjuster接口产生实例,该类通过静态方法提供了大量的常用TemporalAdjuster实现
static void test5(){ //TemporalAdjuster:时间校正器 LocalDateTime ldt = LocalDateTime.now(); System.out.println(ldt); // 当前月中的天指定成10日 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 ldt4 = (LocalDateTime) l; // 获取周几 DayOfWeek dow = ldt4.getDayOfWeek(); if(dow.equals(DayOfWeek.FRIDAY)){ return ldt4.plusDays(3); } else if(dow.equals(DayOfWeek.SATURDAY)) { return ldt4.plusDays(2); } else{ return ldt.plusDays(1); } }); System.out.println("下个工作日"); System.out.println(ldt5); }
格式化时间/日期
DateTimeFormatter:格式化时间/日期
static void test6(){ // DateTimeFormatter 格式化时间/日期 DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE; LocalDateTime ldt = LocalDateTime.now(); String strDate = ldt.format(dtf); System.out.println(strDate); System.out.println("------------------------"); DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss"); String strDate2 = dtf2.format(ldt); System.out.println(strDate2); System.out.println("------------------------"); // 将字符串解析成时间日期 LocalDateTime newDate = LocalDateTime.parse(strDate2, dtf2); System.out.println(newDate); }
时区的处理
ZondDate、ZondTime、ZondDateTime其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式,例如:Asia/Shanghai等
ZondId:该类包含了所有的时区信息
getAvailableZondIds():可以获取所有时区信息
of(id):用指定的时区信息获取ZoneId对象
static void test7(){ // 获取所有时区信息 Set<String> set = ZoneId.getAvailableZoneIds(); set.forEach(System.out::println); } static void test8(){ //ZondDate、ZondTime、ZondDateTime // 获取指定时区时间 LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Europe/Podgorica")); System.out.println(ldt); //带时区的日期时间格式 LocalDateTime ldt2 = LocalDateTime.now(ZoneId.of("Asia/Shanghai")); ZonedDateTime zdt = ldt2.atZone(ZoneId.of("Asia/Shanghai")); System.out.println(zdt); }