java时间API总结笔记

374 阅读2分钟

时间相关小知识

  • 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);
}