1.LocalDate 和 LocalTime
LocalDate、 LocalTime、 LocalDateTime 类的实例是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息 .
你可以通过静态工厂方法of创建一个LocalDate实例。 LocalDate实例提供了多种方法来
读取常用的值,比如年份、月份、星期几等
now() | 静态方法, 根据当前时间创建对象 | LocalDate localDate = LocalDate.now(); LocalTime localTime = LocalTime.now(); LocalDateTime localDateTime = LocalDateTime.now(); |
---|---|---|
of() | 静态方法, 根据指定日期/时间创建 对象 | LocalDate localDate = LocalDate.of(2016, 10, 26); LocalTime localTime = LocalTime.of(02, 22, 56); LocalDateTime localDateTime = LocalDateTime.of(2016, 10, 26, 12, 10, 55); |
plusDays, plusWeeks, plusMonths, plusYears | 向当前 LocalDate 对象添加几天、 几周、 几个月、 几年 | |
minusDays, minusWeeks, minusMonths, minusYears | 从当前 LocalDate 对象减去几天、 几周、 几个月、 几年 | |
plus, minus | 添加或减少一个 Duration 或 Period | |
withDayOfMonth, withDayOfYear, withMonth, withYear | 将月份天数、 年份天数、 月份、 年 份 修 改 为 指 定 的 值 并 返 回 新 的 LocalDate 对象 | |
getDayOfMonth | 获得月份天数(1-31) | |
getDayOfYear | 获得年份天数(1-366) | |
getDayOfWeek | 获得星期几(返回一个 DayOfWeek 枚举值) | |
getMonth | 获得月份, 返回一个 Month 枚举值 | |
getMonthValue | 获得月份(1-12) | |
getYear | 获得年份 | |
until | 获得两个日期之间的 Period 对象, 或者指定 ChronoUnits 的数字 | |
isBefore, isAfter | 比较两个 LocalDate | |
isLeapYear | 判断是否是闰年 |
构造及创建方式以LocalDate为例
//创建初始化LocalDate对象
LocalDate date = LocalDate.of(2021, 3, 18);
//获取年份
int year = date.getYear();
//获取当前是几月输出为当权月份的英文表示
Month month = date.getMonth();
//获取月份的原始数值
int value = date.getMonthValue();
//获取对象中的日的原始数值为18
int day = date.getDayOfMonth();
//获取今天属于周几
DayOfWeek dow = date.getDayOfWeek();
//获取当前月分的天数
int len = date.lengthOfMonth();
//判断是否为闰年
boolean leap = date.isLeapYear();
//获取当前的年月日对象
LocalDate now = LocalDate.now();
LocalDateTime now1 = LocalDateTime.now();
System.out.println(now);
System.out.println(now1);
/**
now:2021-03-05
now1:2021-03-05T18:15:43.816
**/
注:
- LocalDateTime另外多了获取时分秒的方法
- 也可以通过使用TemporalField 作为参数获取响应的时间字段
//ChronoField为一个枚举类实现了TemporalField
int year1 = date.get(ChronoField.YEAR);
int month1 = date.get(ChronoField.MONTH_OF_YEAR);
int day1 = date.get(ChronoField.DAY_OF_MONTH);
LocalDate和LocalTime都可以通过解析代表它们的字符串创建。使用静态方法parse,你
可以实现这一目的
LocalDate date = LocalDate.parse("2021-03-18");
LocalTime time = LocalTime.parse("13:45:20");
你可以向parse方法传递一个DateTimeFormatter。该类的实例定义了如何格式化一个日
期或者时间对象。
2.Instant 时间戳
注:只能操作事件戳的形式,常用形式如"2021-03-18"不可用。它是以Unix元年(传统的设定为UTC时区1970年1月1日午夜时分)开始所经历的描述进行运算.
你可以通过向静态工厂方法ofEpochSecond传递一个代表秒数的值创建一个该类的实例。你可以通过向静态工厂方法ofEpochSecond传递一个代表秒数的值创建一个该类的实例。
构造示例如下
//下面四个为 1970年1月1日午夜时分后三秒的时间戳
Instant instant1 = Instant.ofEpochSecond(3);
Instant instant2 = Instant.ofEpochSecond(3, 0);
//下面两个为添加偏移量
Instant instant3 = Instant.ofEpochSecond(2, 1_000_000_000);
Instant instant4 = Instant.ofEpochSecond(4, -1_000_000_000);
long timeMillis = System.currentTimeMillis();
Instant instant = Instant.ofEpochSecond(System.currentTimeMillis());
Instant now = Instant.now();
Instant now = Instant.now();//获取当前时间戳
可以通过Duration和Period类使用Instant
3.Duration 和 Period
Duration:用于计算两个“时间”间隔 ,Duration类表示秒或纳秒时间间隔,适合处理较短的时间,需要更高的精确性。我们能使用between()方法比较两个瞬间的差:
Period:用于计算两个“日期”间隔 ,Period 类表示一段时间的年、月、日,开使用between()方法获取两个日期之间的差作为Period 对象返回:
目前为止,你看到的所有类都实现了Temporal接口, Temporal接口定义了如何读取和操纵
为时间建模的对象的值。 LocalDateTime和Instant是为不同的目的而设计的,一个是为了便于人阅读使用,另一个是为了便于机器处理,所以你不能将二者混用。
Duration类和Period类共享了很多相似的方法
方 法 名 | 是否是静态方法 | 方法描述 |
---|---|---|
between | 是 | 创建两个时间点之间的 interval |
from | 是 | 由一个临时时间点创建 interval |
of | 是 由它的组成部分创建 interval 的实例 | |
parse | 是 | 由字符串创建 interval 的实例 |
addTo | 否 | 创建该 interval 的副本,并将其叠加到某个指定的 temporal 对象 |
get | 否 | 读取该 interval 的状态 |
isNegative | 否 | 检查该 interval 是否为负值,不包含零 |
isZero | 否 | 检查该 interval 的时长是否为零 |
minus | 否 | 通过减去一定的时间创建该 interval 的副本 |
multipliedBy | 否 | 将 interval 的值乘以某个标量创建该 interval 的副本 |
negated | 否 | 以忽略某个时长的方式创建该 interval 的副本 |
plus | 否 | 以增加某个指定的时长的方式创建该 interval 的副本 |
subtractFrom | 否 | 从指定的 temporal 对象中减去该 interval |
Period 类
Period 类表示一段时间的年、月、日,开使用between()方法获取两个日期之间的差作为Period 对象返回:
Period duration = Period .between(LocalDate.of(2018, 9, 8),
LocalDate.of(2020, 3, 18));
long YEARS = duration.get(ChronoUnit.YEARS);
long month = duration.get(ChronoUnit.MONTHS);
long day = duration.get(ChronoUnit.DAYS);
System.out.println("相差:"+YEARS+"year"+month+"month"+day+"day");
//相差:1year6month10day
//也可通过下面的方法
LOG.info("Years:" + period.getYears() +
" months:" + period.getMonths() +
" days:"+period.getDays());
//创建Period类型对象是基于年、月、日和周,构造日期差值
Period fromUnits = Period.of(3, 10, 10);
Period fromDays = Period.ofDays(50);
Period fromMonths = Period.ofMonths(5);
Period fromYears = Period.ofYears(10);
Period fromWeeks = Period.ofWeeks(40);
Duration类
Duration类表示秒或纳秒时间间隔,适合处理较短的时间,需要更高的精确性。我们能使用between()方法比较两个瞬间的差:
Instant instant1 = Instant.ofEpochSecond(3);
Instant instant2 = Instant.ofEpochSecond(System.currentTimeMillis());
//也可以通过LocalTime构造
Duration between = Duration.between(instant1, instant2);
System.out.println(between.getSeconds());
//我们能基于下面的方法获得Duration对象,ofDays(), ofHours(), ofMillis(), ofMinutes(), ofNanos(), ofSeconds():
// 可以使用toDays(), toHours(), toMillis(), toMinutes()方法把Duration对象可以转成其他时间单元:
long days = between.toDays();
//将间隔的秒数转化为天数
System.out.println(days);
在测试程序运行时间时,可获取指定单位的时间
long startup = System.currentTimeMillis();
run();
long end = System.currentTimeMillis();
long runTime= startup-end;
Duration duration = Duration.ofMillis(runTime);
long minutes = duration.toMinutes();
log.info("总共花费了{}分钟",minutes);
4. 日期的操纵
一般方法
如果你已经有一个LocalDate对象,想要创建它的一个修改版,最直接也最简单的方法是使
用withAttribute方法。 withAttribute方法会创建对象的一个副本,并按照需要修改它的属
性。
LocalDate date1 = LocalDate.of(2014, 3, 18);
LocalDate date2 = date1.withYear(2011); //修改了年份
LocalDate date3 = date2.withDayOfMonth(25);
LocalDate date4 = date3.with(ChronoField.MONTH_OF_YEAR, 9)
以相对方式修改LocalDate对象的属性
LocalDate date1 = LocalDate.of(2014, 3, 18);
LocalDate date2 = date1.plusWeeks(1);//其他的类也有类似plus方法去调整日期
LocalDate date3 = date2.minusYears(3);//减
LocalDate date4 = date3.plus(6, ChronoUnit.MONTHS);
像LocalDate、 LocalTime、 LocalDateTime以及Instant这样表示时间点的日期时间类提供了大量通用的方法
使用 TemporalAdjuster
TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下个周日”等操作。
TemporalAdjusters : 该类通过静态方法提供了大量的常用 TemporalAdjuster 的实现
进行一些更加复杂的操作,比如,将日期调整到下个周日、下个工作日,或者是本月的最后一天。这时,你可以使用重载版本的with方法,向其传递一个提供了更多定制化选择的TemporalAdjuster对象,更 加 灵 活 地 处 理 日 期 。 对 于 最 常 见 的 用 例 , 日 期 和 时 间 API 已 经 提 供 了 大 量 预 定 义 的TemporalAdjuster。你可以通过TemporalAdjuster类的静态工厂方法访问它们 。
import static java.time.temporal.TemporalAdjusters.*;
LocalDate date1 = LocalDate.of(2014, 3, 18);
LocalDate date2 = date1.with(nextOrSame(DayOfWeek.SUNDAY));
LocalDate date3 = date2.with(lastDayOfMonth());
TemporalAdjuster类为是一个函数式接口
@FunctionalInterface
public interface TemporalAdjuster {
Temporal adjustInto(Temporal temporal);
}
TemporalAdjusters 工厂中的方法
方 法 名 | 描述 |
---|---|
dayOfWeekInMonth | 创建一个新的日期,它的值为同一个月中每一周的第几天 |
firstDayOfMonth | 创建一个新的日期,它的值为当月的第一天 |
firstDayOfNextMonth | 创建一个新的日期,它的值为下月的第一天 |
firstDayOfNextYear | 创建一个新的日期,它的值为明年的第一天 |
firstDayOfYear | 创建一个新的日期,它的值为当年的第一天 |
firstInMonth | 创建一个新的日期,它的值为同一个月中,第一个符合星期几要求的值 |
lastDayOfMonth | 创建一个新的日期,它的值为当月的最后一天 |
lastDayOfNextMonth | 创建一个新的日期,它的值为下月的最后一天 |
lastDayOfNextYear | 创建一个新的日期,它的值为明年的最后一天 |
lastDayOfYear | 创建一个新的日期,它的值为今年的最后一天 |
lastInMonth | 创建一个新的日期,它的值为同一个月中,最后一个符合星期几要求的值 |
next/previous | 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期 |
nextOrSame/previousOrSame | 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期,如果该日期已经符合要求,直接返回该对象 |
实例
请设计一个NextWorkingDay类,该类实现了TemporalAdjuster接口,能够计算明天 的日期,同时过滤掉周六和周日这些节假日。格式如下所示: date = date.with(new NextWorkingDay()); 如果当天的星期介于周一至周五之间,日期向后移动一天;如果当天是周六或者周日,则 返回下一个周一.
public class NextWorkingDay implements TemporalAdjuster {
@Override
public Temporal adjustInto(Temporal temporal) {
DayOfWeek dow =
DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
int dayToAdd = 1;
if (dow == DayOfWeek.FRIDAY) dayToAdd = 3;
else if (dow == DayOfWeek.SATURDAY) dayToAdd = 2;
return temporal.plus(dayToAdd, ChronoUnit.DAYS);
}
}
================测试===============
@Test
public void temporalAdjuster(){
LocalDate date = LocalDate.of(2020, 3, 18);
//方式一
date = date.with(new NextWorkingDay());
// 方式二 或者通过lambda
date = date.with(temporal -> {
DayOfWeek dow = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
int dayToAdd = 1; //正常增加一天
if (dow == DayOfWeek.FRIDAY) dayToAdd = 3; //周五增加三天
else if (dow == DayOfWeek.SATURDAY) dayToAdd = 2; //周六增加两天
return temporal.plus(dayToAdd, ChronoUnit.DAYS); //返回修改后的日期
});
System.out.println(date);
// 方式三 也可以使用工厂类
TemporalAdjuster nextWorkingDay = TemporalAdjusters.ofDateAdjuster(
temporal -> {
DayOfWeek dow = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
int dayToAdd = 1;
if (dow == DayOfWeek.FRIDAY) dayToAdd = 3;
if (dow == DayOfWeek.SATURDAY) dayToAdd = 2;
return temporal.plus(dayToAdd, ChronoUnit.DAYS);
});
date = date.with(nextWorkingDay);
System.out.println();
}
注:调用with方法是会将对象本身传入TemporalAdjuster的实例中,进行处理后返回该实例
5.DateTimeFormatter 类
处理日期和时间对象时,格式化以及解析日期时间对象是另一个非常重要的功能。新的
java.time.format包就是特别为这个目的而设计的。这个包中,最重要的类是DateTimeFormatter。创建格式器最简单的方法是通过它的静态工厂方法以及常量。像BASIC_ISO_DATE和 ISO_LOCAL_DATE 这 样 的 常 量 是 DateTimeFormatter 类 的 预 定 义 实 例 。 所 有 的DateTimeFormatter实例都能用于以一定的格式创建代表特定日期或时间的字符串。比如,下面的这个例子中,我们使用了两个不同的格式器生成了字符串
LocalDate date = LocalDate.of(2014, 3, 18);
String s1 = date.format(DateTimeFormatter.BASIC_ISO_DATE);20140318
String s2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE);2014-03-18
你也可以通过解析代表日期或时间的字符串重新创建该日期对象。所有的日期和时间API
都提供了表示时间点或者时间段的工厂方法,你可以使用工厂方法parse达到重创该日期对象的目的 .
LocalDate date1 = LocalDate.parse("20140318",DateTimeFormatter.BASIC_ISO_DATE);
LocalDate date2 = LocalDate.parse("2014-03-18",DateTimeFormatter.ISO_LOCAL_DATE);
和老的java.util.DateFormat相比较,所有的DateTimeFormatter实例都是线程安全
的。所以,你能够以单例模式创建格式器实例,就像DateTimeFormatter所定义的那些常量,并能在多个线程间共享这些实例。 DateTimeFormatter类还支持一个静态工厂方法,它可以按照某个特定的模式创建格式器,代码清单如下。
//自定义格式,这段代码中, LocalDate的formate方法使用指定的模式生成了一个代表该日期的字符串。紧接着,静态的parse方法使用同样的格式器解析了刚才生成的字符串,并重建了该日期对象。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate date1 = LocalDate.of(2020,3, 18);
String formattedDate = date1.format(formatter);
LocalDate date2 = LocalDate.parse(formattedDate, formatter);