日期时间API详解

Java8之前的日期问题

Java 8以前日期时间API存在的问题

在Java 8以前,相信你对 java.util.Date 、java.util.Calendar 、java.util.GregoiranCalendar 和 java.text.SimpleDateFormat 这四大类非常熟悉,它们分别用于处理日期、日历、公历、日期时间格式化

这四个类有好多陷阱和坑,比如:

  1. 非线程安全:这四大类都不是线程安全的。开发者在使用这些类时必须自己处理多线程并发问题。
  2. 设计不佳 :一方面日期和日期格式化分布在多个包中;另一方面,java.util.Date 的默认日期为1970年1月1日,没有统一性。而且 Date 类也缺少直接操作日期的相关方法。
  3. 时区处理困难:因为设计不佳,开发人员不得不编写大量代码来处理时区问题。
  4. 还有其它一些问题,如Calendar类月份从零开始计算等。

Java8改进

面对种种问题,Java 8 终于重新设计了所有日期时间、日历及时区相关的 API。并把它们都统一放置在 java.time 包和子包下。

  1. 新的日期时间 API 是线程安全的。不仅没有 setter 方法,而且任何对实例的变更都会返回一个新的实例,保证原来的实例不变。
  2. 新的日期时间 API 提供了大量的方法,用于修改日期时间的各个部分,并返回一个新的实例。
    借鉴了第三方日期时间库joda很多的优点。
  3. 在时区方面,新的日期时间 API 引入了 域 ( domain ) 这个概念。
  4. 同时 Java 8 还针对原来复杂的 API 进行重新组合和拆分,分成了好多个类。

关于时间和时区

GMT和UTC

UTC与GMT基本上等同,误差不超过0.9秒。不过日常使用中,GMT 与 UTC 的功能与精确度是没有差别的。

  • GMT,即格林尼治标准时间,也就是世界时。GMT的正午是指当太阳横穿格林尼治子午线(本初子午线)时的时间。但由于地球自转不均匀不规则,导致GMT不精确,现在已经不再作为世界标准时间使用。

  • UTC,即协调世界时。是经过平均太阳时(以格林威治时间 GMT 为准)、地轴运动修正后的新时标,以「秒」为单位的国际原子时所综合精算而成的时间。为确保UTC与GMT相差不会超过0.9秒,在有需要的情况下(例如 1998-12-31T23:59:60Z)会在UTC内加上正或负闰秒。协调世界时区会使用 “Z” 来表示,协调世界时也会被称为 “Zulu time”。UTC现在作为世界标准时间使用。

时区

时区作为地理概念,表示 “遵守统一时间标准的一个地区”。

地球自西向东旋转,东边比西边先看到太阳,东边的时间也比西边的早。为了统一世界的时间,1884年的国际经度会议规规定将全球划分为24个时区(东、西各12个时区)。规定英国(格林尼治天文台旧址)为零时区(基准 UTC),东1-12区,西1-12区,中国北京处于东8区(UTC+08:00),那么我们的时间会领先基准-也就是我们在早上 9 点时,伦敦是早上 1 点。

Unix时间戳

计算机中的Unix时间戳,使用自 1970-01-01T00:00:00Z(Z 即表示 UTC 时间)至今的毫秒差作为表示时间的数值,并且移除期间的“闰秒”(例如 1998-12-31T23:59:60Z),这么做当然是为了简化计算机对时间操作的复杂度。Unix 时间体系中,每天固定 86400 秒,这个时间是绝对公立的,它和时区没有任何关系。

Java中的 Unix 时间

Java 确保:每天 24 小时、每小时 60 分、每分钟 60 秒。

Java 中获取 “当前” 时间的方法,其底层实现,全部由 java.lang.System.currentTimeMillis() 提供自 UTC 1970-01-01T00:00:00 的毫秒数。java.lang.System.currentTimeMillis() 作为 native 方法,其实现与 JVM 所在的机器相关(通常使用 NTP 协议保持更新)。

Java 8日期时间

类图

在这里插入图片描述

java.time.temporal 提供的接口:

  1. TemporalField:日期与时间 “字段”,例如:2017-11-18 中的 18 “天”
  2. TemporalUnit:时间 “单位”,例如:1 年 13 天的 13 “天”
  3. TemporalAccessor:“时间相关” 对象的 “只读” 接口
  4. Temporal:“时间相关” 对象的 “读写” 接口,继承自 TemporalAccessor
  5. TemporalAdjuster:Temporal 类型对象 “设置 & 调整” 的函数式接口
  6. TemporalAmount:时间段

API

新的时间与日期 API 中很重要的一点是,它定义清楚了基本的时间与日期的概念,比方说日期、时间、瞬时时间、持续时间、时区及时间段。它们都是基于 ISO8601 日历系统,它是世界民用历法,也就是我们所说的公历

java.time包下主要包含下面几个主要的类:

  1. LocalDate:表示不带时间的日期,比如:2016-10-20
  2. LocalTime:表示不带日期的时间,比如:23:12:10
  3. LocalDateTime:日期时间,比如:2016-10-20 23:14:21
  4. TemporalAduster : 时间调节器
  5. TemporalAdjusters:获得指定日期时间等,如当月的第一天、今年的最后一天等
  6. Duration:持续时间,计算两个“时间”的间隔
  7. Period:日期间隔,计算两个“日期”的间隔
  8. Instant:Unix 时间,它代表的是时间戳,比如 2018-01-14T02:20:13.592Z
  9. Clock:时钟,获取某个时区下的瞬时时间
  10. ZoneId:时区id,例如 Asia/Shanghai等
  11. ZonedDateTime:带时区的日期时间
  12. DateTimeFormatter:时间格式化

新的 API 区分各种日期时间概念并且各个概念使用相似的方法定义模式,这种相似性非常有利于 API 的学习。总结一下一般的方法规律:

  1. of:静态工厂方法,用于创建实例
  2. now:静态工厂方法,用当前时间创建实例
  3. parse:静态工厂方法,从字符串解析得到对象实例
  4. get:获取对象的部分状态
  5. is:检查某些东西的是否是 true,例如比较时间前后
  6. with:返回一个部分状态改变了的时间日期对象拷贝(单独一个with方法,参数为TemporalAdjusters类型)
  7. plus:返回一个时间增加了的时间日期对象拷贝
  8. minus:返回一个时间减少了的时间日期对象拷贝
  9. to:把当前时间日期对象转换成另外一个,可能会损失部分状态。
  10. at:把这个对象与另一个对象组合起来,例如:date.atTime(time)
  11. format:将时间日期格式化为字符串

注意

最后强调,Java 8 中新的时间与日期 API 中的所有类都是不可变且线程安全的,任何修改操作都会返回一个新的实例,而之前 java.util.Date、Calendar 以及 SimpleDateFormat 这些关键的类都不是线程安全的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值