卜娃娃|最硬核的「Java8时间系统」设计原理与使用方法( 五 )


卜娃娃|最硬核的「Java8时间系统」设计原理与使用方法所以说Java8时间系统的精度并没有提升 , 至少在某些方面没有提升 。 当毫秒被转化为秒和纳秒后 , 首先要加上或减去时区的时间偏移量 , 这个偏移量是精确到秒级的 。 所以不影响纳秒的数值 。 然后开始计算日期和时间 , 日期和时间肯定要分开计算的 , 用秒数除以86400(每天的秒数)并取整得到的就是自1970-01-01经过的天数 , 这个天数可能是负的 。 由于大月为31天/月 , 小月为30天/月 , 2月份为平年28天/闰年29天 , 所以从天数转化为年/月/日的时候也是比较繁琐的 , 而且正的天数是往后算 , 负的天数是往前算 , 也是不一样的 。 日期这就算出来了 , 然后再算时间 。 用计算天数时剩下(不足1天)的秒数 , 再加上纳秒那部分 , 去计算出时/分/秒/纳秒 , 这部分的计算要相对容易些了 。 这样时间(LocalTime)也计算出来了 , 在加上前面算出来的日期(LocalDate) , 就是现在的日期时间(LocalDateTime)了 。 这就是JDK8里面的计算方法 , 如下图03:
卜娃娃|最硬核的「Java8时间系统」设计原理与使用方法时间的获取与跨时区转换获取自己所在地区的当前时间 , 是这样子的:
1LocalDateTime.now();Java会利用操作系统设置的地区信息 。 如果要获取指定地区的当前时间 , 需要自己指定一个时区(地区) , 是这样子的:
1LocalDateTime.now(ZoneId.of("America/Chicago"));如果知道了一个地区的时间偏移量 , 那就指定一个时区偏(地区)移量 , 也可以这样子:
1LocalDateTime.now(ZoneOffset.of("-6"));如果要获取UTC(标准)时间 , 可以这样子:
1LocalDateTime.now(ZoneId.of("Europe/London"));2LocalDateTime.now(ZoneOffset.of("Z"));因为伦敦时间就是标准时间 , 也是0时区时间 , 也是没有时区偏移量的时间 , “Z”的意思就是偏移量为0 。 如果在一个非常确定的情况下进行跨时区转换时间的话 , 是这样子的:
1ZoneOffsetTransition zot = ZoneOffsetTransition.of(LocalDateTime.now().withNano(0), ZoneOffset.of("+8"), ZoneOffset.of("-6"));2zot.getDateTimeBefore();3zot.getDateTimeAfter();of方法的第一个参数是待转换的时间 , 第二个参数是该时间对应的偏移量 , 第三个参数是转换后的偏移量 。 其实内部原理很简单 , 就是加上或减去这两个偏移量之间的差值 。 由于过去很多地方都进行过时区的多次反复变更 , 如果想知道某个地方过去的某个时间当时所采用的时区 , 可以这样子:
1ZoneRules rules = ZoneId.of("Asia/Shanghai").getRules();2LocalDateTime someTime = //过去的某个时间;3ZoneOffset offset = rules.getOffset(someTime);就是根据地区获取到该地区的变换规则 , 根据规则获取过去某个时间当时的偏移量 , 当然这个时间也可以是未来的时间 。 这在一般情况下都会得到唯一的准确的结果 , 但发生在日期调整的特殊时刻时就不是这样的了 。 比如美国在夏天到来时会在某个周日的凌晨2点把时间往前调一个小时 , 就是从2点直接蹦到3点 , 时间偏移量就是从-6变为-5 。 如果我们要找2点半对应的时间偏移量 , 其实是没有的 。 因为这个时间根本就没有出现过 , 是被蹦过去了 。 这是时间裂缝 , 我们等于掉到裂缝里了 。 同样美国在冬天到来时会在某个周日的凌晨2点把时间往回调一个小时 , 就是从2点直接退到1点 , 时间偏移量就是从-5变为-6 。 如果我们要找1点半对应的时间偏移量 , 其实是有2个 。 因为这个时间实际上出现过两次 , 因为1点到2点又重复走了一遍 。 这就是时间重复 , 我们等于掉到重复里了 。 对于这两种情况 , 系统给的是调整前的时间偏移量 , 而且明确说明这只是个“最佳”结果而非“正确”结果 , 应用程序应该自己认真对待这种情况 。 系统给出的这个“最佳”结果 , 对于过去的时间和未来的时间都是一样的 , 即在“临界区”的时间段内选的都是调整前的时间偏移量 。 这个是使用当地的时间获取当地的时间变换规则 , 其实还有更麻烦的场景 。 像下面这个 。就是我们想知道在中国过去(或未来)的某个时间的时候 , 美国的芝加哥对应时间是几点?这时候其实需要知道在中国的这个时间的时候 , 美国芝加哥的时间的偏移量是多少?因为芝加哥的时间偏移量也是反复变化的 , 所以还需像上面那样去获取 , 就是这样子: