8.3.4 将本地时间转换成GMT

优质
小牛编辑
134浏览
2023-12-01

JDK中提供了一个java.util.Date类,该类是Java中用来处理时间的类。在Date类中有很多和日期/时间相关的方法,如getDate、getDay等,但这些方法都是Date类的遗留产物,这些方法在以后的JDK版本中可以被去掉,因此,并不建议在程序中使用这些方法。不过Date类中有少数的方法不在这些方法之列,这些方法仍然可以在程序中放心地使用。其中getTime和setTime方法是经常被用到的。getTime方法返回从1970年1月1日 0时0分0秒 GMT到当前时间的毫秒数。setTime方法用于设置日期/时间对应的毫秒数。要注意的是,Date对象中封装的毫秒数是GMT时间,并不是本地的时间。看如下的代码:

java.util.Date date = new java.util.Date();

System.out.println(date.getTime());

System.out.println(date);

上面代码中的第2行代码输出了GMT时间的毫秒数。第3行输出了本地时间。将操作系统设为不同的时区(可按8.3.3节所介绍的方法改变操作系统的时区),并执行上面的代码。读者会发现,在不同的时间,输出的毫秒数基本保持不变(毫秒数会有一定的变化,但毫秒数之差只是读者切换时区和再次运行程序所花的时间,可能只有几秒钟),而输出的本地时间却相差数小时。假设两次设置的时区分别是GMT+8和GMT-8,两次输出的本地日期将会相差16个小时,可能还不是同一天。

从上面的实验结果可知,getTime方法返回的始终是以GMT计算的毫秒数,无论操作系统的时区怎样改变,GMT时间始终不会变。而在输出本地日期/时间时,Date类在内部通过时差和夏令时对这个GMT毫秒数进行了处理,因此,输出的本地日期/时间就会和操作系统任务栏右侧显示的时间一致。

如果想获得当前时区和GMT的时间差以及当前年份是否使用了夏令时,可以使用java.util.TimeZone类的getRawOffset和getDSTSavings。代码如下:

java.util.TimeZone tz = java.util.TimeZone.getDefault();

System.out.println("与GMT的时差(毫秒):" + tz.getRawOffset());

System.out.println("是否为夏令时:" + tz.inDaylightTime());

如果当前的时区是GMT+08.00(北京时间),则上面的代码输出的结果如下:

与GMT的时差(毫秒):28800000

是否为夏令时:false

如果当前的时区是GMT-04.00(圣地亚哥),则上面的代码输出的结果如下:

与GMT的时差(毫秒):-14400000

是否为夏令时:true

上面的测试时间是2008年10月22日 15:05:00(读者需要将本机的年和月改成2008和10)。

如果时区使用的是夏令时,可以使用TimeZone类的getDSTSavings方法获得夏令时快的毫秒数(3600000毫秒,1小时)

为了对日期/时间进行更多的处理,从JDK1.1开始增加了一个java.util.Calendar类。通过该类的getTimeZone方法也可以获得当前操作系统的默认时区。

如果想获得格林威治标准时间(GMT),可以使用如下的代码:

package chapter8;
import java.util.Calendar;
import java.util.Locale;
import java.text.DateFormat;
public class GMT
{
    public static void main(String[] args)
    {
        Calendar calendar = Calendar.getInstance();
        //  获得本地时间相对于GMT的时间差(不考虑夏令时)
        int rawOffset = calendar.getTimeZone().getRawOffset();
        int dstSavings = 0;
        //  返回当前时区是否使用夏令时
        boolean dst = calendar.getTimeZone().inDaylightTime(calendar.getTime());
        if(dst)
        {
            //  如果当前时区采用了夏令时,则本地时间要快一小时(3600000毫秒)
            dstSavings = calendar.getTimeZone().getDSTSavings();
        }
        System.out.println("相对GMT的时间差(毫秒):" + rawOffset);
        System.out.println("是否为夏令时:" + dst);
        dstSavings = (rawOffset > 0) ? dstSavings : (-dstSavings);
        DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG,
                DateFormat.LONG, Locale.getDefault());
        //  使用当前的GMT毫秒 、本地时间相对于GMT的时间差和夏令时快的毫秒重新设置当前毫秒数
        calendar.setTimeInMillis(calendar.getTimeInMillis() - (rawOffset - dstSavings));
        //  输出当前的GMT
        System.out.println("GMT:" + calendar.getTime());
    }
}

由于Calendar对象中封装的毫秒是GMT,而使用getTime方法返回的日期是使用时差和夏令时处理过的日期。假设当前时区是GMT+8(北京时间),这时调用getTime方法,系统会将GMT毫秒加上时差(3600 * 1000 * 8毫秒)。如果本地实行夏令时,还会减去3600 * 1000毫秒。如果要让系统输出GMT的时间,就需要先在GMT毫秒上减去这些增量,如下面的代码所示:

calendar.setTimeInMillis(calendar.getTimeInMillis() - (rawOffset - dstSavings));

在运行GMT程序时,无论操作系统的时区如何改变,都会输出一个相对固定的时间。下面是GMT程序的运行结果:

相对GMT的偏移量:28800000

是否为夏令时:false

GMT:Wed Oct 22 13:22:50 CST 2008

如果操作系统的当前时区是GMT+8,上面的输出结果的GMT就是本地时间减8小时。如果操作系统是在其他的时区,则GMT为本地时间减去或加上若干个小时。读者在运行本程序时应注意这一点。