Java 时间类
Java 时间类在 Java 8 发生变化本记录基于 Java 8 时间类
新时间类和 Date 对比
Date 和 SimpleDateFormatter 非线程安全,而 LocalDate 和 LocalTime 和 String 一样,是final类型 - 线程安全且不能被修改
Date 月份从 0 开始,一月是 0,十二月是 11。LocalDate 月份和星期都改成了 enum ,不会再用错。
Date 是一个“万能接口”,它包含日期、时间,还有毫秒数。如果你只需要日期或时间那么有一些数据就没啥用。在新的 Java 8 中,日期和时间被明确划分为 LocalDate 和 LocalTime,LocalDate 无法包含时间,LocalTime 无法包含日期。当然,LocalDateTime 才能同时包含日期和时间。
Date 推算时间(比如往前推几天/ 往后推几天/ 计算某年是否闰年/ 推算某年某月的第一天、最后一天、第一个星期一等等)要结合 Calendar 要写好多代码。
新时间类
Instant 类
Instant 类对时间轴上的单一瞬时点建模,可以用于记录应用程序中的事件时间戳,之后学习的类型转换中,均可以使用 Instant 类作为中间类完成转换
演示
// 获取当前时间戳
Instant instant1 = Instant.now();
// 秒
System.out.println(instant1.getEpochSecond());
// 毫秒
System.out.println(instant1.toEpochMilli());
// 以指定时间戳创建Instant
Instant instant2 = Instant.ofEpochSecond(1637406017);
// 构造 ZonedDateTime 类
ZonedDateTime zonedDateTime = instant2.atZone(ZoneId.systemDefault());
System.out.println(zonedDateTime);
Duration 类
Duration类表示秒或纳秒时间间隔,适合处理较短的时间,需要更高的精确性
Duration 的内部实现与 Instant 类似,也是包含两部分:seconds 表示秒,nanos 表示纳秒。两者的区别是 Instant 用于表示一个时间戳(或者说是一个时间点),而 Duration 表示一个时间段,所以 Duration 类中 不包含 now() 静态方法。可以通过 Duration.between() 方法创建 Duration 对象
// 构造 ZonedDateTime 类
ZonedDateTime start = Instant.ofEpochSecond(1637406017).atZone(ZoneId.systemDefault());
ZonedDateTime end = Instant.now().atZone(ZoneId.systemDefault());
// 求两个时间戳相差多少时间
Duration between = Duration.between(start, end);
System.out.println(between.getSeconds());
Period 类
Period类表示一段时间的 年、月、日
ZonedDateTime start = Instant.ofEpochSecond(1229105017).atZone(ZoneId.systemDefault());
ZonedDateTime end = Instant.now().atZone(ZoneId.systemDefault());
Period period = Period.between(start.toLocalDate(), end.toLocalDate());
System.out.printf("相差%d年%d月%d日\n", period.getYears(), period.getMonths(), period.getDays());
运行结果
相差12年11月7日
LocalDate 类
LocalDate是一个 不可变 的日期时间对象,表示日期,通常被视为年-月-日
LocalDate localDate = LocalDate.from(Instant.ofEpochSecond(1229105017)
.atZone(ZoneId.systemDefault()));
int year = localDate.getYear(); // 年份:2008
Month month = localDate.getMonth(); // 月份:DECEMBER
int dayOfMonth = localDate.getDayOfMonth(); // 月份中的第几天:13
DayOfWeek dayOfWeek = localDate.getDayOfWeek(); // 一周的第几天:SATURDAY
int length = localDate.lengthOfMonth(); // 月份的天数:31
boolean leapYear = localDate.isLeapYear(); // 是否为闰年:true
LocalTime 类
LocalTime是一个不可变的日期时间对象,代表一个时间,通常被看作是小时-秒,时间表示为纳秒精度
LocalTime localTime = LocalTime.of(17, 23, 52); // 初始化一个时间:17:23:52
int hour = localTime.getHour(); // 时:17
int minute = localTime.getMinute(); // 分:23
int second = localTime.getSecond(); // 秒:52
LocalDateTime 类
LocalDateTime类是一个不可变的日期时间对象,代表日期时间,通常被视为年-月-日-时-分-秒
LocalDateTime dateTime = LocalDateTime.now();
Month month = dateTime.getMonth(); // 返回 Month 对象 NOVEMBER
int monthValue = dateTime.getMonthValue(); // 返回月份数字 11
int dayOfYear = dateTime.getDayOfYear(); // 返回这一天在这一年的第几天 324
long secondOfDay = dateTime.getLong(
ChronoField.SECOND_OF_DAY); // 在这一天多少秒 82609
ZonedDateTime 类
ZonedDateTime是具有时区的日期时间的不可变表示,此类存储所有日期和时间字段,精度为纳秒,时区为区域偏移量,用于处理模糊的本地日期时间
LocalDateTime localDateTime = LocalDateTime.now();
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.of("+08:00"));
System.out.println(zonedDateTime);
转换
LocalDateTime LocalTime LocalDate 互转
// LocalDateTime to LocalDate
LocalDate date = localDateTime.toLocalDate();
// LocalDateTime to LocalTime
LocalTime time = localDateTime.toLocalTime();
// LocalDate to LocalDateTime
LocalDateTime dateTime = localDate.atStartOfDay()
.atZone(ZoneId.systemDefault()).toLocalDateTime();
// LocalTime to LocalDateTime 因为没有提供日期默认是 1970-01-01
Instant.ofEpochSecond(localTime.getSecond()).atZone(ZoneId.systemDefault()).toLocalDateTime()
// LocalDate,LocalTime to LocalDateTime
LocalDateTime localDateTime = LocalDateTime.of(LocalDate.now(), LocalTime.now());
操作
minus 减法操作
方法签名
public LocalDateTime minus(long amountToSubtract, TemporalUnit unit);
default Temporal minus(TemporalAmount amount);
描述
返回减去指定时间的该日期时间的副本
plus 加法操作
方法签名
Temporal plus(long amountToAdd, TemporalUnit unit);
Temporal plus(TemporalAmount amount);
描述
返回加上指定时间的该日期时间的副本
with 设置值操作
方法签名
Temporalemporal with(TemporalField field, long newValue);
default Temporal with(TemporalAdjuster adjuster);
描述
指定项(年/月/日/时/分/秒)设置指定值
演示
// 设置年为 2020 年
LocalDateTime dateTime = localDateTime.withYear(2020);
// 本月第一天
LocalDateTime with = LocalDateTime.now()
.with(TemporalAdjusters.firstDayOfMonth());
//本月最后一天
LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
until 两个时间的间隔
方法签名
long until(Temporal endExclusive, TemporalUnit unit);
演示
long seconds = dateTime.until(LocalDateTime.now(), ChronoUnit.SECONDS);
辅助类
ChronoUnit 类
public enum ChronoUnit implements TemporalUnit {
/**
* 纳秒概念的单位,最小支持的时间单位。对于ISO日历系统,它等于第二个单位的第1,000,000,000个部分。
*/
NANOS("Nanos", Duration.ofNanos(1)),
/**
* 微秒概念的单位。对于ISO日历系统,它等于第二个单位的百万分之一。
*/
MICROS("Micros", Duration.ofNanos(1000)),
/**
* 代表毫秒概念的单位。对于ISO日历系统,它等于第二个单位的千分之一。
*/
MILLIS("Millis", Duration.ofNanos(1000_000)),
/**
* 代表秒的概念的单位。对于ISO日历系统,除around秒外,它等于SI单位制中的秒。
*/
SECONDS("Seconds", Duration.ofSeconds(1)),
/**
* 代表分钟概念的单位。对于ISO日历系统,它等于60秒。
*/
MINUTES("Minutes", Duration.ofSeconds(60)),
/**
* 代表小时概念的单位。对于ISO日历系统,它等于60分钟。
*/
HOURS("Hours", Duration.ofSeconds(3600)),
/*
* 代表半天概念的单位,用于AM / PM。对于ISO日历系统,它等于12小时。
*/
HALF_DAYS("HalfDays", Duration.ofSeconds(43200)),
/**
* 代表一天的概念的单位。对于ISO日历系统,这是从午夜到午夜的标准日期。估计一天的持续时间为24小时。
* 与其他日历系统一起使用时,它必须与地球上太阳升起和落下所定义的日期相对应。不必将日期从午夜开始-在日 * 历系统之间进行转换时,日期应等于午夜。
*/
DAYS("Days", Duration.ofSeconds(86400)),
/**
* 代表一周概念的单位。对于ISO日历系统,它等于7天。
* 与其他日历系统一起使用时,它必须对应整数天
*/
WEEKS("Weeks", Duration.ofSeconds(7 * 86400L)),
/**
* 代表一个月概念的单位。对于ISO日历系统,月份的长度因一年中的月份而异。估计的持续时间为365.2425天的十 * 二分之一。
* 与其他日历系统一起使用时,它必须对应整数天。
*/
MONTHS("Months", Duration.ofSeconds(31556952L / 12)),
/**
* 代表一年概念的单位。对于ISO日历系统,它等于12个月。一年的估计持续时间为365.2425天。
* 当与其他日历系统一起使用时,它必须对应于整数天或月,大约等于地球绕太阳公转所定义的一年。
*/
YEARS("Years", Duration.ofSeconds(31556952L)),
/**
* 代表十年概念的单位。对于ISO日历系统,它等于10年。
* 与其他日历系统一起使用时,它必须对应整数天,通常是整数年。
*/
DECADES("Decades", Duration.ofSeconds(31556952L * 10L)),
/**
* 代表一个世纪概念的单位。对于ISO日历系统,它等于100年。
* 与其他日历系统一起使用时,它必须对应整数天,通常是整数年。
*/
CENTURIES("Centuries", Duration.ofSeconds(31556952L * 100L)),
/**
* 代表千年概念的单位。对于ISO日历系统,它等于1000年。
* 与其他日历系统一起使用时,它必须对应整数天,通常是整数年。
*/
MILLENNIA("Millennia", Duration.ofSeconds(31556952L * 1000L)),
/**
* 代表时代概念的单位。 ISO日历系统没有纪元,因此无法在日期或日期时间中添加纪元。
* 人为地将时代的估计持续时间定义为1,000,000,000年。
* 与其他日历系统一起使用时,该装置没有任何限制。
*/
ERAS("Eras", Duration.ofSeconds(31556952L * 1000_000_000L)),
/**
* 代表永恒概念的人造单位。这主要与TemporalField一起使用,以表示无限制的字段,
* 例如年份或时代。人为地将时代的估计持续时间定义为“持续时间”支持的最大持续时间。
*/
FOREVER("Forever", Duration.ofSeconds(Long.MAX_VALUE, 999_999_999));
}
TemporalAdjusters 类
时间调节器: 是修改时间对象的一个关键工具。它们的存在是为了将调整的过程外部化,根据策略设计模式,允许不同的方法。
使用不同方式调节 Temporal 对象而与 Temporal 实现无关
有两种使用TemporalAdjuster的同等方式。
第一种是直接调用接口上的方法。第二种是使用Temporal.with(TemporalAdjuster)。
/**
* 当前月的第一天
*/
public static TemporalAdjuster firstDayOfMonth();
/**
* 当月的最后一天
*/
public static TemporalAdjuster lastDayOfMonth();
/**
* 下个月第一天
*/
public static TemporalAdjuster firstDayOfNextMonth();
/**
* 这年第一天
*/
public static TemporalAdjuster firstDayOfYear();
/**
* 这年最后一天
*/
public static TemporalAdjuster lastDayOfYear();
/**
* 明年第一天 明年元旦
*/
public static TemporalAdjuster firstDayOfNextYear();
/**
* 返回月份调整器中的第一个,它在同一个月中返回第一个匹配的星期几的新日期。
*/
public static TemporalAdjuster firstInMonth(DayOfWeek dayOfWeek);
/**
* 返回“最后一天”调整器,它返回设置为当前月份最后一天的新日期。
*/
public static TemporalAdjuster lastDayOfMonth();