JDK 1.8 新特性之Date-Time API
原文:点击查看
1.8之前的日期类:
- 线程不安全:java.util.Date 这个类线程不安全,而且所有日期类都是可变的。
- 时间处理麻烦:默认的开始日期从1900年,不支持国际化,不提供时区支持,所以经常算出来的时间不是中国时间。
- 设计不好:java初学者接触到导包的时候,总会导错包,比如java.util和java.sql包中都有日期类,类名却是一样的。
日期和时间
Instant 本质上是一个数字时间戳。可以从a中检索当前的Instant Clock。这对于某个时间点的日志记录和持久性非常有用。
LocalDate 没有时间存储日期。存储类似“2010-12-03”的日期,可用于存储生日。
LocalTime 没有日期存储时间。存储像'11:30'这样的时间,可用于存储开盘或收盘时间。
LocalDateTime 存储日期和时间。这会存储类似'2010-07-23T15:47:25.890'的日期时间。
ZonedDateTime 使用时区存储日期和时间。如果您想要考虑到日期和时间的准确计算ZoneId,例如“欧洲/巴黎”,这将非常有用。在可能的情况下,建议使用没有时区的更简单的类。时区的广泛使用往往会给应用程序增加相当大的复杂性
其他类型
Month 用来存储一个月。这样可以隔离单个月份,例如“DECEMBER”。
DayOfWeek 用来存储一个星期的日子。这样可以隔离存储一个星期几,例如“星期二”。
Year 用来存储一年。这样可以隔离一年,例如'2010'。
YearMonth 用来存储年加月份的时间。这会存储一年和一个月,例如“2010-12”,并可用于信用卡到期。
MonthDay 用来存储月份和日子。它存储月份和日期,例如“12-03”,可用于存储年度活动,如生日,而不存储年份。
注
在连接数据库的时候,使用 Java 8 新特性 TimeDateAPI,字段对应不上,或者存入的不是时间,或者直接抛异常,请更新对应数据库的 pom 依赖,添加以下支持
Spring Data API
<!--java 8 time date 支持--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-java8</artifactId> <version>5.0.12.Final</version> </dependency>
MyBatis
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-typehandlers-jsr310</artifactId> <version>1.0.1</version> </dependency>
Instant
这个类是不可变的,线程安全。
public class InstantDemo { public static void main(String[] args) { //=============================================================================== // 1、获取当前时间戳 //=============================================================================== System.out.println(Instant.now()); // 2018-07-23T07:57:00.821Z //=============================================================================== // 2、传入CharSequence类型,转换为instant对象 //=============================================================================== CharSequence text = "2010-10-31T07:57:00.821Z"; Instant instant = Instant.parse(text); System.out.println(instant); // 2010-10-31T07:57:00.821Z // 注意:格式不正确或者不存在该日期时,会抛出DateTimeParseException异常 //=============================================================================== // 3、比较时间(大于小于排序) //=============================================================================== System.out.println(instant.isAfter(Instant.parse("2010-11-30T07:57:00.821Z"))); // false 返回布尔值 System.out.println(instant.isBefore(Instant.parse("2010-11-30T07:57:00.821Z"))); // true 返回布尔值 System.out.println(instant.compareTo(Instant.parse("2010-11-30T07:57:00.821Z"))); // -1 compareTo 返回值int类型 等于返回 0 小于返回 -1 大于返回 1 System.out.println(instant.equals(Instant.parse("2010-10-31T07:57:00.821Z"))); // true 返回布尔值 比较两个时间是否相等 //=============================================================================== // 4、获取从1970-01-01T00:00:00Z到现在的秒数 //=============================================================================== System.out.println(instant.getEpochSecond()); // 1288511820 // 返回值long,注意返回的是秒!不是毫秒! //=============================================================================== // 5、设置时区偏移 //=============================================================================== OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8)); System.out.println(offsetDateTime); // 2010-10-31T15:57:00.821+08:00 // 返回值类型OffsetDateTime 我们在东八区,所以加上八小时,就是本地时间戳 } }
LocalDate
LocalDate是一个不可变的类,它表示默认格式(yyyy-MM-dd)的日期,线程安全。
public class LocalDateDemo { public static void main(String[] args) { //=============================================================================== // 1、获取当前日期 //=============================================================================== LocalDate localDate = LocalDate.now(); System.out.println(localDate); // 2018-07-23 //=============================================================================== // 2、构造LocalDate //=============================================================================== CharSequence text = "2010-10-10"; System.out.println(LocalDate.parse(text)); // 2010-10-10 CharSequence date = "20101010"; System.out.println(LocalDate.parse(date,DateTimeFormatter.BASIC_ISO_DATE));// 2010-10-10 // 自定义对应格式的转换,JDK1.8给出了预定义的格式化 DateTimeFormatter.BASIC_ISO_DATE 就是其中之一 CharSequence myDate = "2010年10月10日"; System.out.println(LocalDate.parse(myDate,DateTimeFormatter.ofPattern("yyyy年MM月dd日"))); // 2010-10-10 // 预定义格式没有的情况,也可以自定义 System.out.println(LocalDate.of(2010, 10, 10));// 2010-10-10 // 给出int类型对应的 年月日,亦可构造出LocalDate对象 System.out.println(LocalDate.of(2010, Month.JULY, 10));// 2010-07-10 // 月份亦可给出对应 Mouth 枚举 System.out.println(LocalDate.ofEpochDay(123)); // 1970-05-04 // 给出日子,计算出 从 1970-01-01 对应日子后的日期 System.out.println(LocalDate.ofYearDay(2010, 163)); //2010-06-12 // 传入 年,日数,计算出 对应该年份 对应日子后的日期 //=============================================================================== // 3、获取,年,月,日 //=============================================================================== System.out.println(localDate.getMonth()); // JULY 返回英文月份,对应 Mouth 枚举 System.out.println(localDate.getMonthValue()); // 7 返回数字月份 System.out.println(localDate.getYear()); // 2018 返回对应年 System.out.println(localDate.getDayOfMonth()); // 23 返回对应月份中的日子 System.out.println(localDate.getDayOfWeek()); // MONDAY 返回对应星期,对应 DayOfWeek 枚举 System.out.println(localDate.getDayOfYear()); // 204 返回对应年份中的日子 System.out.println(localDate.lengthOfMonth()); // 31 对应该月份有多少天 System.out.println(LocalDate.parse("2004-02-10").lengthOfMonth()); // 29 证明可以自动判断是否为闰年!!! System.out.println(localDate.lengthOfYear()); // 365 对应年份有多少天 System.out.println(LocalDate.parse("2004-02-10").lengthOfYear()); // 366 证明可以自动判断是否为闰年!!! //=============================================================================== // 4、判断大于小于,排序,判断是否闰年 //=============================================================================== System.out.println(localDate.compareTo(LocalDate.parse("2000-01-01"))); // 18 // 这里的 compareTo 方法为什么返回 18 请看下面详解!!! System.out.println(localDate.isAfter(LocalDate.parse("2000-01-01"))); // true System.out.println(localDate.isBefore(LocalDate.parse("2000-01-01"))); // false System.out.println(localDate.isEqual(LocalDate.parse("2000-01-01"))); // false System.out.println(localDate.isLeapYear());// false 返回布尔值,该年是否为闰年 //=============================================================================== // 5、日期的加减 //=============================================================================== System.out.println(localDate.plusMonths(1)); // 2018-08-23 加一个月 System.out.println(localDate.plusMonths(-1)); // 2018-06-23 减去一个月,传入负数即可,下面的也是 System.out.println(localDate.plusDays(1)); // 2018-07-24 加上一天 System.out.println(localDate.plusMonths(1)); // 2018-08-23 加上一个月 System.out.println(localDate.plusWeeks(1)); // 2018-07-30 加上一个星期 //=============================================================================== // 6、其他计算 //=============================================================================== System.out.println(localDate.withDayOfYear(123)); // 2018-05-03 计算当前年第123天的日期 } }
LocalTime
LocalTime是一个不可变的日期时间对象,代表一个时间,通常被看作是小时 - 秒,这个类不可变,线程安全。
public class LocalTimeDemo { public static void main(String[] args) { //=============================================================================== // 1、获取当前时间 //=============================================================================== LocalTime time1 = LocalTime.now(); System.out.println(time1); // 09:39:47.275 //=============================================================================== // 2、构造LocalTime //=============================================================================== // 根据传入文本构造LocalTIme时间对象,格式不正确会抛出 java.time.format.DateTimeParseException 异常 CharSequence text1 = "22:22:22"; LocalTime localTime1 = LocalTime.parse(text1); System.out.println(localTime1); // 22:22:22 // 传入自定义文本,自定义格式化 构造 LocalTime 对象 CharSequence text2 = "11-11-11"; DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH-mm-ss"); LocalTime localTime2 = LocalTime.parse(text2, dateTimeFormatter); System.out.println(localTime2); // 11:11:11 // 根据入参 时,分,秒,纳秒构造出LocalTime对象,24小时制 // 如果入参不符合时间要求,例如传入25小时,61分钟,会抛出 java.time.DateTimeException 异常 LocalTime time2 = LocalTime.of(13, 22); System.out.println(time2); // 13:22 LocalTime time3 = LocalTime.of(14, 22, 31); System.out.println(time3); // 14:22:31 LocalTime time4 = LocalTime.of(22, 43, 33, 422); System.out.println(time4); // 22:43:33.000000422 // 根据分钟 构造 LocalTime 时间对象 超过最大分钟,会抛出 java.time.DateTimeException 异常 LocalTime time5 = LocalTime.ofSecondOfDay(22324); System.out.println(time5); // 06:12:04 // 根据纳秒构造LocalTime对象 LocalTime time6 = LocalTime.ofNanoOfDay(1231); System.out.println(time6); // 00:00:00.000001231 //=============================================================================== // 3、获时,分,秒等 //=============================================================================== int hour = time1.getHour(); int minute = time1.getMinute(); int second = time1.getSecond(); System.out.println("小时:" + hour + ",分钟:" + minute + ",秒数:" + second); // 小时:10,分钟:5,秒数:53 //=============================================================================== // 4、判断大于小于,排序,相差多少 //=============================================================================== // 判断时间1是否在时间2后 boolean after = time1.isAfter(time2); System.out.println(after); // false // 判断时间1是否在时间2前 boolean before = time1.isBefore(time2); System.out.println(before); // true // 排序比较,前者大于后者返回 1,否则 -1,相等 0 int i = time1.compareTo(time2); System.out.println(i); // -1 // 时间1和时间2相差多少小时,分钟,秒,大于为正数,小于为负数(坏处就是分跟分加减,秒跟秒加减) long betweenHours = ChronoUnit.HOURS.between(time1, time2); long betweenSeconds = ChronoUnit.SECONDS.between(time1, time2); long betweenMinutes = ChronoUnit.MINUTES.between(time1, time2); System.out.println("相差小时:" + betweenHours + " 分钟: " + betweenMinutes + " 秒数:" + betweenSeconds); // 相差小时:2 分钟: 178 秒数:10707 //=============================================================================== // 5、时间的加减,修改 //=============================================================================== // 加两小时,减去传入负数即可 LocalTime time7 = time3.plusHours(2); System.out.println(time7); // 16:22:31 // 减去10分钟 LocalTime time8 = time3.plusMinutes(-10); System.out.println(time8); // 14:12:31 // 加上30秒 LocalTime time9 = time3.plusSeconds(30); System.out.println(time9); // 14:23:01 // 修改小时 LocalTime time10 = time3.withHour(23); System.out.println(time10); // 23:22:31 // 修改分钟 LocalTime time11 = time3.withMinute(11); System.out.println(time11); // 14:11:31 // 修改秒数 LocalTime time12 = time3.withSecond(50); System.out.println(time12); // 14:22:50 //=============================================================================== // 6、两个时间之间的相差秒数,小时 //=============================================================================== Duration duration = Duration.between(time3, time12); long days = duration.toDays(); long hours = duration.toHours(); long millis = duration.toMillis()/1000; } }
LocalDateTime
是一个不可变的日期时间对象,代表日期时间,年-月-日-时-分-秒,线程安全
public class LocalDateTimeDemo { public static void main(String[] args) { //=============================================================================== // 1、获取当前日期时间 //=============================================================================== LocalDateTime localDateTime = LocalDateTime.now(); System.out.println(localDateTime); // 2018-07-26T14:47:44.144 //=============================================================================== // 2、构造日期时间 //=============================================================================== CharSequence text = "2007-12-03T10:15:30"; // 从一个文本字符串 获得 LocalDateTime实例 LocalDateTime dateTime1 = LocalDateTime.parse(text); System.out.println(dateTime1); // 2007-12-03T10:15:30 //=============================================================================== // 3、获取,年,月,日,时等等 //=============================================================================== int dayOfMonth = localDateTime.getDayOfMonth(); DayOfWeek dayOfWeek = localDateTime.getDayOfWeek(); int dayOfYear = localDateTime.getDayOfYear(); int hour = localDateTime.getHour(); Month month = localDateTime.getMonth(); int year = localDateTime.getYear(); System.out.println(year + "年" + month.toString() + "月" + dayOfMonth + "日" + hour + "时" + "|||" + dayOfWeek + "|||" + dayOfYear); // 2018年JULY月31日9时|||TUESDAY|||212 } }
YearMonth
是一个不变的日期时间对象,表示一年和一个月的组合。 可以获得可以从年和月派生的任何字段,例如四分之一年份。类线程安全
public class YearMonthDemo { public static void main(String[] args) { //=============================================================================== // 1、获取当前年月 //=============================================================================== YearMonth yearMonth = YearMonth.now(); System.out.println(yearMonth); // 2018-07 //=============================================================================== // 2、构造年月 //=============================================================================== CharSequence text = "2018-01"; YearMonth yearMonth1 = YearMonth.parse(text); System.out.println(yearMonth1); // 2018-01 CharSequence text2 = "2018年02月"; YearMonth yearMonth2 = YearMonth.parse(text2, DateTimeFormatter.ofPattern("yyyy年MM月")); System.out.println(yearMonth2); // 2018-02 //=============================================================================== // 3、获取,年,月 //=============================================================================== int year = yearMonth.getYear(); Month month = yearMonth.getMonth(); int monthValue = yearMonth.getMonthValue(); System.out.println(year + "年" + monthValue + "月" + "mouth对象-》" + month); // 2018年7月mouth对象-》JULY //=============================================================================== // 4、判断大于小于,排序,判断是否闰年 //=============================================================================== System.out.println(yearMonth.isAfter(yearMonth1)); // true System.out.println(yearMonth.isBefore(yearMonth1)); // false System.out.println(yearMonth.isLeapYear()); // 是否闰年 false System.out.println(yearMonth.compareTo(yearMonth1)); // 6 (这里为什么是6 上面有详解) //=============================================================================== // 5、年月的加减,设置年月 //=============================================================================== YearMonth yearMonth3 = yearMonth.plusMonths(1); System.out.println(yearMonth3); // 2018-08 YearMonth yearMonth4 = yearMonth.plusYears(-1); System.out.println(yearMonth4); // 2017-07 YearMonth yearMonth5 = yearMonth.withMonth(5); System.out.println(yearMonth5); // 2018-05 YearMonth yearMonth6 = yearMonth.withYear(2000); System.out.println(yearMonth6); // 2000-07 } }
MonthDay
是一个不变的日期时间对象,代表一年和一个月的组合。 可以获得可以从月和日派生的任何字段,线程安全。
public class MonthDayDemo { public static void main(String[] args) { //=============================================================================== // 1、获取当前月日 //=============================================================================== MonthDay monthDay = MonthDay.now(); System.out.println(monthDay); // --07-31 //=============================================================================== // 2、构造月日 //=============================================================================== CharSequence text1 = "--03-01"; MonthDay monthDay1 = MonthDay.parse(text1); System.out.println(monthDay1); // --03-01 CharSequence text2 = "11月23日"; MonthDay monthDay2 = MonthDay.parse(text2, DateTimeFormatter.ofPattern("MM月dd日")); System.out.println(monthDay2); // --11-23 MonthDay monthDay3 = MonthDay.of(2, 3); System.out.println(monthDay3); // --02-03 MonthDay monthDay4 = MonthDay.of(Month.AUGUST, 22); System.out.println(monthDay4); // --08-22 //=============================================================================== // 3、获取 月,日 //=============================================================================== int monthValue = monthDay.getMonthValue(); Month month = monthDay.getMonth(); int dayOfMonth = monthDay.getDayOfMonth(); System.out.println(monthValue + "月" + dayOfMonth + "日" + "月份-》" + month); // 7月31日月份-》JULY //=============================================================================== // 4、判断大于小于,排序 //=============================================================================== System.out.println(monthDay.isAfter(monthDay1)); // true System.out.println(monthDay.isBefore(monthDay1)); // false System.out.println(monthDay.compareTo(monthDay1)); // 4 (这里为什么是4,上面有详解) } }
常见需求
public class NewTimeDemo { public static void main(String args[]) { // 输入 20180101 CharSequence str = "20040201"; // BASIC_ISO_DATE -》ISO日期格式化,格式或解析无偏移的日期,如“20111203”。 LocalDate localDate = LocalDate.parse(str, BASIC_ISO_DATE); //=============================================================================== // 1、 这个月月末 //=============================================================================== System.out.println("本月月末是:" + localDate.with(TemporalAdjusters.lastDayOfMonth())); // 本月月末是:2004-02-29 //=============================================================================== // 2、 下个月月初 //=============================================================================== System.out.println("下月月初是:" + localDate.with(TemporalAdjusters.firstDayOfNextMonth())); //下月月初是:2004-03-01 //=============================================================================== // 3、 下个月月末 //=============================================================================== System.out.println("下月月末是:" + localDate.with(TemporalAdjusters.firstDayOfNextMonth()) .with(TemporalAdjusters.lastDayOfMonth())); // 下月月末是:2004-03-31 //=============================================================================== // 4、 给年月,计算当月天数 //=============================================================================== CharSequence str2 = "200102"; DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMM"); YearMonth ym = YearMonth.parse(str2, dateTimeFormatter); System.out.println(ym.lengthOfMonth()); // 28 //=============================================================================== // 5、 日期加减天数 //=============================================================================== System.out.println(localDate.plusDays(-1)); // 2004-01-31 //=============================================================================== // 6、 日期加减月份 //=============================================================================== System.out.println(localDate.plusMonths(-1)); // 2004-01-01 System.out.println(localDate.plusMonths(1)); // 2004-03-01 //=============================================================================== // 7、 传参月份,日子,输出修改后的 //=============================================================================== try { System.out.println(localDate.withMonth(2).withDayOfMonth(2)); // 2004-02-02 } catch (DateTimeException exception) { System.out.println("输入日期异常!"); } System.out.println(localDate.withDayOfMonth(1)); // 2004-02-01 //=============================================================================== // 8、 小于15日,输出该月15日,否则输出下月1日 //=============================================================================== System.out.println("--------------------"); if (localDate.getDayOfMonth() < 15) { System.out.println(localDate.withDayOfMonth(15)); } else { System.out.println(localDate.with(TemporalAdjusters.firstDayOfNextMonth())); } // 2004-02-15 } }