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

可以看到首次调整是在“1883-11-18T12:09:24”的时候把时间偏移量从“-05:50:36”调整到了“-06:00” , 等于回调了9分24秒 , 所以是“Overlap” , 即重叠 。
仔细看的话会发现后续的调整都集中到每年的3/4/6月份和9/10/11月份 , 而且都是在西5区和西6区之间的变换 。 相信大家都已经猜出来了 , 美国是分“冬令时(正常时间)”和“夏令时”的国家 。 所以每年都会调整2次 , 那为什么上面的最后一次调整是2008年呢?后续的调整呢?上面那些都是历史了 , 所以需要都记录下来 , 其实这个调整是有规律的 , 因此只需要记录下规律 , 而不需要记录每次变更的日志了 。 美国芝加哥(中部时间)当地的冬令时和夏令时的变换规律是:
1[Gap -06:00 to -05:00, SUNDAY on or after MARCH 8 at 02:00 WALL, standard offset -06:00],2[Overlap -05:00 to -06:00, SUNDAY on or after NOVEMBER 1 at 02:00 WALL, standard offset -06:00]冬令时到夏令时的转换是在 , 每年3月8日及其之后最近的一个周日凌晨2点 , 把时区从“-6”变到“-5” , 即提前1小时 , 所以是“Gap”裂缝 。 夏令时到冬令时的转换是在 , 每年11月1日及其之后最近的一个周日凌晨2点 , 把时区从“-5”变到“-6” , 即延后1小时 , 所以是“Overlap”重叠 。 “standard offset -06:00”的意思是 , 这里(当地)的标准时间偏移量是比UTC晚6个小时 , 为了照顾当地人们的生活和上班习惯 , 在夏天到来时 , 把时间提前1个小时 。 “WALL”这个单词是墙的意思 , 所以“at 02:00 WALL”的意思就是在你看到墙上挂的钟表是凌晨2点的时候 。 是对当前正在使用(还未调整)的时间的一种指代吧 。 上面那些已经记录下来的转换历史日志 , 是为了对过去时间的计算用的 , 而这个转换规则 , 是为了对未来的时间计算用的 。 还好中国没有冬令时和夏令时的概念 , 中国只是改变了上下班的时间 , 冬天下班早些 , 因此中国没有转换规则 , 一年四季都是比UTC早8小时 。 “当地时间”的计算方法
在Java时间系统里 , 时间就是自“时间起点”开始经过的毫秒数 , 这对全球24个时区都是一样的 。 如果把这个毫秒数直接转化为时间 , 它对应的就是UTC时间 , 即0时区的时间 , 也是英国伦敦的时间 。 如果某地不是位于0时区的话 , 那就再加上或减去当地时区对应的时间偏移量 , 得到的就是当地时间 。 比如中国就是“毫秒数”再加上8个小时对应的毫秒数 , 美国中部就是”毫秒数“再减去6个小时对应的毫秒数 。 不要以为这样就完事了 , 历史上同一个地方的时区都是比较混乱的 , 可能反复变换过几十次甚至上百次 , 那么这个地方对应的时区到底该怎么取呢?还好 , 上面说了 , Java时间系统已经记录下了每个地方时区变更历史日志了 , 这些反复的变更其实构成了一个个连续的区间 。 每个区间的两端都是一个日期(时间) , 其实也是一个“毫秒数” 。 这样当我们拿到一个时间“毫秒数”后 , 就去和这个地方的所有变更区间两端的“毫秒数”进行比对 。 确认出我们拿到的这个“毫秒数”落到了哪个区间 , 然后就使用这个区间对应的时区时间偏移量即可 。 这样所有的历史(过去的)时间就都算出来了 。 那对于未来的时间呢?像美国那样的有冬令时和夏令时变换规则的 , 就按规则去计算 。 像中国这种没有变换规则的 , 就按历史上最后一次变换后对应的时区时间偏移量去计算 。 即如果不出意外的话 , 中国永远是采用东8区 , 时间永远比UTC早8小时 。 从“毫秒数”计算出具体时间
首先需要说明的是 , Java8获取的还是毫秒级别的偏移量 , 而且和之前的方法是一样 , 并不是直接获取的纳秒 。 证明如下图01:
卜娃娃|最硬核的「Java8时间系统」设计原理与使用方法后来又将毫秒转换为秒和纳秒 , 证明如下图02: