彻底弄透Java处理GMT/UTC日期时间

作者丨BAT的乌托邦
平时工作中遇到时间如何处理?用Date还是JDK 8之后的日期时间API?如何解决跨时区转换等等头大问题 。A哥向来管生管养 , 管杀管埋 , 因此本文就带你领略一下 , JAVA是如何实现GMT和UTC的?
众所周知 , JDK以版本8为界 , 有两套处理日期/时间的API:
彻底弄透Java处理GMT/UTC日期时间

文章插图
 
虽然我一直鼓励弃用Date而支持在项目中只使用JSR 310日期时间类型 , 但是呢 , 由于Date依旧有庞大的存量用户 , 所以本文也不落单 , 对二者的实现均进行阐述 。
Date类型实现java.util.Date在JDK 1.0就已存在 , 用于表示日期 + 时间的类型 , 纵使年代已非常久远 , 并且此类的具有职责不单一 , 使用很不方便等诸多毛病 , 但由于十几二十年的历史原因存在 , 它的生命力依旧顽强 , 用户量巨大 。
先来认识下Date , 看下这个例子的输出:
@Testpublic void test1() {    Date currDate = new Date();    System.out.println(currDate.toString());    // 已经@Deprecated    System.out.println(currDate.toLocaleString());    // 已经@Deprecated    System.out.println(currDate.toGMTString());}运行程序 , 输出:
Fri Jan 15 10:22:34 CST 20212021-1-15 10:22:3415 Jan 2021 02:22:34 GMT第一个:标准的UTC时间(CST就代表了偏移量 +0800) 第二个:本地时间 , 根据本地时区显示的时间格式 第三个:GTM时间 , 也就是格林威治这个时候的时间 , 可以看到它是凌晨2点(北京时间是上午10点哦)
第二个、第三个其实在JDK 1.1就都标记为@Deprecated过期了 , 基本禁止再使用 。若需要转换为本地时间 or GTM时间输出的话 , 请使用格式化器java.text.DateFormat去处理 。
时区/偏移量TimeZone【彻底弄透Java处理GMT/UTC日期时间】在JDK8之前 , Java对时区和偏移量都是使用java.util.TimeZone来表示的 。
一般情况下 , 使用静态方法TimeZone#getDefault()即可获得当前JVM所运行的时区 , 比如你在中国运行程序 , 这个方法返回的就是中国时区(也叫北京时区、北京时间) 。
有的时候你需要做带时区的时间转换 , 譬如:接口返回值中既要有展示北京时间 , 也要展示纽约时间 。这个时候就要获取到纽约的时区 , 以北京时间为基准在其上进行带时区转换一把:
@Testpublic void test2() {    String patternStr = "yyyy-MM-dd HH:mm:ss";    // 北京时间(new出来就是默认时区的时间)    Date bjDate = new Date();    // 得到纽约的时区    TimeZone newYorkTimeZone = TimeZone.getTimeZone("America/New_York");    // 根据此时区 将北京时间转换为纽约的Date    DateFormat newYorkDateFormat = new SimpleDateFormat(patternStr);    newYorkDateFormat.setTimeZone(newYorkTimeZone);    System.out.println("这是北京时间:" + new SimpleDateFormat(patternStr).format(bjDate));    System.out.println("这是纽约时间:" + newYorkDateFormat.format(bjDate));}运行程序 , 输出:
这是北京时间:2021-01-15 11:48:16这是纽约时间:2021-01-14 22:48:16(11 + 24) - 22 = 13 , 北京比纽约快13个小时没毛病 。
注意:两个时间表示的应该是同一时刻 , 也就是常说的时间戳值是相等的
那么问题来了 , 你怎么知道获取纽约的时区用America/New_York这个zoneId呢?随便写个字符串行不行?
答案是当然不行 , 这是有章可循的 。下面我介绍两种查阅zoneId的方式 , 任你挑选:
方式一:用Java程序把所有可用的zoneId打印出来 , 然后查阅
@Testpublic void test3() {    String[] availableIDs = TimeZone.getAvailableIDs();    System.out.println("可用zoneId总数:" + availableIDs.length);    for (String zoneId : availableIDs) {        System.out.println(zoneId);    }}


推荐阅读