• Java8新特性-摆脱坑爹的时间API


    Java8之前的Date有哪些槽点

    槽点一

    最开始的时候,Date既要承载日期信息,又要做日期之间的转换,还要做不同日期格式的显示,职责较繁杂;后来从JDK1.1开始,这三项职责分开了

      1. 使用Calendar类实现日期和时间字段之间转换
      1. 使用DateFormat类来格式化和分析日期字符串
      1. 而Date只用来承载日期和时间信息
    槽点二

    java.util.Date与java.util.Calendar中的所有属性都是可变的,下面的代码,计算两个日期之间的天数…

    // 计算两个日期之间的天数
        private static long daysBetween(Calendar begin, Calendar end) {
            long daysBetween = 0;
            while (begin.before(end)) {
                begin.add(Calendar.DAY_OF_MONTH, 1);
                daysBetween++;
            }
            return daysBetween;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Main方法

    Calendar birth = Calendar.getInstance();
    birth.set(1975, Calendar.MAY, 26);
    Calendar now = Calendar.getInstance();
    System.out.println(daysBetween(birth, now));
    System.out.println(daysBetween(birth, now));
    
    • 1
    • 2
    • 3
    • 4
    • 5

    daysBetween有点问题,如果连续计算两个Date实例的话,第二次会取得0,因为Calendar状态是可变的,考虑到重复计算的场合,最好复制一个新的Calendar

    槽点三

    SimpleDateTimeFormat是非线程安全的

    Java8时间和日期

    类概览

    Java8仍然延用了ISO的日历体系,并且与它的前辈们不同,java.time包中的类是不可变且线程安全的。新的时间及日期API位于java.time包中,下面是里面的一些关键的类:

    • Instant: 时间戳
    • LocalDate: 不包含具体时间的日期,比如2014-01-14。它可以用来存储生日,周年纪念日,入职日期等。
    • LocalTime: 不含日期的时间
    • LocalDateTime: 包含了日期及时间,不过还是没有偏移信息或者说时区
    • ZonedDateTime: 这是一个包含时区的完整的日期时间,偏移量是以UTC/格林威治时间为基准的
      新的库还增加了ZoneOffset及Zoned,可以为时区提供更好的支持。有了新的DateTimeFormatter之后日期的解析及格式化也变得焕然一新了
    方法概览

    改包的API提供了大量相关的方法,这些方法一般有一致的方法前缀

    • of: 静态工厂方法
    • parse: 静态工厂方法,关注于解析
    • get: 获取某些东西的值
    • is: 检查某些东西的值是否是true
    • with: 不可变的setter等价物
    • plus: 加一些量到某个对象
    • minus: 从某个对象减去一些量
    • to: 转换到另一个类型
    • at: 把这个对象与另一个对象组合起来,例如:date.atTime(time)
      例子:
    public class TimeIntroduction {
        public static void main(String[] args) throws InterruptedException {
            testClock();
            System.out.println("===============================");
            testInstant();
            System.out.println("===============================");
            testLocalDateTime();
            System.out.println("===============================");
            testNewOldDateConversion();
            System.out.println("===============================");
            testChronology();
        }
    
        static void testClock() throws InterruptedException {
            // 时钟提供给我们用于访问某个特定时区的瞬时时间、日期和时间
            Clock c1 = Clock.systemUTC();
            System.out.println("系统默认UTC时钟(当前瞬时时间 System.currentTimeMillis(): " + c1.millis()); // 系统默认UTC时钟(当前瞬时时间 System.currentTimeMillis())
            System.out.println("系统默认UTC时钟(当前瞬时时间 System.currentTimeMillis(): " + System.currentTimeMillis());
            Clock c2 = Clock.systemDefaultZone();// 系统默认时区时钟(当前瞬时时间)
            System.out.println(" 系统默认时区时钟(当前瞬时时间): " + c2.millis());
            Clock c31 = Clock.system(ZoneId.of("Europe/Paris"));//巴黎时区
            System.out.println("巴黎时区:" + c31.millis());
            Clock c32 = Clock.system(ZoneId.of("Asia/Shanghai"));
            System.out.println("上海时区: " + c32.millis());
            Clock c4 = Clock.fixed(Instant.now(), ZoneId.of("Asia/Shanghai"));// 固定上海时区时钟
            System.out.println("固定上海时区时钟: " + c4.millis());
            TimeUnit.MILLISECONDS.sleep(1000);
            System.out.println("一秒钟之后,固定上海时区时钟:" + c4.millis()); // 不变,即时钟在那一个点不动
            Clock c5 = Clock.offset(c1, Duration.ofSeconds(2));// 相对于系统默认时钟两秒的时钟
            System.out.println(c1.millis());
            System.out.println(c5.millis());
        }
    
        static void testInstant() throws InterruptedException {
            // 瞬时时间,相当于以前的System.currentTimeMillis
            Instant instant1 = Instant.now();
            System.out.println("精确到秒: " + instant1.getEpochSecond());// 精确到秒 得到相对于1970-01-01 00:00:00 UTC的一个时
            System.out.println("精确到毫秒:" + instant1.toEpochMilli());// 精确到毫秒
            Clock clock1 = Clock.systemUTC();// 获得系统UTC默认时钟
            Instant instant2 = Instant.now(clock1);// 得到时钟的瞬时时间
            System.out.println("精确到毫秒: " + instant2.toEpochMilli());
            Clock clock2 = Clock.fixed(instant1, ZoneId.systemDefault());// 固定瞬时时间时钟
            TimeUnit.MILLISECONDS.sleep(2000);
            Instant instant3 = Instant.now(clock2);// 得到时钟的瞬时时间
            System.out.println("精确到毫秒: " + instant3.toEpochMilli());
        }
    
        static void testLocalDateTime() {
            // 使用默认时区时钟瞬时时间创建 Clock.systemDefaultZone() --> 即相对于 ZoneId.systemDefault() 默认时区
            LocalDateTime now = LocalDateTime.now();
            System.out.println(now);
            LocalDateTime now2 = LocalDateTime.now(ZoneId.of("Europe/Paris"));
            System.out.println(now2);// 会以响应的时区显示日期
            // 自定义时钟
            Clock clock = Clock.system(ZoneId.of("Asia/Dhaka"));
            LocalDateTime now3 = LocalDateTime.now(clock);
            System.out.println(now3);// 会以相应的时区显示日期
    
            LocalDateTime d1 = LocalDateTime.of(2013, 12, 31, 23, 59);
            LocalDateTime d2 = LocalDateTime.of(2013, 12, 31, 23, 59, 59, 11);
            // 使用瞬时时间+时区
            Instant instant = Instant.now();
            LocalDateTime d3 = LocalDateTime.ofInstant(Instant.now(), ZoneId.systemDefault());
            System.out.println(d3);
    
            LocalDateTime d4 = LocalDateTime.parse("2013-12-31T23:59");
            System.out.println(d4);
            LocalDateTime d5 = LocalDateTime.parse("2013-12-31T23:59:59.999");
            System.out.println(d5);
    
    
            //使用DateTimeFormatter API 解析 和 格式化
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
            LocalDateTime d6 = LocalDateTime.parse("2013/12/31 23:59:59", formatter);
            System.out.println(formatter.format(d6));
    
            //时间获取
            System.out.println(d6.getYear());
            System.out.println(d6.getMonth());
            System.out.println(d6.getDayOfYear());
            System.out.println(d6.getDayOfMonth());
            System.out.println(d6.getDayOfWeek());
            System.out.println(d6.getHour());
            System.out.println(d6.getMinute());
            System.out.println(d6.getSecond());
            System.out.println(d6.getNano());
    
    
            //时间增减
            LocalDateTime d7 = d6.minusDays(1);
            LocalDateTime d8 = d7.plus(1, IsoFields.QUARTER_YEARS);
            //LocalDate 即年月日 无时分秒
            //LocalTime即时分秒 无年月日
            //API和LocalDateTime类似就不演示了
    
            // 两个日期是否相等
            System.out.println(d1.equals(d2));
    
            // MonthDay - 用来检查生日
            LocalDate dateOfBirth = LocalDate.of(2010, 01, 14);
            MonthDay birthday = MonthDay.of(dateOfBirth.getMonth(), dateOfBirth.getDayOfMonth());
            MonthDay currentMonthDay = MonthDay.from(ZonedDateTime.now());
            System.out.println(currentMonthDay.equals(birthday));
    
            // YearMonth - 用来检查信用卡过期
            YearMonth currentYearMonth = YearMonth.now(); System.out.printf("Days in month year %s: %d%n", currentYearMonth, currentYearMonth.lengthOfMonth());
            YearMonth creditCardExpiry = YearMonth.of(2018, Month.FEBRUARY);
            System.out.printf("Your credit card expires on %s %n", creditCardExpiry);
    
            // 判断闰年 - LocalDate类有一个isLeapYear()的方法
            System.out.println(dateOfBirth.isLeapYear());
        }
    
        static void testNewOldDateConversion() {
            Instant instant = new Date().toInstant();
            Date date = Date.from(instant);
            System.out.println(instant);
            System.out.println(date);
        }
    
        // 提供对java.util.Calendar的替换,提供对年历系统的支持
        static void testChronology() {
            HijrahChronology instance = HijrahChronology.INSTANCE;
            ChronoLocalDateTime d = instance.localDateTime(LocalDateTime.now());
            System.out.println(d);
        }
    
        // 根据指定formatter类型转换 ”yyyy-MM-dd'T'HH:mm:ss.SSSZ “
        public static String transToFormatterDate(String date, String formatter) {
            LocalDateTime localDate = LocalDateTime.parse(date,DateTimeFormatter.ISO_OFFSET_DATE_TIME);
            return localDate.format(DateTimeFormatter.ofPattern(formatter));
        }
    }
    
    
    • 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
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134

    总结

    • 提供了javax.time.ZoneId用来处理时区
    • 提供了LocalDate与LocalTime类。Java8中新的时间与日期API中的所有类都是不可变且线程安全的,这与之前的Date和Calendar API中的恰好相反,那里面想java.util.Date以及SimpleDateFormat这些关键的类都不是线程安全的
    • 新的时间与日期API中很重要的一点是它定义清楚了基本的时间与日期的概念,比方说,瞬时时间,持续时间,日期,时间,时区以及时间段。它们都是基于ISO日历体系的
    • 这个库的主包是java.time
    • DateTimeFormatter类用于在Java中进行日期的格式化与解析。与SimpleDateFormat不同,它是不可变且线程安全的,如果需要的话,可以赋值给一个静态变量。DateTimeFormatter类提供了许多预定义的格式器,你也可以自定义自己想要的格式。当然了,根据约定,它还有一个parse()方法是用于将字符串转换为日期的,如果转换期间出现任何错误,就会抛出DateTimeParseException异常。类似的,DateFormatter类也有一个用于格式化日期的format()方法,它出错的话则会抛出DateTimeException异常
  • 相关阅读:
    windows 上的C语言 图形界面设计函数 ( easyx 插件 )
    设计模式笔记
    web前端期末大作业《中华传统文化题材网页之丝绸之路》 html+css+javascript网页设计实例
    本地备份和还原 SQL Server 数据库
    力扣每日一题48:旋转图像
    产品问答:陪学数据分析公开课答疑
    ​Word处理控件Aspose.Words功能演示:在 Python 中将 Word 文档转换为 EPUB​
    机器学习中的几种交叉验证方法(5种)
    智工教育:环评师考试重要知识点
    CentOS部署kvm虚拟化机器
  • 原文地址:https://blog.csdn.net/qq_42582773/article/details/126767983