当前正在希望制作的一个小程序,程序中可以根据用户输入不同的TimeZone计算出对应的时间,
使用Calendar的getInstance(TimeZone zone)方法获取输入的TimeZone对应的Calendar对象,
然后通过getInstance()方法获取默认的Calendar对象,但是,每次通过指定TimeZone方式作成
的Calendar对象与默认的都一样,不知道为何?
代码如下:
Calendar cal1 = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
System.out.println(cal1.getTime());
输出结果:
Fri Apr 18 17:48:28 CST 2008
此处还是CST的时区,不知道为何,请指教。

解决方案 »

  1.   

       对于时间分为 本地挂钟时间 和 UTC时间,所谓的UTC时间就是指表示自从标准基准时间(称为“历元(epoch)”,即 1970 年 1 月 1 日 00:00:00 GMT)以来的指定毫秒数,毫无疑问这个时间所有计算机都是一样的。那么我们任务栏上的时间是怎么回事呢?那是OS会把计算机所在的当前时区加上,如:中国在东八区,就会在UTC 时间上加上 8(小时)*60*60*1000作为本地挂钟时间(不考虑夏令时)。     这篇文章主要是说明,为什么修改了“系统时区”,程序不能马上把打印时间切换到修改的时区,而是需要重新再次执行该程序的时候,才能生效(http://www.javaeye.com/post/338220)。JDK源代码中
    java 代码   1. private static void setDefaultZone() {   
       2. TimeZone tz = null;   
       3. // get the time zone ID from the system properties   
       4. String zoneID = (String) AccessController.doPrivileged(   
       5.     new GetPropertyAction("user.timezone"));   
       6.   
       7. // if the time zone ID is not set (yet), perform the   
       8. // platform to Java time zone ID mapping.   
       9. if (zoneID == null || zoneID.equals("")) {    
      10.     String country = (String) AccessController.doPrivileged(   
      11.         new GetPropertyAction("user.country"));   
      12.     String javaHome = (String) AccessController.doPrivileged(   
      13.         new GetPropertyAction("java.home"));   
      14.     try {   
      15.     zoneID = getSystemTimeZoneID(javaHome, country);   
      16.     if (zoneID == null) {   
      17.         zoneID = GMT_ID;   
      18.     }   
      19.     } catch (NullPointerException e) {   
      20.     zoneID = GMT_ID;   
      21.     }   
      22. }   
      23.   
      24. // Get the time zone for zoneID. But not fall back to   
      25. // "GMT" here.   
      26. tz = getTimeZone(zoneID, false);   
      27.   
      28. if (tz == null) {   
      29.     // If the given zone ID is unknown in Java, try to   
      30.     // get the GMT-offset-based time zone ID,   
      31.     // a.k.a. custom time zone ID (e.g., "GMT-08:00").   
      32.     String gmtOffsetID = getSystemGMTOffsetID();   
      33.     if (gmtOffsetID != null) {   
      34.     zoneID = gmtOffsetID;   
      35.     }   
      36.     tz = getTimeZone(zoneID, true);   
      37. }   
      38. assert tz != null;   
      39.   
      40. final String id = zoneID;   
      41. AccessController.doPrivileged(new PrivilegedAction() {   
      42.     public Object run() {   
      43.         System.setProperty("user.timezone", id);   
      44.         return null;   
      45.     }   
      46.     });   
      47.   
      48. defaultZoneTL.set(tz);   
      49.    }   显然这段代码的意思是:如果在系统变量中找不到设置的TimeZone就会设置新的,如果找到了就使用原来存在的,那为什么重新执行该程序就可以了呢?    因为这里的系统指的是JRE而不是我们的OS,当执行一个程序的时候后,JVM会创建一个JVM实例,这个实例的生命周期就是这个进程的生命的周期,我们写入的系统变量都是些入了这个JVM实例,当然再次执行这个程序,又会创建一个新的JVM实例,原来写入的系统变量也就不存在了。    这里介绍一下
    java 代码   1. String zoneID = (String) AccessController.doPrivileged(   
       2.         new GetPropertyAction("user.timezone"));  这是一个特权处理(摘自http://ganzhi.bokee.com/1791837.html):来自不同的位置的代码可以由一个CodeSource对象描述其位置和签名证书。根据代码的CodeSource的不同,代码拥有不同的权限。例如所有Java SDK自带的代码都具有所有的权限,而Applet中的代码则具有非常受限的权限,用户编写的代码可以自己定制权限(通过SecurityManager)。
    当执行一段代码时,这段代码的StackTrace包含了从Main开始所有正在被调用而且没有结束的方法。在这个调用过程中,很有可能出现跨多个不同的 CodeSource的调用序列。由于CodeSource不同,这些代码通常拥有不同的权限集。只有所有途经的CodeSource都具有对应的权限集合时,当前正在运行的代码才能存取某个Resource。
    而doPrivileged方法是对这个规则的一种补充。他类似于Unix中的setuid程序。Unix中的login程序必须访问password文件从而获得用户授权信息,但是用户不能随意的访问password文件。因此,login程序具有setuid位,它不管被哪个用户所调用,都具有 root的权限。
    调用doPrivileged的方法不管其StackTrace中其他方法的权限,而仅仅根据当前方法的权限来判断用户是否能访问某个resource。也即可以规定用户只能用某种预定的方式来访问其本来不能访问的resource。
    使用doPrivileged方法和使用setuid位都有需要注意的地方,例如仅执行必要的操作。否则,可能带来安全上的问题。对于
    java 代码   1. new GetPropertyAction("user.timezone")  就是“利用需要取到值的系统变量名称创建GetPropertyAction对象”,该对象的作用可以在特权处理中重新得到系统变量名称代表的变量值。    这段代码是jdk1.4和1.5中的公共部分,在1.5中 增加了ThreadLocal保证不同线程逗留保留一份该时区系统属性的副本,保证同一个进程中的不同线程使用到TimeZone.getDefault()可以从ThreaLocal中直接取出!
      

  2.   

    1楼说的内容确实很实用,首先谢谢了。
    但是我的问题是我创建的Calendar对象为何在指定了TimeZone后仍然还是当前系统的时间,
    或者我想问一下如何能够创建一个“GMT”时区的Calendar对象呢?
    我希望先创建一个GMT时区的Calendar对象,然后再创建一个本地时区的Calendar对象,然后把两个相减。
    请指教。
      

  3.   

    你可以这样行不行:TimeZone tz = new TimeZone();
               tz.setDefault(TimeZone.getTimeZone(""GMT));
               Calendar cl = new Calendar(tz,Locale.CHINA);
      

  4.   

    写错了
    呵呵呵TimeZone tz = new TimeZone();
               tz.setDefault(TimeZone.getTimeZone("GMT"));
               Calendar cl = new Calendar(tz,Locale.CHINA);
      

  5.   

    根据4楼的提示作成以下代码,实现了。
    TimeZone tz = TimeZone.getDefault();
    TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
    Calendar cl = Calendar.getInstance(tz, Locale.CHINA);
    System.out.println(cl.getTime().toString());
    输出:
    Sat Apr 19 13:18:10 GMT 2008
    谢谢。