Java 8 中新的时间与日期 API 中的所有类都是不可变且线程安全的,任何修改操作都会返回一个新的实例,而之前 java.util.Date、Calendar 以及 SimpleDateFormat 这些关键的类都不是线程安全的。
java 8 对 时间api 重新进行了设计,常用的有以下几种类。
/*** * LocalDate:表示不带时间的日期 * LocalTime:表示不带日期的时间 * LocalDateTime:日期和时间类 * ZoneId:时区 * ZonedDateTime:一个带时区的完整时间 * Instant:Unix 时间,它代表的是时间戳,比如 2018-01-14T02:20:13.592Z * Clock:获取某个时区下当前的瞬时时间,日期或者时间 * Duration:表示一个绝对的精确跨度,使用毫秒为单位 * Period:这个类表示与 Duration 相同的概念,但是以人们比较熟悉的单位表示,比如年、月、周 * DateTimeFormatter:格式化输出 * TemporalAdjusters:获得指定日期时间等,如当月的第一天、今年的最后一天等 * */
方法
/** * of:静态工厂方法,用于创建实例 * now:静态工厂方法,用当前时间创建实例 * parse:静态工厂方法,从字符串解析得到对象实例 * get:获取时间日期对象的部分状态。 * is:检查某些东西的是否是 true,例如比较时间前后 * with:返回一个部分状态改变了的时间日期对象拷贝 * plus:返回一个时间增加了的、时间日期对象拷贝 * minus:返回一个时间减少了的、时间日期对象拷贝 * to:转换到另一个类型 * at:把这个对象与另一个对象组合起来,例如 date.atTime(time) * format:提供格式化时间日期对象的能力 * */
/** *LocalDate */ //LocalDate 是用来表示无时间的日期的,也不附带任何与时区相关的信息 LocalDate today = LocalDate.now(); System.out.println("今日日期:"+ today); //它提供 plus()/minus() 方法可以用来增加减少日、星期或者月,ChronoUnit 则用来表示这个时间单位。 // 这些方法返回的是一个新的 LocalDate 实例的引用,因为 LocalTime 是不可变的, // 任何修改操作都会返回一个新的实例。 LocalDate localDate = today.plusDays(1); //等价于 today.plus(1, ChronoUnit.DAYS); System.out.println("明日日期:"+ localDate); //日期减法 LocalDate today1 = localDate.minus(1, ChronoUnit.DAYS); System.out.println("今日日期:" + today1);
LocalTime time = LocalTime.now(); System.out.println("现在的时间:" + time); //小时 int hour = time.getHour(); System.out.println(hour); OffsetTime offsetTime = time.atOffset(ZoneOffset.UTC); System.out.println("UTC时间: "+offsetTime); /** * */ //系统默认时间 LocalTime time2 = LocalTime.now(Clock.systemDefaultZone()); System.out.println("系统默认时间 : "+time2); LocalDate date =LocalDate.now(); //LocalDateTime 将 LocalDate 和 LocalTime 结合起来 LocalDateTime localDateTime = LocalDateTime.of(today,time2); System.out.println("LocalDateTime 将 LocalDate 和 LocalTime 结合起来 : " + localDateTime); // LocalDate localDate1 = LocalDate.of(2018, 11, 11); System.out.println("localDate1 自定义日期: " + localDate1); LocalTime localTime2 = LocalTime.of(12, 11, 11); LocalTime localTime3 = LocalTime.of(12, 12, 12, 12); System.out.println("LocalTime 自定义时间: " + localTime2); System.out.println("LocalTime 自定义时间带纳秒: " + localTime3);
格式化与解析时间对象 DateTimeFormatter 格式器用于解析日期字符串和格式化日期输出, 创建格式器最简单的方法是通过 DateTimeFormatter 的静态工厂方法以及常量。
//1 自定义字母模式解析 DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd"); String format = localDate1.format(dateTimeFormatter); System.out.println(format); //2 常用 ISO 格式常量,如 ISO_LOCAL_DATE dateTimeFormatter = DateTimeFormatter.ISO_DATE; format = localDate1.format(dateTimeFormatter); System.out.println(format); //3 本地化样式,如 ofLocalizedDate(FormatStyle.MEDIUM) dateTimeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL); format = localDate1.format(dateTimeFormatter); System.out.println("FormatStyle.FULL = "+ format);//2018年11月11日 星期日 dateTimeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM); format = localDate1.format(dateTimeFormatter); System.out.println("FormatStyle.MEDIUM = " + format);//2018-11-11 dateTimeFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG); format = localDate1.format(dateTimeFormatter); System.out.println("FormatStyle.LONG = "+ format);//2018-11-11 //将日期格式化指定格式 String format1 = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy,MM,dd")); System.out.println(format1);//2019,08,25
字符串格式化成日期
LocalDate parse = LocalDate.parse("2019-10-10"); System.out.println("默认: " + parse); //parse = LocalDate.parse("2019/8/10");//异常 /** 默认的解析格式是 - * public static final DateTimeFormatter ISO_LOCAL_DATE; * static { * ISO_LOCAL_DATE = new DateTimeFormatterBuilder() * .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) * .appendLiteral('-') * .appendValue(MONTH_OF_YEAR, 2) * .appendLiteral('-') * .appendValue(DAY_OF_MONTH, 2) * .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE); * } */ //System.out.println("默认: " + parse); //所以对于 "2019/8/10" 格式 我们需要自定义 解析格式 //注意 2019/08/10 不能写成 2019/8/10 ,不然会抛出异常 parse = LocalDate.parse("2019/08/10",DateTimeFormatter.ofPattern("yyyy/MM/dd")); System.out.println(parse); //2019-08-10 //自定义解析格式 dates = LocalDate.parse("20190825", DateTimeFormatter.ofPattern("yyyyMMdd")); System.out.println(dates);//2019-08-25 dates = LocalDate.parse("2019/08/25", DateTimeFormatter.ofPattern("yyyy/MM/dd")); System.out.println(dates);//2019-08-25 // 25/08/2019 - > 2019/08/25 LocalDate parse2 = LocalDate.parse("25/08/2019",DateTimeFormatter.ofPattern("dd/MM/yyyy")); String format2 = parse2.format(DateTimeFormatter.ofPattern("yyyy/MM/dd")); System.out.println(format2);//2019/08/25 LocalDate parse2 = LocalDate.parse("25/08/2019",DateTimeFormatter.ofPattern("dd/MM/yyyy")); System.out.println(parse2);//2019-08-25
Duration 表示一个时间段,Duration 包含两部分:seconds 表示秒,nanos 表示纳秒,它们的组合表达了时间长度。 因为 Duration 表示时间段,所以 Duration 类中不包含 now() 静态方法。注意,Duration 不包含毫秒这个属性。
LocalDateTime from =LocalDateTime.of(2019,8,11,11,11,11,11); LocalDateTime to =LocalDateTime.of(2019,8,10,10,10,10,10); Duration between = Duration.between(from, to); long l = between.toDays(); System.out.println("相差天数= " + l); // -1 long l1 = between.toHours(); System.out.println(l);// -1 long l2 = between.toMinutes(); System.out.println(l);// -1 long l3 = between.toMillis(); System.out.println(l);// -1 long l4 = between.toNanos(); System.out.println(l);// -1
Period 在概念上和 Duration 类似,区别在于 Period 是以年月日来衡量一个时间段。
Duration 用于计算两个时间间隔,Period 用于计算两个日期间隔,所以 between() 方法只能接收 LocalDate 类型的参数。
Period of1 = Period.of(2019, 10, 10); Period of2 = Period.of(2018, 9, 9); System.out.println(of1);//P2019Y10M10D LocalDate from1 =LocalDate.of(2019,8,11); LocalDate to2 =LocalDate.of(2018,8,10); Period between1 = Period.between(from1, to2); //Period 得到的是差值的绝对值 System.out.println("相差年 : " + between1.getYears());//-1 System.out.println("相差月 : " + between1.getMonths());//0 System.out.println("相差日 : " + between1.getDays());//-1 //计算两个时间的区间距离呢 long year = from1.until(to2, ChronoUnit.YEARS);//-1 long month = from1.until(to2, ChronoUnit.MONTHS);//-12 long month1 = to2.until(from1, ChronoUnit.MONTHS);//12 System.out.println(year); System.out.println(month); System.out.println("正值 " + month1);
//加1s Instant instant1 = Instant.ofEpochSecond(1); System.out.println(instant1);//1970-01-01T00:00:01Z //加10毫秒 Instant instant2 = Instant.ofEpochMilli(10); System.out.println(instant2);//1970-01-01T00:00:00.010Z //当前时间 从1970-1-1号到现在的时间 相当于new Date() Instant instant = Instant.now(); //秒 = 2019-08-24T14:49:36.344Z System.out.println(" 秒 = " + instant); //new Date()转为Instant Instant instant3 = new Date().toInstant(); System.out.println(" 与new Date()转换 " + instant3);//2019-08-24T14:57:07.464Z //解析时间 Instant parse1 = Instant.parse("2019-08-24T14:59:16.708Z"); System.out.println(parse1); //加10天 Instant plus = parse1.plus(10, ChronoUnit.DAYS); //2019-09-03T14:59:16.708Z System.out.println(plus);
Clock 是时钟系统,用于查找当前时刻。 你可以用它来获取某个时区下当前的日期或者时间。可以用 Clock 来替代旧的 System.currentTimeInMillis() 与 TimeZone.getDefault() 方法。
//世界协调时UTC Clock clock = Clock.systemUTC(); System.out.println(clock.getZone());// time-zone Z //获取clock对应的毫秒数,与System.currentTimeMillis()输出相同 System.out.println(clock.millis());// //通过Clock获取当前时刻 System.out.println("通过Clock获取当前时刻 " + clock.instant());// //默认时区时间 Clock clock1 = Clock.systemDefaultZone(); System.out.println(clock1.instant()); //自定义时区 Clock clock2 = clock1.withZone(ZoneId.of("Asia/Shanghai")); Instant instant4 = clock2.instant(); System.out.println(instant4); //纽约时间 Clock clock3 = Clock.system(ZoneId.of("America/New_York")); System.out.println("纽约时间: " + LocalDateTime.now(clock3)); //不能用 .instant() 输出 此输出是系统默认时间 //System.out.println(clock3.instant()); //当前时区加上 100s Clock offset = Clock.offset(clock, Duration.ofSeconds(100)); System.out.println(offset.instant());
//默认时区时间 ZonedDateTime now = ZonedDateTime.now(); LocalDate localDate2 = now.toLocalDate(); System.out.println(localDate2);//2019-08-24 //特定时区下的日期和时间 ZonedDateTime Shanghai = ZonedDateTime.of(LocalDateTime.now(), ZoneId.of("Asia/Shanghai")); System.out.println(Shanghai);//2019-08-24T23:22:31.149+08:00[Asia/Shanghai] ZonedDateTime Tokyo = ZonedDateTime.now(ZoneId.of("Asia/Tokyo")); System.out.println(Tokyo);//2019-08-25T00:26:51.690+09:00[Asia/Tokyo] ZoneId america = ZoneId.of("America/New_York"); System.out.println(ZonedDateTime.now(america));//2019-08-24T11:28:48.430-04:00[America/New_York]
有的时候,你需要进行一些更加复杂的日期操作,比如,将日期调整到下个周日、下个工作日,或者是本月的最后一天。这时,你可以使用重载版本的withXXX方法,向其传递一个提供了更多定制化选择的TemporalAdjuster对象, 更加灵活地处理日期。对于最常见的用例,日期和时间API已经提供了大量预定义的 TemporalAdjuster。你可以通过TemporalAdjuster类的静态工厂方法访问它们。
//当月中 第二周 的周一 TemporalAdjuster temporalAdjuster1 = TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.MONDAY); LocalDate with = LocalDate.now().with((temporal) -> temporal.with(temporalAdjuster1)); System.out.println(with);//2019-08-12 //firstDayOfMonth 当月的第一天 TemporalAdjuster temporalAdjuster2 = TemporalAdjusters.firstDayOfMonth(); with = LocalDate.now().with((temporal) -> temporal.with(temporalAdjuster2)); System.out.println(with);//2019-08-1 //firstDayOfNextYear 明年的第一天 System.out.println(LocalDate.now().with((temporal -> temporal.with(TemporalAdjusters.firstDayOfNextYear()))));//2020-01-01 /** * nextOrSame/previousOrSame 创建一个新的日期, * 并将其值设定为日期调整后或者调整前,第一个符合指定星 期几要求的日期,如果该日期已经符合要求,直接返回该对象 */ //今天是2019-08-25 周日 下一个周一 返回2019-08-26 System.out.println(LocalDate.now().with((temporal -> temporal.with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY)))));//2020-01-01 //返回下一个第一个满足的指定日期 也就是 周四 第一个是 2019-08-29 第二个是 2019-09-05 但是返回一个满足的。 System.out.println(LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.THURSDAY)));//2019-08-29
Date date1 = new Date(); System.out.println("current date: " + date1); ZonedDateTime zonedDateTime = date1.toInstant().atZone(ZoneId.systemDefault()); //Date -> LocalDate LocalDate localDate31 = zonedDateTime.toLocalDate(); System.out.println(localDate31);//2019-08-24 //Date -> LocalDate ZonedDateTime zonedDateTime3 = date1.toInstant().atZone(ZoneId.of("Asia/Shanghai")); LocalDate localDate32 = zonedDateTime3.toLocalDate(); System.out.println(localDate32);//2019-08-24 //Date -> LocalDateTime LocalDateTime localDateTime1 = zonedDateTime.toLocalDateTime(); //Date -> LocalDateTime 另一种方式 LocalDateTime localDateTime2 = LocalDateTime.ofInstant(date1.toInstant(), ZoneId.systemDefault()); //Date -> LocalTime LocalTime time1 = zonedDateTime.toLocalTime(); //Calendar --> Instant Calendar.getInstance().toInstant();
//LocalDateTime-> Date 方法 LocalDateTime localDateTime4 = LocalDateTime.now(); System.out.println("localDateTime: " + localDateTime4);//2019-08-24T23:44:23.274 //LocalDateTime-> Date 方法 Date from2 = Date.from(localDateTime4.toInstant(ZoneOffset.UTC)); Instant instant5 = from2.toInstant(); System.out.println(from2);//Sun Aug 25 07:44:23 CST 2019 System.out.println(instant5);//2019-08-24T23:44:23.274Z //// LocalDate -> Date LocalDate localDate3 = LocalDate.now(); //先把 LocalDate -> LocalDateTime LocalDateTime localDateTime3 = localDate3.atStartOfDay(); //再把 LocalDateTime -> Date Date from3 = Date.from(localDateTime3.toInstant(ZoneOffset.UTC)); System.out.println(from3);