1, 前言
Java8 之前处理日期一直是 Java 程序员比较头疼的问题, 从 Java 8 之后, Java 里面添加了许多的新特性, 其中一个最常见也是最实用的便是日期处理的类 --LocalDate.LocalDate 是一种更为高效的日期类, 比起 Date 的复杂具有相当高的简洁性, 吸取了企业级别的 joda.time 时间处理的优点, 避免了传统的 Date 和 Calendar 复合起来计算的难处.
新增的日期常用的用这三个:
java.time.LocalDate: 只对年月日做出处理
java.time.LocalTime: 只对时分秒纳秒做出处理
java.time.LocalDateTime : 同时可以处理年月日和时分秒
2,LocalDate,LocalTime,LocalDateTime
LocalDate: 代表 iOS 格式 (yyyy-MM-hh) 的日期, 不包含具体时间的日期, 比如 2014-01-14. 它可以用来存储生日, 周年纪念日, 入职日期等.
LocalTime: 它代表的是不含日期的时间;
LocalDateTime: 它包含了日期及时间, 不过还是没有偏移信息或者说时区, 比较常用;
它们三者共同特点:
相比于前面的 Date 和 Calendar, 他们是线程安全的;
它们是不可变的日期时间对象;
常用方法:
now() , now(Zoneld zone): 静态方法, 根据当前时间创建对象 , 指定时区的对象
of() : 静态方法, 根据指定日期, 时间创建对象
getDayOfMonth(): 获得月份天数(1-31)
getDayOfYear(): 获取年份天数(1-366)
getDayOfWeek(): 获得星期几
getYear(): 获得年份
getMonth() , getMonthValue(): 获得月份(返回枚举值如: January) , 返回数字(1-12)
getHour(),getMinute(),getSecond(): 获得当前对象的时, 分, 秒
withDayOfMonth(),withDayOfYear(),withMonth(),withYear(): 将月份天数, 年份天数, 月份, 年份修改为指定的值并且返回新的对象, 因为 LocalDate 等是不变性的
plusDays(),plusWeeks(),plusMonths(),plusYears(),plusHours(): 向当前对象添加几天, 几周, 几个月, 几年, 几小时
minusDays(),minusWeeks(),minusMonths(),minusYears(),minusHours(): 从当前对象减去几月, 几周, 几个月, 几年, 几小时
isLeapYear(): 判断是否为闰年
isBefore,isEqual,isAfter: 检查日期是否在指定日期前面, 相等, 后面
由于 LocalDate 的 API 与 LocalTime,LocalDateTime 大都是通用的, 所有后面两个的就不展示了.
方法使用举例:
- //now(): 获取当前日期
- LocalDate localDate=LocalDate.now();
- LocalTime localTime=LocalTime.now();
- LocalTime localTime1= LocalTime.now().withNano(0); // 这个是不带毫秒的
- LocalDateTime localDateTime=LocalDateTime.now();
- System.out.println("日期:"+localDate);
- System.out.println("时间:"+localTime);
- System.out.println("时间不带毫秒:"+localTime1);
- System.out.println("日期时间:"+localDateTime);
- //of(): 设置指定的年月日时分秒, 没有偏移量
- System.out.println("-----------");
- LocalDateTime localDateTime2=LocalDateTime.of(2020, 04, 04, 18, 48, 56);
- System.out.println("设置的时间为:"+localDateTime2);
- //getXXX: 获取相关的属性
- System.out.println("-----------");
- System.out.println("这年的第几天:"+localDateTime.getDayOfYear());
- System.out.println("这月的第几天:"+localDateTime.getDayOfMonth());
- System.out.println("这月的第几天:"+localDateTime.getDayOfWeek());
- System.out.println("月份为:"+localDateTime.getMonth());
- System.out.println("月份为:"+localDateTime.getMonthValue());
- System.out.println("小时为:"+localDateTime.getHour());
- //withXXX: 设置相关的属性, 体现了不可变性, 修改后返回了新的对象
- LocalDateTime localDateTime3=localDateTime.withDayOfMonth(22);
- System.out.println("当前的时间:"+localDateTime);
- System.out.println("修改月份后:"+localDateTime3);
- LocalDateTime localDateTime4=localDateTime.withHour(14);
- System.out.println("当前的时间:"+localDateTime);
- System.out.println("修改小时后:"+localDateTime4);
- //plusXXX: 增加相关属性
- LocalDateTime localDateTime5=localDateTime.plusDays(10);
- System.out.println("当前时间:"+localDateTime);
- System.out.println("相加之后:"+localDateTime5);
- //minusXXX: 减少相关属性
- LocalDateTime localDateTime6=localDateTime.minusDays(10);
- System.out.println("当前时间:"+localDateTime);
- System.out.println("相减之后:"+localDateTime6);
LocalDate ,LocalTime ,LocalDateTime 它们之间的互相转换:
- /**
- * LocalDate ,LocalTime,LocalDateTime 互相转换
- */
- @Test
- public void test5(){
- String date = "2020-7-12";
- String time = "15:51:30";
- LocalDate localDate = LocalDate.parse(date);
- LocalTime localTime = LocalTime.parse(time);
- LocalDateTime localDateTime = LocalDateTime.of(2020, 7, 13, 16, 01, 30, 888);
- LocalDateTime localDateTime1 = LocalDateTime.of(localDate, localTime);
- //localDateTime-->LocalDate,LocalTime
- LocalDate localDate1 = localDateTime.toLocalDate();
- LocalTime localTime1 = localDateTime.toLocalTime();
- // LocalDate,LocalTime --> LocalDateTime
- LocalDateTime localDateTime2 = localDate.atTime(16, 02, 30);
- LocalDateTime localDateTime3 = localTime.atDate(localDate);
- }
3, 瞬时(Instant)
Instant 类: 时间线上的一个瞬时点, 设计初衷是为了便于机器使用, 不提供人类意义上的时间单位, 获取当前时刻的时间戳; 它只是简单的从 1970 年 1 月 1 日 0 时 0 分 0 秒 (UTC) 开始的秒数.
常用方法:
now(): 静态方法, 返回默认的 UTC 时区的 Instant 类的对象
atOffset(ZoneOffset offset): 将此瞬间与偏移组合起来创建一个 OffsetDateTime
toEpochMilli(): 返回 1970-01-01 00:00:00 到当前的毫秒数, 即时间戳
ofEpochMilli(long epochMilli): 静态方法, 返回在 1970-01-01 00:00:00 基础加上指定毫秒数之后的 Instant 类的对象
ofEpochSecond(long epochSecond): 静态方法, 返回在 1970-01-01 00:00:00 基础加上指定秒数之后的 Instant 类的对象
方法使用举例:
- @Test
- public void testInstant() {
- //now(): 获取标准时间, 即本初子午线的时间, 没有偏移量
- Instant instant = Instant.now();
- System.out.println(instant);
- //atOffset: 添加偏移量, 北京在东八区, 时区加八即为北京时间
- OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
- System.out.println(offsetDateTime);
- //toEpochMilli: 获取 1970-01-01 00:00:00 开始的毫秒; 类似 Date 的 getTime
- long epochMilli = instant.toEpochMilli();
- System.out.println(epochMilli);
- //ofEpochMilli: 通过给定的毫秒数, 获取 Instant 实例; 类似 Date(long millis)
- Instant ofEpochMilli = Instant.ofEpochMilli(1562384592201L);
- System.out.println(ofEpochMilli);
- }
4, 日期间隔, 持续时间 (Period 和 Duration)
Java 8 中还引入的两个与日期相关的新类: Period 和 Duration. 两个类分别表示时间量或两个日期之间的差, 两者之间的差异为: Period 基于日期值, 而 Duration 基于时间值.
实例:
- @Test
- public void testDurationAndPeriod(){
- //Duration
- LocalDate date1 = LocalDate.of(2020, 7, 6);
- LocalDate date2 = LocalDate.of(2025, 9, 10);
- LocalTime time1 = LocalTime.of(15, 7, 50);
- LocalTime time2 = LocalTime.of(17, 8, 53);
- LocalDateTime dateTime1 = LocalDateTime.of(2020, 5, 12, 14, 22, 28);
- LocalDateTime dateTime2 = LocalDateTime.of(2024, 5, 12, 14, 22, 28);
- Instant instant1 = Instant.ofEpochSecond(1);
- Instant instant2 = Instant.now();
- Duration d1 = Duration.between(time1, time2);
- Duration d2 = Duration.between(dateTime1, dateTime2);
- Duration d3 = Duration.between(instant1, instant2);
- // 这里会抛异常 java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds
- // 需要使用 Period 类进行操作日期
- //Duration d4 = Duration.between(date1, date2);
- System.out.println("LocalTime 持续秒数:" + d1.getSeconds());
- System.out.println("LocalDateTime 持续秒数:" + d2.getSeconds());
- System.out.println("Instant 持续秒数" + d3.getSeconds());
- //Period
- Period period=Period.between(date1, date2);
- System.out.println(period.getYears());
- System.out.println(period.getMonths());
- System.out.println(period.getDays());
- System.out.println(period.toTotalMonths());
- }
5, 日期校正器 TemporalAdjusters
到现在你所看到的所有日期操作都是相对比较直接的. 有的时候, 你需要进行一些更加 复杂的操作, 比如, 将日期调整到下个周日, 下个工作日, 或者是本月的最后一天. 这时, 你可以使用重载版本的 with 方法, 向其传递一个提供了更多定制化选择的 TemporalAdjusters 对象, 更加灵活地处理日期. 对于最常见的用例, 日期和时间 API 已经提供了大量预定义的 TemporalAdjusters. 你可以通过 TemporalAdjusters 类的静态工厂方法访问它们, 如下所示:
下面是 TemporalAdjusters 类中的方法:
dayOfWeekInMonth(int ordinal,DayOfWeek dayOfWeek): 返回一个新的日期, 它的值为同一个月中每一周的第几天
firstDayOfMonth(): 返回一个新的日期, 它的值为当月的第一天
firstDayOfNextMonth(): 返回一个新的日期, 它的值为下月的第一天
firstDayOfNextYear(): 返回一个新的日期, 它的值为明年的第一天
firstDayOfYear(): 返回一个新的日期, 它的值为当年的第一天
firstInMonth(DayOfWeek dayOfWeek): 返回一个新的日期, 它的值为同一个月中, 第一个符合星期几要求的值
lastDayOfMonth(): 返回一个新的日期, 它的值为当月的最后一天
lastDayOfNextMonth(): 返回一个新的日期, 它的值为下月的最后一天
lastDayOfNextYear(): 返回一个新的日期, 它的值为明年的最后一天
lastDayOfYear(): 返回一个新的日期, 它的值为今年的最后一天
lastInMonth(DayOfWeek dayOfWeek): 返回一个新的日期, 它的值为同一个月中, 最后一个符合星期几要求的值
next(DayOfWeek dayOfWeek),previous(DayOfWeek dayOfWeek): 返回一个新的日期, 并将其值设定为日期调整后或者调整前, 第一个符合指定星期几要求的日期
nextOrSame(DayOfWeek dayOfWeek),previousOrSame(DayOfWeek dayOfWeek): 返回一个新的日期, 并将其值设定为日期调整后或者调整前, 第一个符合指定星期几要求的日期, 如果该日期已经符合要求, 直接返回该对象
方法使用举例:
- @Test
- public void testTemporalAdjusters(){
- //dayOfWeekInMonth: 返回这个月第二周星期二的日期
- LocalDate localDate1=LocalDate.of(2020,9,15);
- LocalDate localDate2 = localDate1.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.TUESDAY));
- System.out.println("默认时间:"+localDate1);
- System.out.println("更改时间:"+localDate2);
- //firstDayOfMonth(): 这个月第一天
- System.out.println("---------");
- LocalDate localDate3=localDate1.with(TemporalAdjusters.firstDayOfMonth());
- System.out.println("默认时间:"+localDate1);
- System.out.println("更改时间:"+localDate3);
- //lastDayOfMonth(): 这个月最后一天
- System.out.println("---------");
- LocalDate localDate4=localDate1.with(TemporalAdjusters.lastDayOfMonth());
- System.out.println("默认时间:"+localDate1);
- System.out.println("更改时间:"+localDate4);
- //nextOrSame(): 获取周 2 时间, 如果当前时间刚好是星期 2, 那么就返回当前时间
- System.out.println("---------");
- LocalDate localDate5 = localDate1.with(TemporalAdjusters.nextOrSame(DayOfWeek.TUESDAY));
- System.out.println("默认时间:"+localDate1);
- System.out.println("更改时间:"+localDate5);
- }
运行结果:
6,Java 8 日期解析和格式化(DateTimeFormatter)
之前格式化有 SimpleDateFormat 和 DateFormat, 但是它们两者都是线程不安全的! 啥情况下会有这样的问题呢? 如果我们为了实现日期转换这样的工具, 每次都 new 一个对象, 但是用完了就不用了, 就造成了浪费, 为此我们会将它写成单例的, 但是单例的同时, 一个对象供多个线程使用的时候, 就会出现线程安全的问题. 这个时候就需要这个新的 jdk8 出的 DateTimeformatter 这个类.
由字符串转为日期的方法:
如果是默认的格式, yyyy-MM-dd 这种日期格式字符串, 直接用 LocalDate.parse()进行转换就行了, 相对应的时间也是. 既有时间又有日期的用 DateTimeformatte 这个类就行.
- String time="2019-02-16";
- LocalDate localDate=LocalDate.parse(time);
- System.out.println(localDate);
有时间有日期:
- String datetime1="2019-05-24 18:15:56";
- DateTimeFormatter formatter1=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
- LocalDateTime localDateTime1=LocalDateTime.parse(datetime1,formatter1);
- System.out.println(localDateTime1);
或者:
- String datetime2="2019-05-24 18:15:56";
- DateTimeFormatter formatter2=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
- TemporalAccessor parse = formatter2.parse(datetime2);
- LocalDateTime localDateTime=LocalDateTime.from(parse);
- System.out.println(localDateTime);
由日期转为字符串的方法:
如果是 LocalDate 这种标准格式的, 直接 toString 就可以了,
如果是 LocalTime 这种格式的, toString 会附带纳秒值 21:06:30.760163, 这个时候你可以使用日期格式器, 或者这样 LocalTime time = LocalTime.now().withNano(0), 把纳秒直接清 0.
如果是 LocalDateTime, 这个时候是需要一个日期转换器的. 才能由时间 + 日期 ->想要的时间,
- LocalDate localDate=LocalDate.now();
- System.out.println(localDate.toString());
- DateTimeFormatter formatter=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
- LocalDateTime localDateTime=LocalDateTime.now();
- String result=localDateTime.format(formatter);
- System.out.println(result);
7,JDBC 中对应的日期
最新 JDBC 映射将把数据库的日期类型和 Java 8 的新类型关联起来:
- SQL -> Java
- ---------------------
- date -> LocalDate
- time -> LocalTime
- timestamp -> LocalDateTime
8, 小结
这次主要学习了 Java8 中新的日期处理类
LocalDate,LocalTime,LocalDateTime 处理日期时间都非常的方便, 而且它们是线程安全的,
新版的日期和时间 API 中, 日期和时间对象是不可变的.
LocalDate 日期是一个便于使用的日期类, 线程安全, Date 类比较复杂, 时间计算麻烦.
DateTimeFormatter 的使用也安全, 方便. 以后用它来代替 SimpleDateFormat
TemporalAdjuster 让你能够用更精细的方式操纵日期, 不再局限于一次只能改变它的 一个值, 并且你还可按照需求定义自己的日期转换器
JDBC 的 TimeStamp 类和 LocalDateTime 的转换也很方便, 提供了相应的方法.
使用的时候, 日期必须是标准的 yyyy-MM-dd 格式, 比如 1 月必须写成 01, 不然会报错.
更多用例查看此文: https://www.cnblogs.com/comeboo/p/5378922.html
来源: https://www.cnblogs.com/tang-hao-/p/11308713.html