开发跨地域的程序时,常需要进行时区转换,一个设计优良的系统,也必须考虑对多时区的支持。JDK提供了很多方便的机制和工具,来帮助我们解决时区转换问题。
解决跨时区问题的关键在于时间的记录形式。若将时间单纯的记录成“2011-05-14 23:30:00”,其中蕴含的信息并不足以进行时区转换,因为无法获知这是中国的23点30,还是美国的23点30,更不用说复杂的夏令时问题了。
我们可以使用一个long类型的变量来记录时间,该变量的值等于从1970年1月1日 00:00:00 GMT到记录时间点以来的毫秒数,其中GMT代表格林威治标准时间,通过这个差值,可以获得记录时间点的格林威治(零时区)时间,进而能方便的转换成全世界各时区的时间。(很多数据库引擎就是如此处理时间类型数据)
在Java中,有两个常用方法来获取以上描述的值:
1. System.currentTimeMillis(),该方法的返回值是从1970年1月1日 00:00:00 GMT至当前时间点以来的毫秒数,通常被用来获取当前系统时间;
2. java.util.Date的getTime(),该方法的返回值是从1970年1月1日 00:00:00 GMT至Date对象所表示的时间点以来的毫秒数,通常被用来获取特定的时间。
此外,我们还需要借助java.util.TimeZone类,来获取特定的时区,JRE安装目录下的\lib\zi文件夹列出了所有TimeZoneID,如:Asia/Shanghai。最后,使用java.text.SimpleDateFormat类提供的方法进行转换,并格式化输出。
以下是两段示例代码:
//1. 将系统当前时间转换成美国东部时间 TimeZone timeZoneNY = TimeZone.getTimeZone("America/New_York"); SimpleDateFormat outputFormat = new SimpleDateFormat("EEE MMM d HH:mm:ss Z yyyy", Locale.US); outputFormat.setTimeZone(timeZoneNY); Date date = new Date(System.currentTimeMillis()); System.out.println(outputFormat.format(date)); //2. 将一个以字符串形式输入的北京时间转换成美国东部时间 String inputDate = "2011-05-14 23:30:00"; TimeZone timeZoneSH = TimeZone.getTimeZone("Asia/Shanghai"); TimeZone timeZoneNY = TimeZone.getTimeZone("America/New_York"); SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); inputFormat.setTimeZone(timeZoneSH); Date date = null; try { date = inputFormat.parse(inputDate); } catch (ParseException e) { } SimpleDateFormat outputFormat = new SimpleDateFormat("EEE MMM d HH:mm:ss Z yyyy", Locale.US); outputFormat.setTimeZone(timeZoneSH); System.out.println("Asia/Shanghai:" + outputFormat.format(date)); outputFormat.setTimeZone(timeZoneNY); System.out.println("America/New_York:" + outputFormat.format(date));
那么,夏令时(DST)的问题怎么解决呢?令人高兴的是,JDK(or JRE)已自动为我们进行了夏令时处理。可以做个试验,来验证以上第2段代码能适用于夏令时转换。美国在2011年开始和结束夏令时的时间是:3.13 2AM和11.6 2AM。
1. 将输入时间inputDate设置为"2011-03-13 14:59:59",输出:
Asia/Shanghai:Sun Mar 13 14:59:59 +0800 2011
America/New_York:Sun Mar 13 01:59:59 -0500 2011
此时,美国东部时间还差1秒进入夏令时,与北京时间相差13小时。
2. 将输入时间inputDate设置为"2011-03-13 15:00:00",输出:
Asia/Shanghai:Sun Mar 13 15:00:00 +0800 2011
America/New_York:Sun Mar 13 03:00:00 -0400 2011
此时,美国东部时间刚好进入夏令时,与北京时间相差12小时,同时,所使用的时区也发生了变化。
结束夏令时的试验就不再赘述了。
JDK(or JRE)之所以能自动的进行DST处理,是因为其已内置了各个国家的夏令时政策,并提供Timezone Updater Tool来保持低版本JDK(or JRE)的TimeZone更新,但SUN官方推荐使用JDK(or JRE)的更新来更新TimeZone信息。
综上,我们应尽量在系统中使用如上描述的long类型变量来记录时间,借助相应的方法,可方便的格式化为不同时区的时间进行显示。