新的日期和时间API
1.LocalDate、LocalTime、Instant、Duration 以及 Period
开始使用新的日期和时间
API
时,你最先碰到的可能是
LocalDate
类。该类的实例是一个不 可变对象,它只提供了简单的日期,并不含当天的时间信息。另外,它也不附带任何与时区相关的信息。
你可以通过静态工厂方法
of
创建一个
LocalDate
实例。
LocalDate
实例提供了多种方法来 读取常用的值,比如年份、月份、星期几等
LocalDate:
LocalDate date = LocalDate.of(2020, 5, 20);
System.out.println("this year is :" + date.getYear());
System.out.println("the month is :" + date.getMonth());
System.out.println(" the day of month is :" + date.getDayOfMonth());
System.out.println("the day of week is :" + date.getDayOfWeek());
System.out.println("this month has days :" + date.lengthOfMonth());
System.out.println("this year was leap ? :" + date.isLeapYear()) ;
LocalDate now = LocalDate.now();
System.out.println("the time now is :" + now);
this year is :2020
the month is :MAY
the day of month is :20
the day of week is :WEDNESDAY
this month has days :31
this year was leap ? :true
the time now is :2020-05-19
LoaclTime:
LocalTime localTime = LocalTime.now();
System.out.println("now time is :" + localTime);
System.out.println("hour is " + localTime.getHour());
System.out.println("minute is " + localTime.getMinute());
System.out.println("second is " + localTime.getSecond());
now time is :11:45:18.117740500
hour is 11
minute is 45
second is 18
LocalDateTime
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("now is :" + localDateTime);
System.out.println(localDateTime.getDayOfMonth());
System.out.println(localDateTime.getDayOfWeek());
System.out.println(localDateTime.getDayOfYear());
System.out.println(localDateTime.getMonthValue());
now is :2020-05-19T11:49:09.700690500
19
TUESDAY
140
5
2.机器的日期和时间格式
作为人,我们习惯于以星期几、几号、几点、几分这样的方式理解日期和时间。毫无疑问, 这种方式对于计算机而言并不容易理解。从计算机的角度来看,建模时间最自然的格式是表示一 个持续时间段上某个点的单一大整型数。这也是新的java.time.Instant
类对时间建模的方 式,基本上它是以Unix
元年时间(传统的设定为
UTC
时区
1970
年
1
月
1
日午夜时分)开始所经历的 秒数进行计算。
你可以通过向静态工厂方法
ofEpochSecond
传递一个代表秒数的值创建一个该类的实例。静态工厂方法ofEpochSecond
还有一个增强的重载版本,它接收第二个以纳秒为单位的参数值,对传入作为秒数的参数进行调整。重载的版本会调整纳秒参数,确保保存的纳秒分片在0
到
999 999 999之间。这意味着下面这些对
ofEpochSecond
工厂方法的调用会返回几乎同样的
Instant
对象:
Instant instant = Instant.now();
System.out.println(instant);
System.out.println(instant.getEpochSecond());
//多加了1天时间
Instant instant1 = Instant.ofEpochSecond((instant.getEpochSecond() + (long) 60 * 60* 24));
System.out.println(instant1);
System.out.println(instant1.getEpochSecond());
2020-05-19T04:04:09.401508500Z
1589861049
2020-05-20T04:04:09Z
1589947449
3.使用 TemporalAdjuster
截至目前,你所看到的所有日期操作都是相对比较直接的。有的时候,你需要进行一些更加 复杂的操作,比如,将日期调整到下个周日、下个工作日,或者是本月的最后一天。这时,你可 以使用重载版本的with
方法,向其传递一个提供了更多定制化选择的
TemporalAdjuster
对象, 更加灵活地处理日期。对于最常见的用例,日期和时间API
已经提供了大量预定TemporalAdjuster。你可以通过
TemporalAdjuster
类的静态工厂方法访问它们,如下所示。

LocalDate date = LocalDate.now();
LocalDate localDate = date.with(nextOrSame(DayOfWeek.SUNDAY));
System.out.println(localDate);
LocalDate localDate4 = date.with(previousOrSame(DayOfWeek.SUNDAY));
System.out.println(localDate4);
LocalDate localDate1 = localDate.with(lastDayOfMonth());
System.out.println(localDate1);
//第三周的星期五
LocalDate localDate2 = localDate.with(dayOfWeekInMonth(3, DayOfWeek.FRIDAY));
System.out.println(localDate2);
//当前月的第一个星期一
LocalDate localDate3 = localDate.with(firstInMonth(DayOfWeek.MONDAY));
System.out.println(localDate3);
2020-05-24
2020-05-17
2020-05-31
2020-05-15
2020-05-04
正如我们看到的,使用
TemporalAdjuster
我们可以进行更加复杂的日期操作,而且这些方 法的名称也非常直观,方法名基本就是问题陈述。此外,即使你没有找到符合你要求的预定义的 TemporalAdjuster,创建你自己的
TemporalAdjuster
也并非难事。实际上,
TemporalAdjuster接口只声明了单一的一个方法(这使得它成为了一个函数式接口),定义如下。
TemporalAdjuster
接口
@FunctionalInterface
public interface TemporalAdjuster {
Temporal adjustInto(Temporal temporal);
}
这意味着
TemporalAdjuster
接口的实现需要定义如何将一个
Temporal
对象转换为另一 个Temporal
对象。你可以把它看成一个
UnaryOperator<Temporal>
。
设计一个
NextWorkingDay
类,该类实现了
TemporalAdjuster
接口,能够计算明天 的日期,同时过滤掉周六和周日这些节假日。格式如下所示:
如果当天的星期介于周一至周五之间,日期向后移动一天;如果当天是周六或者周日,则 返回下一个周一。
LocalDate localDate5 = date.with(temporal -> {
DayOfWeek dayOfWeek = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
int addToDay = 1;
if (dayOfWeek == DayOfWeek.FRIDAY)
addToDay = 3;
else if (dayOfWeek == DayOfWeek.SATURDAY)
addToDay = 2;
return temporal.plus(addToDay, ChronoUnit.DAYS);
});
System.out.println(localDate5);
你大概会希望在你代码的多个地方使用同样的方式去操作日期,为了达到这一目的,我们 建议你像我们的示例那样将它的逻辑封装到一个类中。对于你经常使用的操作,都应该采用类 似的方式,进行封装。最终,你会创建自己的类库,让你和你的团队能轻松地实现代码复用。
如果你想要使用
Lambda
表达式定义
TemporalAdjuster
对象,推荐使用
TemporalAdjusters类的静态工厂方法
ofDateAdjuster
,它接受一个UnaryOperator<LocalDate> 类型的参数,代码如下:
import static java.time.temporal.TemporalAdjusters.*;
TemporalAdjuster temporalAdjuster = ofDateAdjuster(temporal -> {
DayOfWeek dayOfWeek = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
int addToDay = 1;
if (dayOfWeek == DayOfWeek.FRIDAY)
addToDay = 3;
else if (dayOfWeek == DayOfWeek.SATURDAY)
addToDay = 2;
return temporal.plus(addToDay, ChronoUnit.DAYS);
});
LocalDate localDate6 = date.with(temporalAdjuster);
System.out.println(localDate6);
DateTimeFormatter :线程安全的类
LocalDate of = LocalDate.of(2019, 6, 20);
String format = of.format(DateTimeFormatter.BASIC_ISO_DATE);
String format1 = of.format(DateTimeFormatter.ISO_DATE);
System.out.println(format);
System.out.println(format1);
String format2 = of.format(DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println(format2);
LocalDate parse = LocalDate.parse("20140318", DateTimeFormatter.BASIC_ISO_DATE);
System.out.println(parse);
LocalDate parse1 = LocalDate.parse("2014-03-18", DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println(parse1);
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("yyyy/MM/dd");
System.out.println(now.format(dateTimeFormatter1));
System.out.println(now.format(dateTimeFormatter));
20190620
2019-06-20
2019-06-20
2014-03-18
2014-03-18
2020/05/19
2020-05-19 16:28:47