前言       

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显示日期有T全局处理 java 日期处理类_静态方法

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,不然会报错。