时间对生活来说非常重要,Java也为我们提供了时间的API,多数程序员都在吐槽Java8之前的日期和时间,在Java8中引入全新的日期和时间API,目前我们项目中都在使用这一新的API。之前的API到底不好在哪里?Java8的时间API到底是在吹还是真的不错?在这篇文章中都有答案!,接下来会先介绍之前API的弊病,然后转而介绍新API的升级和具体应用,老样子文章写的非常用心,都喜欢长的,建议收藏反复观看,对于日期和时间的操作都在这了!,Java老API的缺点主要为以下几点:,在Java1.0中,对日期和时间的支持只能依赖java.util.Date类。这个类无法表示日期,只能以毫秒的精度表示时间。而且设计不合理,比如:年份的起始选择是1900年,月份的起始从0开始。如果你想表示女朋友的生日,即2022年12月10日,需要通过以下方式:,输出结果为:,其中,Sat:是 Saturday,周六的缩写,Dec:是 December,12月的缩写,手把手解释,就是这么细,10就不解释了吧,都知道是10号的意思!,总之,看起来非常别扭,它的返回值中的 CST 其实是JVM的默认时区,即美国、澳大利亚、古巴或中国的标准时间,具体是哪一个我也不清楚,毕竟这几个时区都可以简写为 CST,如果能识别出来当前程序在中国运行的,那么可以理解为代表了中国标准时间,java.util.Date源码:,通过源码就会明白几个为什么:,,在java.sql包中也有一个Date类,通过源码可以看出,其实java.sql.Date是继承了java.util.Date,,类上边的注解这么写道:,翻译:,一个围绕毫秒值的精简包装器,允许JDBC将其标识为SQL DATE值。毫秒值表示自1970年1月1日00:00:00.000 GMT以来经过的毫秒数。,为了符合SQL DATE的定义,毫秒值由java.sql.Date包装。必须通过在与实例关联的特定时区中将小时、分钟、秒和毫秒设置为零来“规范化”日期实例,通过上边的翻译可以看出,Java想用java.sql.Date类来映射SQL中的时间戳,非常理想化,我们一般都需要时分秒,这个类直接将时分秒设置为0啦,基本用不了,总结:,Java 1.1中,Date类中的很多方法被废弃了,取而代之的是java.util.Calendar类,Calendar类也有类似的问题和设计缺陷,导致编码时非常容易出错。比如,月份依旧是从0开始计算(不过,至少Calendar类拿掉了由1900年开始计算年份这一设计)。同时存在Date和Calendar这两个类,出现了选择困难症。有的特性只在某一个类有提供,比如格式化和解析日期或时间的DateFormat方法就只在Date类里有,那我用 Calendar 干什么,这就出现了 Calendar 使用很少很少的现象,我觉得是一个失败的升级,小伙伴们在编程或者阅读别人代码的时候,见过 Calendar 吗?,最后,Date和Calendar类设计了拥有set方法都是可变的,能把原本的时间改为任意一个时间意味着什么呢?意味着你程序中从数据库读取到的时间可以被修改掉,比如交易日期本来是2022年12月8日,一个set方法就可以改成其他时间,在维护时绝对是灾难,交易时间等应该是不可变的才对,并没有内鬼!,运行结果:,,DateFormat是时间格式化的抽象类,我们经常使用它的子类SimpleDateFormat来格式化和解析日期与时间,但是也有它自己的问题。比如,它不是线程安全的。这意味着两个线程如果尝试使用同一个formatter解析日期,你可能会得到无法预期的结果。而且格式化和解析时间的类在 java.text 包下,这是想害死强迫症,劝退处女座。,运行结果:,,解决线程安全:,解决线程安全问题,首先想到的就是加锁,或者通过 JUC 中,也就是Java5新增的Lock对象加锁,这里锁不是重点,运行结果:,,总结:,所有这些缺陷和不一致导致用户转投第三方的日期和时间库,比如Joda-Time。Oracle觉得面子挂不住,决定在原生的Java API中提供高质量的日期和时间支持。所以,在Java 8在java.time包中整合了很多Joda-Time的特性。这一章中,我们会一起探索新的日期和时间API所提供的新特性。首先看一下java.time包中都包含哪些东西:,,开发中常用的看下边脑图:,,将从以下几点系统学习新日期API:,作用:该类的实例是一个不可变对象,它只提供了简单的日期,并不含当天的时间信息。它也不附带任何与时区相关的信息,创建:通过静态工厂方法of创建一个LocalDate实例,提供了多种方法来读取常用的值,比如年份、月份、星期几等,代码实现:,运行结果:,,直接获取当前日期:,使用工厂方法从系统时钟中获取当前的日期:,TemporalField读取值:,LocalDate提供了get方法通过传入TemporalField接口获取值,它是接口无法直接使用,可以使用实现该接口的ChronoField枚举类实现,,LocalTime可以用来表示一天内的时间,比如 13:14:52 ,可以通过工厂方法of实现LocalTime的创建,可以指定,时,分,秒,纳秒,,取值范围合理:,,代码实现:,字符串创建:,可以调用LocalDate 和LocalTime 的parse方法根据字符串解析为日期和时间对象,小贴士:如果你传递的日期和时间是错误的运行时则会报错,比如2022年不是闰年所以2月只有28号,请观察下方动图,其中鼠标选中的leap year是闰年的意思,报错信息提示2022年不是闰年,,是对LocalDate和LocalTime的合并,同时表示了日期和时间,但不带有时区信息,可以直接创建,也可以通过合并日期和时间对象构造,,LocalDate的atTime方法:,支持传入LocalTime对象,一起合并返回一个LocalDateTime对象,,LocalTime的atDate方法:,LocalTime就只有一个 atDate方法接收LocalDate对象,不支持传入年月日,一起返回LocalDateTime对象,LocalDateTime的toLocalDate和toLocalTime:,可以将日期时间对象拆解出 LocalDate和LocalTime对象,Instant 类 是Java8 中补充的一个 时间戳类。相较于 System.currentTimeMillis()获取到【毫秒】,Instant 可以更为精确的获取到【纳秒】。该类是基于计算机角度描述时间,以Unix元年时间,也就是1970年1月1日0点开始所经历的秒数,运行结果:,,Instant的设计初衷是为了便于机器使用。它包含的是由秒及纳秒所构成的数字。所以,它无法处理那些我们非常容易理解的时间单位。比如我们想要和LocalDate那样获取获取当前星期的话:,就会出现UnsupportedTemporalTypeException 异常,,作用:,Period 类与 Duration 类都是一段持续时间的概念,如果需要对比时间,它们就需要一个固定的时间值,所以就需要 LocalDate 、LocalDateTime、LocalTime、Instant 、类来配合它们使用,Period 对应使用 LocalDate ,它们的作用范围域都是日期(年/月/日),Duration 对应使用 Instant、LocalTime、LocalDateTime,它们的作用范围域都是时间(天/时/分/秒/毫秒/纳秒),Period可以用于计算两个日期之间的间隔,但是得到的是年月日,如两个日期相差1年2月3天,但是没办法知道1年2月3天具体是多少天,可以通过ChronoUnit.between()方法计算两个单元相差的天数、月数、年数…这个后便会说到,常用API:,构建Period:,运行结果:,,获取年月日:,获取两个时间差:,运行结果:,,计算相差具体天数:,方法一:通过ChronoUnit也可以计算两个日期之间的天数、月数或年数,方法二:调用LocalDate类的toEpochDay方法,返回距离1970年1月1日的long值,此方法只能计算两个LocalDate日期间的天数,不能计算月份、年数,Duration 表示一个时间段,Duration 包含:seconds 表示秒,nanos 表示纳秒, 不包含毫秒,它们的组合表达了时间长度。因为 Duration 表示时间段,并不存在now()这样的静态方法。,Duration只能处理时间,例如LocalTime, LocalDateTime, ZonedDateTime; 如果传入的是LocalDate这种描述日期的类,将会抛出异常,常用API:,简单API调用:,API和Period基本相似,两者区别在于Period计算日期差,Duration计算时间差,计算时间间隔:,方法一:通过Duration计算两个LocalTime相差的时间,方法二:与Period相似,通过ChronoUnit类的between() 方法来执行相同的操作,方法三:通过LocalTime类的toSecondOfDay()方法,返回时间对应的秒数,然后计算出两个时间相差的间隔,计算两个时间戳的间隔:,总结:,至此,已经为大家讲解了基础的日期、时间、时间戳、两个日期、时间的间隔,累的话可以喝口茶休息一下,接下来讲解操作、格式化、解析日期,注意:LocalDate是不可变的,计算后都会返回一个新的LocalDate对象,增加日期API:,代码实现:,用法和plus基本相同,区别在于方法切换为minus,减去日期API:,代码实现:,修改原LocalDate对象的年、月、日、周等数据,并返回一个新的LocalDate对象,这写方法都是with开头的,调整日期API:,代码实现:,代码实现:,Java 8 的 java.time.format 包中提供了 DateTimeFormatter 和 DateTimeFormatterBuilder 来以不同的方式格式化日期、时间或两者,DateTimeFormatter:具有可直接用于解析字符序列的内置格式。,DateTimeFormatterBuilder:提供自定义方式来创建格式化器,格式化LocalDate:,也可以通过工厂方法解析字符串来创建 LocalDate,老API中的解析时间多线程不安全还记得吗?DateTimeFormatter 实例都是线程安全的,DateTimeFormatterBuilder: 提供了更复杂的格式器,可以自定义格式器。另外,它还提供了非常强大的解析功能,比如区分大小写的解析、柔性解析(允许解析器使用启发式的机制去解析输入,不精确地匹配指定的模式)、填充,所有的格式化器都是用DateTimeFormatterBuilder创建的,可以通过appendValue、appendLiteral和appendText等,用于生成一个格式化器,之前的日期和时间都不包含时区信息。时区的处理是新版日期和时间API新增的重要功能,使用新版日期和时间API时区的处理被极大地简化。新的java.time.ZoneId类是老版java.util.TimeZone的替代品。它的设计目标就是要让你无需为时区处理的复杂和繁琐而操心。跟其他日期和时间类一样,ZoneId类也是无法修改的。时区是按照一定的规则将区域划分成的标准时间相同的区间。在ZoneRules这个类中包含了40个这样的实例。你可以简单地通过调用ZoneId的getRules()得到指定时区的规则。每个特定的ZoneId对象都由一个地区ID标识,地区ID都为{区域}/{城市}的格式,这些地区集合的设定都由英特网编号分配机构(IANA)的时区数据库提供。你可以通过Java 8的新方法toZoneId将一个老的时区对象转换为ZoneId,一旦得到ZoneId对象,就可以将它与LocalDate、LocalDateTime或者是Instant对象整合起来,构造为一个ZonedDateTime实例,它代表了相对于指定时区的时间点,重要:LocalDate、LocalTime、ZoneId、LocalDateTime、ZonedDateTime五者关系如下:,,相信这五张图对您理解个对象之间的关系和差异有非常有力的帮助,文章出自:石添的编程哲学,如有转载本文请联系【石添的编程哲学】今日头条号。
文章版权声明
1 原创文章作者:cmcc,如若转载,请注明出处: https://www.52hwl.com/17793.html
2 温馨提示:软件侵权请联系469472785#qq.com(三天内删除相关链接)资源失效请留言反馈
3 下载提示:如遇蓝奏云无法访问,请修改lanzous(把s修改成x)
4 免责声明:本站为个人博客,所有软件信息均来自网络 修改版软件,加群广告提示为修改者自留,非本站信息,注意鉴别