时间相关小知识
- UTC指的是Coordinated Universal Time- 世界协调时间(又称世界标准时间、世界统一时间)UTC时间+时区偏移量就是当地时间,如北京东8区(GMT+8),则UTC时间+08小时就表示北京时间
- ISO-8601是日期和时间的表示方法全称为《数据存储和交换形式·信息交换·日期和时间的表示方法》,这个规则的时间返回的时间格式在年月日和具体时分秒中有一个T作为分隔符,用字母T分割日期和时间。如20180703T224426Z或2018-07-03T22:44:26Z。
- 在java8中新增的LocalDateTime等相关时间类就是基于ISO-8601标准开发的,在这个标准上做了加强操作。
java8新增的时间api汇总信息
- LocalDate :表示当前日期,相当于:yyyy-MM-dd
- LocalTime :表示当前时间,相当于:HH:mm:ss (24小时制) 或者 hh:mm:ss(12小时制)
- LocalDateTime :表示当前日期时间,相当于:yyyy-MM-ddTHH:mm:ss ,是前两者的结合
- OffsetDateTime : 在LocalDateTime基础上带有时区信息 yyyy-MM-ddTHH:mm:ss+时区,实例 2021-04-28T10:37:39.256+08:00
- ZonedDateTime :在 OffsetDateTime的基础上带有具体的时区信息 yyyy-MM-ddTHH:mm:ss+时区[Asia/Shanghai],实例 2021-04-28T10:49:32.772+08:00[Asia/Shanghai]
- DateTimeFormatter :表示格式化类型,可以取代SimpleDateFormat
- Duration :表示两个时刻之间的时间间隔
- Period :表示两个日期之间的天数
- TemporalAdjusters、TemporalAdjuster :时间调节器
- Instant :表示时刻,用来表示时间线上的一个点(瞬时),也可以说是时间戳
- ZoneId、ZoneOffset :表示时区
传统Date
public void dateTest(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date();
//默认北京时区的时间
log.info("北京时区:{}", sdf.getTimeZone());
log.info("北京时区时间:{}", sdf.format(date));
sdf.setTimeZone(TimeZone.getTimeZone(ZoneId.of("Australia/Brisbane")));
log.info("布里斯班:{}", sdf.getTimeZone());
log.info("布里斯班:{}", sdf.format(date));
}
LocalDate、LocalTime、LocalDateTime 格式区别
public void localDateTimeFormat() {
// 2022-04-28 yyyy-mm-dd
LocalDate localDate = LocalDate.now();
// 09:50:27.908 hh:mm:ss.sss
LocalTime localTime = LocalTime.now();
// 2022-04-28T09:50:27.908 yyyy-mm-dd T hh:mm:ss.sss
LocalDateTime localDateTime = LocalDateTime.now();
log.info("localDate :{}", localDate);
log.info("localTime :{}", localTime);
log.info("localDateTime :{}", localDateTime);
}
LocalDateTime 常用api
public void localDateTimeToolTest() throws InterruptedException {
LocalDateTime firstTime = LocalDateTime.now();
log.error("firstTime时间:{}", firstTime);
TimeUnit.SECONDS.sleep(1);
LocalDateTime second = firstTime.plusDays(1);
log.error("second时间:{}", second);
boolean after = firstTime.isAfter(second);
log.error("firstTime是在second后面吗(firstTime > second):{}", after);
boolean before = firstTime.isBefore(second);
log.error("firstTime是在second前面吗(firstTime < second):{}", before);
boolean equal = firstTime.isEqual(second);
log.error("firstTime和second时间相等吗:{}", equal);
LocalDateTime addDay = second.plusDays(1);
log.error("second加一天后时间:{}", addDay);
LocalDateTime minusDay = second.minusDays(1);
log.error("second减一天后时间:{}", minusDay);
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
LocalDateTime parse = LocalDateTime.parse("20220506101801", dateTimeFormatter);
log.error("解析时间:{}", parse);
String format = parse.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"));
log.error("转换为固定格式的字符串:{}", format);
LocalDateTime of = LocalDateTime.of(2022, 4, 28, 15, 16, 17);
log.error("指定日期:{}", of);
LocalDateTime now = LocalDateTime.now(ZoneId.of("Australia/Brisbane"));
log.error("其他时区相对此服务器时区的时间:{}", now);
ZoneId zoneId = TimeZone.getDefault().toZoneId();
log.error("系统默认时区:{}", zoneId);
}
OffsetDateTime、ZonedDateTime 和 LocalDateTime的api类似
// 2022-04-28T10:37:39.256+08:00 带有时区
OffsetDateTime start = OffsetDateTime.now();
log.info("start开始时间:{}", start);
TimeUnit.SECONDS.sleep(1);
OffsetDateTime end = OffsetDateTime.now();
log.info("end结束时间:{}", end);
OffsetTime offsetTime = OffsetTime.now();
log.info("offsetTime:{}", offsetTime);
// 2022-04-28T10:49:32.772+08:00[Asia/Shanghai] 格式
ZonedDateTime start = ZonedDateTime.now();
log.info("start开始时间:{}", start);
Duration、Period
Duration、Period的时间格式如下:
- P1Y2M10DT2H30M15S
- P 开始标记
- 1Y - 一年
- 2M - 两个月
- 10D - 十天
- T - 时间和日期分的割标记
- 2H - 两个小时
- 30M - 三十分钟
- 15S - 十五秒钟
- 例子,注意如果没有年月日,"T"也不能省略。
public void toolTest() {
Duration between = Duration.between(LocalDateTime.now(), LocalDateTime.now().plusDays(1));
long days = between.toDays();
long hours = between.toHours();
long minutes = between.toMinutes();
long millis = between.toMillis();
long nanos = between.toNanos();
log.info("天:{},小时:{},分钟:{},秒:{},纳秒:{}", days, hours, minutes, millis, nanos);
boolean negative = between.isNegative();
boolean zero = between.isZero();
log.info("negative:{},zero:{}", negative, zero);
//Period 工具 -- 映射 LocalDate
LocalDate start = LocalDate.now();
LocalDate end = LocalDate.now().plusDays(33);
Period betweenPeriod = Period.between(start, end);
long months = betweenPeriod.toTotalMonths();
log.info("月:{}", months);
LocalDateTime max = LocalDateTime.MAX;
LocalDateTime min = LocalDateTime.MIN;
log.info("LocalDateTime-max:{}", max);
log.info("LocalDateTime-min:{}", min);
Duration durationStart = Duration.between(LocalDateTime.now(), LocalDateTime.now().plusDays(1));
Duration durationEnd = Duration.between(LocalDateTime.now(), LocalDateTime.now().plusDays(3));
Duration minus = durationStart.minus(durationEnd);
log.info("durationStart-durationEnd minus:{}", minus);
boolean negativeMark = minus.isNegative();
log.info("可以用于判断是否过期 negativeMark:{}", negativeMark);
}
TemporalAdjusters、TemporalAdjuster时间调节器
public void temporalTest() {
LocalDateTime startTime = LocalDateTime.now();
TimeUnit.SECONDS.sleep(10);
LocalDateTime endTime = LocalDateTime.now();
Duration between = Duration.between(startTime, endTime);
long hours = between.toHours();
log.info("小时:{}", hours);
long millis = between.toMillis();
log.info("毫秒:{}", millis);
long nanos = between.toNanos();
log.info("纳秒:{}", nanos);
LocalDateTime firstDayOfMonth = LocalDateTime.now().with(TemporalAdjusters.firstDayOfMonth());
log.info("当月第一天 firstDayOfMonth:{}", firstDayOfMonth);
LocalDateTime firstDayOfNextMonth = LocalDateTime.now().with(TemporalAdjusters.firstDayOfNextMonth());
log.info("下个月第一天 firstDayOfNextMonth:{}", firstDayOfNextMonth);
LocalDateTime firstDayOfNextYear = LocalDateTime.now().with(TemporalAdjusters.firstDayOfNextYear());
log.info("下个月第一天 firstDayOfNextYear:{}", firstDayOfNextYear);
LocalDateTime dayOfWeekInMonth = LocalDateTime.now().with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.MONDAY));
log.info("当月第二个星期一 dayOfWeekInMonth:{}", dayOfWeekInMonth);
//当月的第N个星期几
LocalDateTime nextMonday = LocalDateTime.now().with(TemporalAdjusters.next(DayOfWeek.MONDAY));
log.info("下个星期一 nextMonday:{}", nextMonday);
//下个星期几
// 2022-04-28 01:00:00 周一
// nextOrSame
// 如果参数是 DayOfWeek.MONDAY 周一
// 输出结果就是当前时间 否则就是下一个周一
// nextOrSame 输出下一个周几 如果刚好当前时间周几和需要的 DayOfWeek.MONDAY 相同就输出本身 否则就输出最近的周几
LocalDateTime customTime = LocalDateTime.of(2022, 4, 25, 1, 0, 0);
LocalDateTime nextOrSameMonday = customTime.with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY));
log.info("下个星期一或者当前的日期 nextOrSameMonday:{}", nextOrSameMonday);
}
// 获取下工作日
public void getNextBusinessDay() {
// 这种写法可以实现比较复杂的操作
LocalDateTime nextWorkDay = LocalDateTime.now().with(tempDateTime -> {
LocalDateTime localDateTime = (LocalDateTime) tempDateTime;
DayOfWeek dayOfWeek = localDateTime.getDayOfWeek();
if (dayOfWeek.equals(DayOfWeek.FRIDAY)) {
// 周五 加三天
return localDateTime.plusDays(3);
} else if (dayOfWeek.equals(DayOfWeek.SATURDAY)) {
// 周六 加两天
return localDateTime.plusDays(2);
} else {
// 其他情况加一天
return localDateTime.plusDays(1);
}
});
log.info("下一个工作日nextWorkDay:{}", nextWorkDay);
}
Date、LocalDateTime 互转
public void dateToLocalDateTime() {
//Date 转 LocalDateTime
LocalDateTime localDateTime = LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault());
log.info("Date 转 LocalDateTime:{}", localDateTime);
// LocalDateTime 转 Date
Date from = Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());
log.info("LocalDateTime 转 Date:{}", from);
}
Date、Instant 互转
private void instantTest(){
//获取本初子午线对应的标准时间== 时区开始时间 (时区为0的时间)
Instant now = Instant.now();
System.out.println(now);
// Instant 转 Date
Date from = Date.from(now);
System.out.println(from);
//Date 转 Instant
Instant instant = new Date().toInstant();
System.out.println(instant);
}