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

Java平台时间系统的设计方案
几乎任何事物都会有“起点”这样的概念 , 比如人生的起点就是我们出生的那一刻 。 Java平台时间系统的起点就是世界时间(UTC)1970年1月1日凌晨零点零分零秒 。 用专业的写法是“1970-01-01T00:00:00Z” , 最后的大写字母“Z”指的是0时区的意思 。 在Java平台时间系统里 , 这个起点用单词“epoch”表示 , 就是“新纪元、新时代”的意思 。 一般来说如果一个事物有起点 , 那么通常该事物也会有一个叫做“偏移量”的概念 。 人一出生 , 就有了年龄 , 这就是个偏移量 , 一旦工作 , 就有了工龄 , 这也是个偏移量 。 Java平台时间系统就是用偏移量来表示时间的 , 表面上看起来有年月日时分秒 , 其实底层就是一个long类型的整数 , 就是自起点开始经过的毫秒数 。 这一点可以很容易说明:
1Date now = new Date();2System.out.println(now);3System.out.println(now.getTime());4System.out.println(System.currentTimeMillis());输出结果如下:
1Fri Mar 06 13:52:41 CST 20202158347396139831583473961398可能有的读者会问 , 那如何表示1970年以前的时间呢?当然也是采用偏移量啊 , 只不过这个偏移量是个负的罢了 , 估计很多人都没见过负的毫秒数 , 那就来看看吧 。 那就把年份设置成1969年试试吧:
1Calendar before = Calendar.getInstance();2before.set(Calendar.YEAR, 1969);3System.out.println(before.getTimeInMillis());输出结果如下:
1-25985142623看到了吧 , 就是一个负的整数 。 偏移量和时区有关吗?
有一个更有意思的问题浮现了出来 , 全球有24个时区 , 那这个偏移量和时区有关吗?如果无关 , 则所有时区的偏移量都一样 , 那时间也应该都一样啊 , 可事实是都不一样 。 如果有关 , 则所有时区的偏移量都不一样 , 那就有24个偏移量 , 感觉似乎也不太对 。 孰对孰错 , 试试便知 , 那就干起来吧 。 获取上海、伦敦、芝加哥三个地方(所在时区)的时间:
1Calendar cn = Calendar.getInstance(TimeZone.getTimeZone("Asia/Shanghai"));2Calendar en = Calendar.getInstance(TimeZone.getTimeZone("Europe/London"));3Calendar us = Calendar.getInstance(TimeZone.getTimeZone("America/Chicago"));打印出来看看:
1System.out.println(getDate(cn));2System.out.println(getDate(en));3System.out.println(getDate(us));输出结果如下:
12020-2-6 13:54:1722020-2-6 05:54:1732020-2-5 23:54:17可以看到 , 时间是正确的 。 再把它们的毫秒数打印出来看看:
1System.out.println(cn.getTimeInMillis());2System.out.println(en.getTimeInMillis());3System.out.println(us.getTimeInMillis());输出结果如下:
115834740573562158347405735631583474057356结论是:偏移量都一样 , 和时区是无关的 。 那日期为啥是不同的呢?这就是时区的功劳了 。 再用Java8的时间API来验证一遍 。 同样创建三个地方的当地时间:
1LocalDateTime cnldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));2LocalDateTime enldt = LocalDateTime.now(ZoneId.of("Europe/London"));3LocalDateTime usldt = LocalDateTime.now(ZoneId.of("America/Chicago"));打印出来看看:
1System.out.println(cnldt);2System.out.println(enldt);3System.out.println(usldt);输出结果如下:
12020-03-06T13:54:17.37022020-03-06T05:54:17.37232020-03-05T23:54:17.372