一、名词
- 时间戳(时刻):时间戳是指格林尼治时间1970年01月01日00时00分00秒到现在的总秒数(毫秒数),可以理解成绝对时间,它与时区无关,不同时区对同一时间戳的解读不一样
- 时区:同一时刻(时间戳),世界上各地区的时间可能是不一样的,具体时间与时区相关,按经度一共分为24个时区,英国格林尼治是0时区,中国北京是东8区
二、Java8时间
- 2.1 Java8时间
Java1.0版本时,对时间的支持仅有java.util.Date类,它表示从1970-01-01 00:00:00开始精确到毫秒的时间点。到Java1.1时,表示日期的java.util.Calendar类被添加进来,但Calendar类也存在很多问题,比如:Date、Calendar类都是可变的,但像时间、日期这样的类应该是不变的;Date中月份是从0开始的;格式化只对Date生效,对Calendar不生效。2001年左右,Joda-Time项目开始致力于提供一个高质量的时间和日期的类库,因为其易用性很快得到了广泛使用。Java8借鉴了大量Joda-Time特性,推出了新的时间工具包
Java8时间相关类在java.time包路径下,表示时间的主要类如下:
类名 | 描述 |
---|---|
Instant | 时间戳(时刻) |
LocalDate | 与时区无关的日期 |
LocalTime | 与时区无关的时间 |
LocalDateTime | 与时区无关的日期和时间 |
ZonedDateTime | 与时区相关的日期和时间 |
ZoneId | 时区 |
ZoneOffset | 相对于格林尼治时间的时间偏差,比如:+08:00 |
时间输出格式类型:
输出类型 | 描述 |
---|---|
2019-06-10T03:48:20.847Z | 世界标准时间,T:日期和时间分隔,Z:世界标准时间 |
2019-06-10T11:51:48.872 | 不含时区信息的时间 |
2019-06-10T11:55:04.421+08:00[Asia/Shanghai] | 包含时区信息的时间,+08:00表示相对于0时区加8小时,[Asia/Shanghai]:时区 |
2.2 Java8时间使用
- 构造时间对象
构造Instant:
public static void main(String ... args) {
// 获取当前时间戳
Instant instant = Instant.now();
System.out.println(instant);
// 指定系统时间戳
Instant instant1 = Instant.ofEpochMilli(System.currentTimeMillis());
System.out.println(instant1);
// 解析指定时间戳
Instant instant2 = Instant.parse("2019-06-10T03:42:39Z");
System.out.println(instant2);
}
---
2019-06-10T03:48:20.847Z
2019-06-10T03:48:20.941Z
2019-06-10T03:42:39Z
构造LocalDateTime:
public static void main(String ... args) {
// 获取当前时间
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime);
// 指定时间
LocalDateTime localDateTime1 = LocalDateTime.of(2019, 06, 10, 10, 30,30);
System.out.println(localDateTime1);
// 解析时间
LocalDateTime localDateTime2 = LocalDateTime.parse("2019-06-10 11:55:04", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
System.out.println(localDateTime2);
}
---
2019-06-10T11:59:58.765
2019-06-10T10:30:30
2019-06-10T11:55:04
构造ZonedDateTime:
public static void main(String ... args) {
// 获取当前时区当前时间
ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println(zonedDateTime);
// 指定时间及时区
ZonedDateTime zonedDateTime1 = ZonedDateTime.of(2019, 06, 10, 10, 30,30, 00, ZoneId.of("UTC"));
System.out.println(zonedDateTime1);
// 解析指定时间
ZonedDateTime zonedDateTime2 = ZonedDateTime.parse("2019-06-10T12:03:19.367+08:00[Asia/Shanghai]", DateTimeFormatter.ISO_ZONED_DATE_TIME);
System.out.println(zonedDateTime2);
}
---
2019-06-10T12:08:44.405+08:00[Asia/Shanghai]
2019-06-10T10:30:30Z[UTC]
2019-06-10T12:03:19.367+08:00[Asia/Shanghai]
- 时间对象转换
public static void main(String ... args) {
Instant instant = Instant.now();
// 时间戳转LocalDateTime
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
System.out.println(localDateTime);
// 时间戳转时区时间
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, ZoneId.of("Asia/Shanghai"));
System.out.println(zonedDateTime);
// LocalDateTime转时间戳,因为LocalDateTime不带时区信息,因此需要指定当前时区到UTC的offset
Instant instant1 = localDateTime.toInstant(ZoneOffset.ofHours(8)); // ZoneOffset.of("+08:00"), ZoneOffset.UTC
System.out.println(instant1);
// 时区时间转时间戳,ZonedDateTime自带时区信息
Instant instant2 = zonedDateTime.toInstant();
System.out.println(instant2);
// LocalDateTime转时区时间(为时间加上时区信息)
ZonedDateTime zonedDateTime1 = ZonedDateTime.of(localDateTime, ZoneId.of("Asia/Tokyo"));
System.out.println(zonedDateTime1);
// 时区时间转换为LocalDateTime,将时区时间的时区信息去除
LocalDateTime localDateTime1 = zonedDateTime.toLocalDateTime();
System.out.println(localDateTime1);
}
---
2019-06-10T14:02:50.483
2019-06-10T14:02:50.483+08:00[Asia/Shanghai]
2019-06-10T06:02:50.483Z
2019-06-10T06:02:50.483Z
2019-06-10T14:02:50.483+09:00[Asia/Tokyo]
2019-06-10T14:02:50.483
- LocalDateTime与Date转换
Instant和Date是新老时间转换的桥梁,二者都是时间戳的表现形式,但Date在打印时会转换成当前时区时间(可通过设置TimeZone调整),Instant打印时默认是0时区时间
public static void main(String ... args) {
Date date = Date.from(Instant.now());
System.out.println(date);
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
System.out.println(date);
Instant instant = date.toInstant();
System.out.println(instant);
}
---
Mon Jun 10 14:09:27 CST 2019
Mon Jun 10 06:09:27 UTC 2019
2019-06-10T06:09:27.307Z
- 时区转换
public static void main(String ... args) {
// 初始化北京时间
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(Instant.now(), ZoneId.of("Asia/Shanghai"));
System.out.println(zonedDateTime);
// 北京时间转换为UTC时间
ZonedDateTime utcZonedDateTime = zonedDateTime.toInstant().atZone(ZoneId.of("UTC"));
System.out.println(utcZonedDateTime);
// 初始化东京时间
ZonedDateTime tokyoDateTime = ZonedDateTime.of(2019, 06, 10, 11, 20, 20, 00, ZoneId.of("Asia/Tokyo"));
System.out.println(tokyoDateTime);
// 东京时间转换为芝加哥时间
ZonedDateTime chicagoDateTime = tokyoDateTime.toInstant().atZone(ZoneId.of("America/Chicago"));
System.out.println(chicagoDateTime);
}
---
2019-06-10T14:19:19.053+08:00[Asia/Shanghai]
2019-06-10T06:19:19.053Z[UTC]
2019-06-10T11:20:20+09:00[Asia/Tokyo]
2019-06-09T21:20:20-05:00[America/Chicago]
- 时间调整(TemporalAdjuster)
public static void main(String ... args) {
LocalDateTime localDateTime = LocalDateTime.now();
// 本年本月最后一天
System.out.println(localDateTime.with(TemporalAdjusters.lastDayOfMonth()));
// 本年本月第一天
System.out.println(localDateTime.with(TemporalAdjusters.firstDayOfMonth()));
// 本年下一月第一天
System.out.println(localDateTime.with(TemporalAdjusters.firstDayOfNextMonth()));
// 下一年第一天
System.out.println(localDateTime.with(TemporalAdjusters.firstDayOfNextYear()));
// 本年最后一天
System.out.println(localDateTime.with(TemporalAdjusters.lastDayOfYear()));
// 下一个周五
System.out.println(localDateTime.with(TemporalAdjusters.next(DayOfWeek.FRIDAY)));
// 本月第一个周五
System.out.println(localDateTime.with(TemporalAdjusters.firstInMonth(DayOfWeek.FRIDAY)));
// 本月最后一个周五
System.out.println(localDateTime.with(TemporalAdjusters.lastInMonth(DayOfWeek.FRIDAY)));
// 下一个周五,如果当前是周五则返回当前时间
System.out.println(localDateTime.with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY)));
// 前一个周五
System.out.println(localDateTime.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY)));
// 前一个周五,如果当前是周五则返回当前时间
System.out.println(localDateTime.with(TemporalAdjusters.previousOrSame(DayOfWeek.FRIDAY)));
}
---
2019-06-30T14:29:50.960
2019-06-01T14:29:50.960
2019-07-01T14:29:50.960
2020-01-01T14:29:50.960
2019-12-31T14:29:50.960
2019-06-14T14:29:50.960
2019-06-07T14:29:50.960
2019-06-28T14:29:50.960
2019-06-14T14:29:50.960
2019-06-07T14:29:50.960
2019-06-07T14:29:50.960
- 计算日期时间差异
public static void main(String ... args) {
// 通过Period计算年龄
LocalDate birthDay = LocalDate.of(1992, 02, 25);
LocalDate localDate = LocalDate.now();
Period period = Period.between(birthDay, localDate);
System.out.printf("%d 岁 %d 月 %d 天 %n", period.getYears(), period.getMonths(), period.getDays());
// 计算时间差值
Instant instant = Instant.now();
Instant instant1 = instant.plus(Duration.ofMinutes(2));
Duration duration = Duration.between(instant, instant1);
System.out.println(duration.getSeconds());
System.out.println(duration.toMillis());
// 按某一单位维度计算差值
LocalDateTime localDateTime = LocalDateTime.of(2019, 05, 20, 10, 10, 10);
LocalDateTime localDateTime1 = LocalDateTime.now();
Long dayDiff = ChronoUnit.DAYS.between(birthDay, localDate);
System.out.println(dayDiff);
Long miniteDiff = ChronoUnit.MINUTES.between(localDateTime, localDateTime1);
System.out.println(miniteDiff);
}
---
27 岁 3 月 16 天
120
120000
9967
30553
- 时间打印
public static void main(String ... args) {
LocalDateTime localDateTime = LocalDateTime.of(2019, 06,10, 10, 10, 10);
System.out.println(localDateTime.format(DateTimeFormatter.BASIC_ISO_DATE));
System.out.println(localDateTime.format(DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss")));
LocalDateTime localDateTime1 = LocalDateTime.parse("20190610 00:00:00", DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss"));
System.out.println(localDateTime1);
}
---
20190610
20190610 10:10:10
2019-06-10T00:00
- 判断是否闰年
public static void main(String ... args) {
LocalDate localDate = LocalDate.now();
System.out.println(localDate.isLeapYear());
}
---
false
- 判断前后
public static void main(String ... args) {
LocalDateTime localDateTime = LocalDateTime.now();
LocalDateTime localDateTime1 = LocalDateTime.of(2019, 05, 20, 10, 10, 10);
System.out.println(localDateTime.isAfter(localDateTime1));
System.out.println(localDateTime.isBefore(localDateTime1));
}
---
true
false