• Java8新特性--新的时间和日期API


    1. 对时间的处理 Date-Time API

    这是对java.util.Date强有力的补充,解决了 Date 类的大部分痛点:
    1.非线程安全
    2. 时区处理麻烦
    3. 各种格式化、和时间计算繁琐
    4. 设计有缺陷,Date 类同时包含日期和时间;还有一个 java.sql.Date,容易混淆。
    常用的时间实例来对比 java.util.Date 和新 Date 有什么区别。用java.util.Date的代码该改改了。

    1.1 java.time 主要类

    java.util.Date 既包含日期又包含时间,而 java.time 把它们进行了分离

    LocalDateTime.class //日期+时间 format: yyyy-MM-ddTHH:mm:ss.SSS
    LocalDate.class //日期 format: yyyy-MM-dd
    LocalTime.class //时间 format: HH:mm:ss
    
    • 1
    • 2
    • 3

    1.2 格式化

    Java 8 之前:

    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public void oldFormat(){
        Date now = new Date();
        //format yyyy-MM-dd HH:mm:ss
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String date  = sdf.format(now);
        System.out.println(String.format("date format : %s", date));
        
        result: date format : 2022-09-22
    ------------------------------------------------------------------
        //format HH:mm:ss
        SimpleDateFormat sdft = new SimpleDateFormat("HH:mm:ss");
        String time = sdft.format(now);
        System.out.println(String.format("time format : %s", time));
    
        result: time format : 10:00:31
    ------------------------------------------------------------------
        //format yyyy-MM-dd HH:mm:ss
        SimpleDateFormat sdfdt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String datetime = sdfdt.format(now);
        System.out.println(String.format("dateTime format : %s", datetime));
        
        result: dateTime format : 2022-09-22 10:00:31
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    Java 8 之后:

    import java.time.LocalDate;
    import java.time.LocalDateTime;
    import java.time.LocalTime;
    import java.time.format.DateTimeFormatter;
    
    public void newFormat(){
        //format yyyy-MM-dd
        LocalDate date = LocalDate.now();
        System.out.println(String.format("date format : %s", date));
    
        result:date format : 2022-09-22
    ------------------------------------------------------------------
        //format HH:mm:ss
        LocalTime time = LocalTime.now().withNano(0);
        System.out.println(String.format("time format : %s", time));
        
        result:time format : 10:05:21
    ------------------------------------------------------------------
        //format yyyy-MM-dd HH:mm:ss
        LocalDateTime dateTime = LocalDateTime.now();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String dateTimeStr = dateTime.format(dateTimeFormatter);
        System.out.println(String.format("dateTime format : %s", dateTimeStr));
        
        result:dateTime format : 2022-09-22 10:06:49
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    1.3 字符串转日期格式

    Java 8 之前:

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    Date date1 = sdf.parse("2022-09-20");
    
    • 1
    • 2

    Java 8 之后:

    LocalDate date = LocalDate.of(2022, 7, 6);
    LocalDate.parse("2022-07-06");
    
    LocalDateTime dateTime = LocalDateTime.of(2021, 1, 26, 12, 12, 22);
    LocalDateTime.parse("2021-01-26 12:12:22");
    
    LocalTime time = LocalTime.of(12, 12, 22);
    LocalTime.parse("12:12:22");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Java 8 之前 转换都需要借助 SimpleDateFormat 类,而Java 8 之后只需要 LocalDate、LocalTime、LocalDateTime的 of 或 parse 方法

    1.4 日期计算:

    1.4.1一周后日期为例

    Java8之前

    public void afterDay(){
         //一周后的日期
         SimpleDateFormat formatDate = new SimpleDateFormat("yyyy-MM-dd");
         Calendar ca = Calendar.getInstance();
         ca.add(Calendar.DATE, 7);
         Date d = ca.getTime();
         String after = formatDate.format(d);
         System.out.println("一周后日期:" + after);
    
         //算两个日期间隔多少天,计算间隔多少年,多少月方法类似
         String dates1 = "2021-12-23";
         String dates2 = "2021-02-26";
         SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
         Date date1 = format.parse(dates1);
         Date date2 = format.parse(dates2);
         int day = (int) ((date1.getTime() - date2.getTime()) / (1000 * 3600 * 24));
         System.out.println(dates2 + "和" + dates2 + "相差" + day + "天");
         //结果:2021-12-23和2021-02-23相差300天
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Java 8 之后:

    public void pushWeek(){
         //一周后的日期
         LocalDate localDate = LocalDate.now();
         //方法1
         LocalDate after = localDate.plus(1, ChronoUnit.WEEKS);
         //方法2
         LocalDate after2 = localDate.plusWeeks(1);
         System.out.println("一周后日期:" + after);
    
         //算两个日期间隔多少天,计算间隔多少年,多少月
         LocalDate date1 = LocalDate.parse("2021-02-26");
         LocalDate date2 = LocalDate.parse("2021-12-23");
         Period period = Period.between(date1, date2);
         System.out.println("date1 到 date2 相隔:"
                    + period.getYears() + "年"
                    + period.getMonths() + "月"
                    + period.getDays() + "天");
                     //打印结果是 “date1 到 date2 相隔:0年9月27天”
         //这里period.getDays()得到的天是抛去年月以外的天数,并不是总天数
         //如果要获取纯粹的总天数应该用下面的方法
         long day = date2.toEpochDay() - date1.toEpochDay();
         System.out.println(date2 + "和" + date2 + "相差" + day + "天");
         //打印结果:2021-12-23和2021-12-23相差300天
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    1.4.2获取指定日期

    Java8之前

    public void getDay() {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            //获取当前月第一天:
            Calendar c = Calendar.getInstance();
            c.set(Calendar.DAY_OF_MONTH, 1);
            String first = format.format(c.getTime());
            System.out.println("first day:" + first);
    
            //获取当前月最后一天
            Calendar ca = Calendar.getInstance();
            ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));
            String last = format.format(ca.getTime());
            System.out.println("last day:" + last);
    
            //当年最后一天
            Calendar currCal = Calendar.getInstance();
            Calendar calendar = Calendar.getInstance();
            calendar.clear();
            calendar.set(Calendar.YEAR, currCal.get(Calendar.YEAR));
            calendar.roll(Calendar.DAY_OF_YEAR, -1);
            Date time = calendar.getTime();
            System.out.println("last day:" + format.format(time));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    Java 8 之后:

    public void getDayNew() {
        LocalDate today = LocalDate.now();
        //获取当前月第一天:
        LocalDate firstDayOfThisMonth = today.with(TemporalAdjusters.firstDayOfMonth());
        // 取本月最后一天
        LocalDate lastDayOfThisMonth = today.with(TemporalAdjusters.lastDayOfMonth());
        //取下一天:
        LocalDate nextDay = lastDayOfThisMonth.plusDays(1);
        //当年最后一天
        LocalDate lastday = today.with(TemporalAdjusters.lastDayOfYear());
        //2021年最后一个周日,如果用Calendar是不得烦死。
        LocalDate lastMondayOf2021 = LocalDate.parse("2021-12-31").with(TemporalAdjusters.lastInMonth(DayOfWeek.SUNDAY));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    java.time.temporal.TemporalAdjusters 里面还有很多便捷的算法
    
    • 1

    1.5 时区

    时区:正式的时区划分为每隔经度 15° 划分一个时区,全球共 24 个时区,每个时区相差 1 小时。但为了行政上的方便,常将 1 个国家或 1 个省份划在一起,比如我国幅员宽广,大概横跨 5 个时区,实际上只用东八时区的标准时即北京时间为准。

    java.util.Date 对象实质上存的是 1970 年 1 月 1 日 0 点( GMT)至 Date 对象所表示时刻所经过的毫秒数。也就是说不管在哪个时区 new Date,它记录的毫秒数都一样,和时区无关。但在使用上应该把它转换成当地时间,这就涉及到了时间的国际化。java.util.Date 本身并不支持国际化,需要借助 TimeZone。

    //北京时间:Thu Sep 22 11:10:52 CST 2022
    Date date = new Date();
    
    SimpleDateFormat bjSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    //北京时区
    bjSdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
    System.out.println("毫秒数:" + date.getTime() + ", 北京时间:" + bjSdf.format(date));
    
    result:毫秒数:1663816337361, 北京时间:2022-09-22 11:12:17
    
    -------------------------------------------------------------
    //东京时区
    SimpleDateFormat tokyoSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    tokyoSdf.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo"));  // 设置东京时区
    System.out.println("毫秒数:" + date.getTime() + ", 东京时间:" + tokyoSdf.format(date));
    
    result:毫秒数:1663816337361, 东京时间:2022-09-22 12:12:17
    
    --------------------------------------------------------
    //如果直接print会自动转成当前时区的时间
    System.out.println(date);
    //Thu Sep 22 11:12:17 CST 2022
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    Java8中在新特性中引入了 java.time.ZonedDateTime 来表示带时区的时间。它可以看成是 LocalDateTime + ZoneId

    import java.time.LocalDateTime;
    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    
    // 当前时区时间
    ZonedDateTime zonedDateTime = ZonedDateTime.now();
    System.out.println("当前时区时间: " + zonedDateTime);
    
    result:当前时区时间: 2022-09-22T11:17:00.542+08:00[Asia/Shanghai]
    --------------------------------------------------------
    // 东京时间
    ZoneId zoneId = ZoneId.of(ZoneId.SHORT_IDS.get("JST"));
    ZonedDateTime tokyoTime = zonedDateTime.withZoneSameInstant(zoneId);
    System.out.println("东京时间: " + tokyoTime);
    
    result:东京时间: 2022-09-22T12:17:00.542+09:00[Asia/Tokyo]
    --------------------------------------------------------
    // ZonedDateTime 转 LocalDateTime
    LocalDateTime localDateTime = tokyoTime.toLocalDateTime();
    System.out.println("东京时间转当地时间: " + localDateTime);
    
    result:东京时间转当地时间: 2022-09-22T12:17:00.542
    --------------------------------------------------------
    // LocalDateTime 转 ZonedDateTime
    ZonedDateTime localZoned = localDateTime.atZone(ZoneId.systemDefault());
    System.out.println("本地时区时间: " + localZoned);
    
    result:本地时区时间: 2022-09-22T12:17:00.542+08:00[Asia/Shanghai]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    通过上面比较新老 Date 的不同,当然只列出部分功能上的区别,更多功能还得自己去挖掘。总之 date-time-api 给日期操作带来了福利。在日常工作中遇到 date 类型的操作,第一考虑的是 date-time-api,实在解决不了再考虑老的 Date

    小结

    通过上面比较新老 Date 的不同,当然只列出部分功能上的区别,更多功能还得自己去挖掘。总之 date-time-api 给日期操作带来了福利。在日常工作中遇到 date 类型的操作,第一考虑的是 date-time-api,实在解决不了再考虑老的 Date

    附录

    1.参考书籍《Java8实战》
    2.参考博客 JavaGuide

  • 相关阅读:
    红黑树(4万字文章超详细,只为一个目的)
    app小程序手机端Python爬虫实战11实现自动化登录考研帮app并滑动资讯信息
    关于log4j安全漏洞以及版本替换的记录
    HCIP-MGRE实验
    Opencv源码解析(2)算法
    微信支付申请
    产品力如何驱动SaaS企业新增长?
    Dubbo框架实现RPC远程调用包括nacos的配置和初始化
    放弃深圳高薪工作回老家
    react hook:useMemo
  • 原文地址:https://blog.csdn.net/Blue_Pepsi_Cola/article/details/127701712