• JDK 1.8 完整日期时间Api (文末附示例)


    一、背景

    jdk 1.8 之前, Java 时间使用java.util.Datejava.util.Calendar 类。

    Date today = new Date();
    System.out.println(today);
    	
     // 转为字符串
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String todayStr = sdf.format(today);
    System.out.println(todayStr);
    

    Date 的几个问题:

    1. 如果不格式化,Date打印出的日期可读性差;
    2. 可以使用 SimpleDateFormat 对时间进行格式化,但 SimpleDateFormat 是线程不安全的(阿里巴巴开发手册中禁用static修饰SimpleDateFormat);
    3. Date对时间处理比较麻烦,比如想获取某年、某月、某星期,以及 n 天以后的时间,如果用Date来处理的话真是太难了,并且 Date 类的 getYear()getMonth() 这些方法都被弃用了;

    二、JDK 1.8 新的日期时间类型

    Java8引入的新的一系列API,对时间日期的处理提供了更好的支持,清楚的定义了时间日期的一些概念,比如说,瞬时时间(Instant),持续时间(duration),日期(date),时间(time),时区(time-zone)以及时间段(Period)。

    1. LocalDate:不包含时间的日期,比如2019-10-14。可以用来存储生日,周年纪念日,入职日期等。
    2. LocalTime:与LocalDate想对照,它是不包含日期的时间。
    3. LocalDateTime:包含了日期及时间,没有偏移信息(时区)。
    4. ZonedDateTime:包含时区的完整的日期时间,偏移量是以UTC/格林威治时间为基准的。
    5. Instant:时间戳,与System.currentTimeMillis()类似。
    6. Duration:表示一个时间段。
    7. Period:用来表示以年月日来衡量一个时间段。
    8. DateTimeFormatter:新的日期解析格式化类。

    2.1 LocalDate

    LocalDate类内只包含日期,不包含具体时间。只需要表示日期而不包含时间,就可以使用它。

    public static void localDate() {
        //获取当前年月日
        LocalDate today = LocalDate.now();
        System.out.println("当前年月日:" + today);
    
        // 获取年的两种方式
        int thisYear = today.getYear();
        int thisYearAnother = today.get(ChronoField.YEAR);
        System.out.println("今年是" + thisYear + "年");
        System.out.println("今年是" + thisYearAnother + "年");
    
        // 获取月
        Month thisMonth = today.getMonth();
        System.out.println(thisMonth.toString());
        // 这是今年的第几个月(两种写法)
        int monthOfYear = today.getMonthValue();
        // int monthOfYear = today.get(ChronoField.MONTH_OF_YEAR);
        System.out.println("这个月是今年的第" + monthOfYear + "个月");
        // 月份的天数
        int length = today.lengthOfMonth();
        System.out.println("这个月有" + length + "天");
    
        // 获取日的两种方式
        int thisDay = today.getDayOfMonth();
        int thisDayAnother = today.get(ChronoField.DAY_OF_MONTH);
        System.out.println("今天是这个月的第" + thisDay + "天");
        System.out.println("今天是这个月的第" + thisDayAnother + "天");
    
        // 获取星期
        DayOfWeek thisDayOfWeek = today.getDayOfWeek();
        System.out.println(thisDayOfWeek.toString());
        // 今天是这周的第几天
        int dayOfWeek = today.get(ChronoField.DAY_OF_WEEK);
        System.out.println("今天是这周的第" + dayOfWeek + "天");
    
        // 是否为闰年
        boolean leapYear = today.isLeapYear();
        System.out.println("今年是闰年:" + leapYear);
    
        //构造指定的年月日
        LocalDate anotherDay = LocalDate.of(2008, 8, 8);
        System.out.println("指定年月日:" + anotherDay);
    }
    

    2.2 LocalTime

    LocalTime只会获取时间,不获取日期。LocalTimeLocalDate类似,区别在于LocalDate不包含具体时间,而LocalTime不包含具体日期。

    public static void localTime() {
        // 获取当前时间
        LocalTime nowTime = LocalTime.now();
        System.out.println("当前时间:" + nowTime);
    
        //获取小时的两种方式
        int hour = nowTime.getHour();
        int thisHour = nowTime.get(ChronoField.HOUR_OF_DAY);
        System.out.println("当前时:" + hour);
        System.out.println("当前时:" + thisHour);
    
    
        //获取分的两种方式
        int minute = nowTime.getMinute();
        int thisMinute = nowTime.get(ChronoField.MINUTE_OF_HOUR);
        System.out.println("当前分:" + minute);
        System.out.println("当前分:" + thisMinute);
    
        //获取秒的两种方式
        int second = nowTime.getSecond();
        int thisSecond = nowTime.get(ChronoField.SECOND_OF_MINUTE);
        System.out.println("当前秒:" + second);
        System.out.println("当前秒:" + thisSecond);
    
        // 构造指定时间(最多可到纳秒)
        LocalTime anotherTime = LocalTime.of(20, 8, 8);
        System.out.println("构造指定时间:" + anotherTime);
    }
    

    2.3 LocalDateTime

    LocalDateTime表示日期和时间组合。可以通过of()方法直接创建,也可以调用LocalDateatTime()方法或LocalTimeatDate()方法将LocalDateLocalTime合并成一个LocalDateTime

    public static void localDateTime() {
        // 当前日期和时间
        LocalDateTime today = LocalDateTime.now();
        System.out.println("现在是:" + today);
    
        // 创建指定日期和时间
        LocalDateTime anotherDay = LocalDateTime.of(2008, Month.AUGUST, 8, 8, 8, 8);
        System.out.println("创建的指定时间是:" + anotherDay);
    
        // 拼接日期和时间
        // 使用当前日期,指定时间生成的 LocalDateTime
        LocalDateTime thisTime = LocalTime.now().atDate(LocalDate.of(2008, 8, 8));
        System.out.println("拼接的日期是:" + thisTime);
        // 使用当前日期,指定时间生成的 LocalDateTime
        LocalDateTime thisDay = LocalDate.now().atTime(LocalTime.of(12, 24, 12));
        System.out.println("拼接的日期是:" + thisDay);
        // 指定日期和时间生成 LocalDateTime
        LocalDateTime thisDayAndTime = LocalDateTime.of(LocalDate.of(2008, 8, 8), LocalTime.of(12, 24, 12));
        System.out.println("拼接的日期是:" + thisDayAndTime);
    
        // 获取LocalDate
        LocalDate todayDate = today.toLocalDate();
        System.out.println("今天日期是:" + todayDate);
    
        // 获取LocalTime
        LocalTime todayTime = today.toLocalTime();
        System.out.println("现在时间是:" + todayTime);
    }
    

    2.4 Instant

    Instant用于一个获取时间戳,与System.currentTimeMillis()类似,但Instant可以精确到纳秒。

    public class InstantDemo {
    
        public static void main(String[] args) {
    
            // 创建Instant对象
            Instant instant = Instant.now();
            // 通过ofEpochSecond方法创建(第一个参数表示秒,第二个参数表示纳秒)
            Instant another = Instant.ofEpochSecond(365 * 24 * 60, 100);
    
            // 获取到秒数
            long currentSecond = instant.getEpochSecond();
            System.out.println("获取到秒数:" + currentSecond);
    
            // 获取到毫秒数
            long currentMilli = instant.toEpochMilli();
            System.out.println("获取到毫秒数:" + currentMilli);
        }
    }
    

    2.5 Duration

    Duration的内部实现与Instant类似,但Duration表示时间段,通过between方法创建,还可以通过of()方法创建。

    public static void duration() {
        LocalDateTime from = LocalDateTime.now();
        LocalDateTime to = LocalDateTime.now().plusDays(1);
        // 通过between()方法创建
        Duration duration = Duration.between(from, to);
        // 通过of()方法创建,该方法参数为时间段长度和时间单位。
        // 7天
        Duration duration1 = Duration.of(7, ChronoUnit.DAYS);
        // 60秒
        Duration duration2 = Duration.of(60, ChronoUnit.SECONDS);
    }
    

    2.5 Period

    PeriodDuration类似,获取一个时间段,只不过单位为年月日,也可以通过of方法和between方法创建,between方法接收的参数为LocalDate

    private static void period() {
        // 通过of方法
        Period period = Period.of(2012, 12, 24);
        // 通过between方法
        Period period1 = Period.between(LocalDate.now(), LocalDate.of(2020,12,31));
    }
    

    三、时间操作

    3.1 时间比较

    isBefore()isAfter()判断给定的时间或日期是在另一个时间/日期之前还是之后。
    LocalDate为例,LocalDateTime/LocalTime 同理。

    public static void compare() {
        LocalDate thisDay = LocalDate.of(2008, 8, 8);
        LocalDate otherDay = LocalDate.of(2018, 8, 8);
    
        // 晚于
        boolean isAfter = thisDay.isAfter(otherDay);
        System.out.println(isAfter);
    
        // 早于
        boolean isBefore = thisDay.isBefore(otherDay);
        System.out.println(isBefore);
    }
    

    3.2 增加/减少年数、月数、天数

    LocalDateTime为例,LocalDate/LocalTime同理。

    public static void plusAndMinus() {
        // 增加
        LocalDateTime today = LocalDateTime.now();
        LocalDateTime nextYearDay = today.plusYears(1);
        System.out.println("下一年的今天是:" + nextYearDay);
        LocalDateTime nextMonthDay = today.plus(1, ChronoUnit.MONTHS);
        System.out.println("下一个月的今天是:" + nextMonthDay);
    
        //减少
        LocalDateTime lastMonthDay = today.minusMonths(1);
        LocalDateTime lastYearDay = today.minus(1, ChronoUnit.YEARS);
        System.out.println("一个月前是:" + lastMonthDay);
        System.out.println("一年前是:" + lastYearDay);
    }
    

    3.3 时间修改

    通过with修改时间

    public static void edit() {
        LocalDateTime today = LocalDateTime.now();
        // 修改年为2012年
        LocalDateTime thisYearDay = today.withYear(2012);
        System.out.println("修改年后的时间为:" + thisYearDay);
        // 修改为12月
        LocalDateTime thisMonthDay = today.with(ChronoField.MONTH_OF_YEAR, 12);
        System.out.println("修改月后的时间为:" + thisMonthDay);
    }
    

    3.4 时间计算

    通过 TemporalAdjusters 的静态方法 和 Duration 计算时间

    public static void compute() {
        // TemporalAdjusters 的静态方法
        LocalDate today = LocalDate.now();
        // 获取今年的第一天
        LocalDate date = today.with(firstDayOfYear());
        System.out.println("今年的第一天是:" + date);
    
        // Duration 计算
        LocalDateTime from = LocalDateTime.now();
        LocalDateTime to = LocalDateTime.now().plusMonths(1);
        Duration duration = Duration.between(from, to);
    
        // 区间统计换算
        // 总天数
        long days = duration.toDays();
        System.out.println("相隔" + days + "天");
        // 小时数
        long hours = duration.toHours();
        System.out.println("相隔" + hours + "小时");
        // 分钟数
        long minutes = duration.toMinutes();
        System.out.println("相隔" + minutes + "分钟");
    }
    
    • TemporalAdjusters的更多方法
    方法名称 描述
    dayOfWeekInMonth() 返回同一个月中每周的第几天
    firstDayOfMonth() 返回当月的第一天
    firstDayOfNextMonth() 返回下月的第一天
    firstDayOfNextYear() 返回下一年的第一天
    firstDayOfYear() 返回本年的第一天
    firstInMonth() 返回同一个月中第一个星期几
    lastDayOfMonth() 返回当月的最后一天
    lastDayOfNextMonth() 返回下月的最后一天
    lastDayOfNextYear() 返回下一年的最后一天
    lastDayOfYear() 返回本年的最后一天
    lastInMonth() 返回同一个月中最后一个星期几
    next() / previous() 返回后一个/前一个给定的星期几
    nextOrSame() / previousOrSame() 返回后一个/前一个给定的星期几,如果这个值满足条件,直接返回

    四、时间日期格式化

    4.1 格式化时间

    DateTimeFormatter默认提供了多种格式化方式,如果默认提供的不能满足要求,可以通过DateTimeFormatterofPattern方法创建自定义格式化方式。

    public static void format() {
        LocalDate today = LocalDate.now();
        // 两种默认格式化时间方式
        String todayStr1 = today.format(DateTimeFormatter.BASIC_ISO_DATE);
        String todayStr2 = today.format(DateTimeFormatter.ISO_LOCAL_DATE);
        System.out.println("格式化时间:" + todayStr1);
        System.out.println("格式化时间:" + todayStr2);
        //自定义格式化
        DateTimeFormatter dateTimeFormatter =   DateTimeFormatter.ofPattern("dd/MM/yyyy");
        String todayStr3 = today.format(dateTimeFormatter);
        System.out.println("自定义格式化时间:" + todayStr3);
    
    }
    

    4.2 解析时间

    4.1 中以何种方式格式化,这里需以同样方式解析。

    public static void parse() {
        LocalDate date1 = LocalDate.parse("20080808", DateTimeFormatter.BASIC_ISO_DATE);
        LocalDate date2 = LocalDate.parse("2008-08-08", DateTimeFormatter.ISO_LOCAL_DATE);
        System.out.println(date1);
        System.out.println(date2);
    }
    

    五、总结

    相较于Date 的优势

    1. Instant 的精确度更高,可以精确到纳秒级;
    2. Duration 可以便捷得到时间段内的天数、小时数等;
    3. LocalDateTime 能够快速地获取年、月、日、下一月等;
    4. TemporalAdjusters 类中包含许多常用的静态方法,避免自己编写工具类;
    5. Date的格式化方式SimpleDateFormat相比,DateTimeFormatter是线程安全的。

    5.1 示例代码

    Github 示例代码

    5.2 技术交流

    1. 风尘博客
    2. 风尘博客-掘金
    3. 风尘博客-博客园
    4. Github
  • 相关阅读:
    SQL Sever 查询所有触发器和存储过程
    写程序就3步
    LVSDR 模型
    sudo 自动输入密码, ssh 协议自动输入密码
    沪漂至2021 4月住过的地方和房租
    win10 作为jenkins node, 新建服务 service自动连接
    Jenkins windows node 上无法执行 system groovy script
    robotframework 导入python包
    sed 非贪婪匹配
    工作英语jenkins 构建
  • 原文地址:https://www.cnblogs.com/vandusty/p/12269050.html
Copyright © 2020-2023  润新知