Java8新增的时间日期处理类

前言       

Java8之前处理日期一直是Java程序员比较头疼的问题,从Java 8之后,Java里面添加了许多的新特性,其中一个最常见也是最实用的便是日期处理的类——LocalDate。LocalDate是一种更为高效的日期类,比起Date的复杂具有相当高的简洁性,吸取了企业级别的joda.time时间处理的优点,避免了传统的Date和Calendar复合起来计算的难处。
新增的日期主要有三种:
java.time.LocalDate  ->只对年月日做出处理
java.time.LocalTime  ->只对时分秒纳秒做出处理
java.time.LocalDateTime ->同时可以处理年月日和时分秒

LocalDate、LocalTime、LocalDateTime

  1. LocalDate:代表IOS格式(yyyy-MM-hh)的日期,不包含具体时间的日期,比如2014-01-14。它可以用来存储生日,周年纪念日,入职日期等。;
  2. LocalTime:它代表的是不含日期的时间;
  3. LocalDateTime:它包含了日期及时间,不过还是没有偏移信息或者说时区,比较常用;

三种共同特点:

  • 相比于前面的Date和Calendar,他们是线程安全的;
  • 它们是不可变的日期时间对象;

常用API:

方法描述
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);

}

瞬时(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);
	    
	//添加偏移量,北京在东八区,时区加八即为北京时间
	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);
}

日期间隔,持续时间 (Period 和 Duration)

Java 8 中引入的两个与日期相关的新类:PeriodDuration。两个类看表示时间量或两个日期之间的差,两者之间的差异为: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());
	}

使用 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);
}

结果:

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);

JDBC

最新JDBC映射将把数据库的日期类型和Java 8的新类型关联起来:

SQL -> Java

---------------------

date -> LocalDate

time -> LocalTime

timestamp -> LocalDateTime

小结

这次主要学习了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

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值