一 时间区域和JAVA:
    Java每个时间区域都有一个时间区域ID标识符。在J2SE 1.3 and 1.4中,这个ID是个字符串,是由位于J2SE 安装程序的jre/lib子目录中的tzmappings文件这些ID列表。 J2SE 1.3 仅仅只包含tzmappings文件,但是 J2SE 1.4包含世界不同地区的时间区域数据文件。jre/lib/zi存放着这些文件。在J2SE 1.4里,sun.util.calendar.ZoneInfo从这些文件获取DST规则。
   java.util.TimeZone类中getDefault方法的源代码显示,它最终是会调用sun.util.calendar.ZoneInfo类的getTimeZone 方法。这个方法为需要的时间区域返回一个作为ID的String参数。这个默认的时间区域ID是从 user.timezone (system)属性那里得到。如果user.timezone没有定义,它就会尝试从user.country和java.home (System)属性来得到ID。 如果它没有成功找到一个时间区域ID,它就会使用一个"fallback" 的GMT值。换句话说, 如果它没有计算出你的时间区域ID,它将使用GMT作为你默认的时间区域。
java.util.TimeZone的部分源码分析:

方法1:
public static TimeZone getDefault() {//返回默认时区的克隆对象
        return (TimeZone) getDefaultRef().clone();//=========>>>>
    }
方法2:
  static TimeZone getDefaultRef() {
    TimeZone defaultZone = defaultZoneTL.get();//参见方法:setDefault(TimeZone zone)
    if (defaultZone == null) {
        defaultZone = defaultTimeZone;
        if (defaultZone == null) {
        // Need to initialize the default time zone.
        defaultZone = setDefaultZone();//=========>>>>
        assert defaultZone != null;
        }
    }
    // Don't clone here.
    return defaultZone;
    }
方法3:
private static synchronized TimeZone setDefaultZone() {
    TimeZone tz = null;
    // get the time zone ID from the system properties
    String zoneID = AccessController.doPrivileged(
        new GetPropertyAction("user.timezone"));//取出默认的时间区域ID

    // if the time zone ID is not set (yet), perform the
    // platform to Java time zone ID mapping.
    if (zoneID == null || zoneID.equals("")) { //尝试从user.country和java.home (System)属性来得到ID
        String country = AccessController.doPrivileged(
            new GetPropertyAction("user.country"));
        String javaHome = AccessController.doPrivileged(
            new GetPropertyAction("java.home"));
        try {
        zoneID = getSystemTimeZoneID(javaHome, country);
        if (zoneID == null) {
            zoneID = GMT_ID;
        }
        } catch (NullPointerException e) {
        zoneID = GMT_ID;//使用GMT作为你默认的时间区域。
        }
    }

    // Get the time zone for zoneID. But not fall back to
    // "GMT" here.
    tz = getTimeZone(zoneID, false);//=========>>>>

    if (tz == null) {
        // If the given zone ID is unknown in Java, try to
        // get the GMT-offset-based time zone ID,
        // a.k.a. custom time zone ID (e.g., "GMT-08:00").
        String gmtOffsetID = getSystemGMTOffsetID();
        if (gmtOffsetID != null) {
        zoneID = gmtOffsetID;
        }
        tz = getTimeZone(zoneID, true);//使用GMT作为你默认的时间区域。
    }
    assert tz != null;

    final String id = zoneID;
    AccessController.doPrivileged(new PrivilegedAction<Object>() {
        public Object run() {
            System.setProperty("user.timezone", id);
            return null;
        }
        });

    defaultTimeZone = tz;
    return tz;
    }
方法4:
private static TimeZone getTimeZone(String ID, boolean fallback) {
    TimeZone tz = ZoneInfo.getTimeZone(ID);
    if (tz == null) {
        tz = parseCustomTimeZone(ID);
        if (tz == null && fallback) {
        tz = new ZoneInfo(GMT_ID, 0);//sun.util.calendar.ZoneInfo类的getTimeZone 方法。
        }
    }
    return tz;
    }
//=======================================
方法5:
//调用此方法后,再getDefault()时,就直接从defaultZoneTL变量里取了,不再查询user.timezone
    public static void setDefault(TimeZone zone)
    {
    if (hasPermission()) {
        synchronized (TimeZone.class) {
        defaultTimeZone = zone;
        defaultZoneTL.set(null);
        }
    } else {
        defaultZoneTL.set(zone);
    }
    }

二 关于Java vm系统环境变量:
    注意,System属性是在java.lang.System类的initProperties方法中被初始化的。这是一个本地方法。因此源代码是不可用的----除非你深入到J2SE分发包中的本地代码库中去研究。然而,在Windows系统中,System 属性是从Windows注册表中被初始化的,而在Linux/Unix中是由环境变量来进行初始化。initProperties方法的Javadoc声明,某些属性"必须保证被定义" 且列出它们。被java.util.TimeZone类的getDefault方法使用的三个System属性中,只有java.home作为一种“保证的”属性在Javadoc中被列出。

推荐的解决方案
     因此,你如何确保JAVA能给你正确的时间和日期呢?最好的办法是确认JAVA虚拟机(JVM)的默认TimeZone类是正确的,且是适合你的地理范围(Locale)的。你如何来确保默认TimeZone是正确的且适合的呢?这又是一个新问题了。象大多数处理的问题一样,这个也有许多解决方案。根据java.util.TimeZone.getDefault方法的源代码来看,最好的办法是正确地设置user.timezone属性。在启动JAVA虚拟机时,你能很容易的通过使用 -D 命令 -line 参数的办法来覆盖(override)在java.lang.System.initProperties方法中所设置的值。例如:
Java代码1:
java -Duser.timezone=Asia/Shanghai DateTest
     这个命令启动DateTest类,并设置 user.timezone属性到Asia/Shanghai。你也能够通过使用java.lang.System 类的setProperty方法来设置user.timezone 属性:
Java代码2:
System.setProperty("user.timezone","Asia/Shanghai");
     如果没有一个可用的时间区域ID适合你,那么就你可以创建一个自定义TimeZone 使用java.util.TimeZone 类的 setDefault 方法将它设置为默认的时间区域----就象我先前在ItsInitializer 类中所做的操作一样。
     记住,在J2SE中,大多数日期和时间相关的类都包含时间区域信息,包括那些格式类,如java.text.DateFormat, 因此它们都会被JVM的默认时间区域所影响。然而,在你创建这些类的实例时,你能为它们确保正确的时间区域信息,使得你可以更容易来设置整个JVM的默认时间区域。并且一旦设置好,就可以确保所有的这些类都将使用同一个默认的时间区域。

三 Java TimeZone 和 Linux TimeZone问题
(1)java vm取默认timezone的算法:
     1)如有环境变量 TZ设置,则用TZ中设置的时区
     2)在 /etc/sysconfig/clock文件中找 "ZONE"的值
         注意ZONE的值要带双引号。如:ZONE="Asia/Shanghai"
     3) 如过没有找到ZONE值,就用/etc/localtime 和 /usr/share/zoneinfo 下的时区文件进行匹配,如找到匹配的,就返回对应的路径和文。
(2)Linux TimeZone:
设置etc/localtime文件连接,或用/usr/share/zoneinfo/下的文件覆盖localtime
[xx:~]> sudo ln -sf /usr/share/zoneinfo/US/Eastern /var/etc/localtime

设置/etc/sysconfig/clock中的时区
   ZONE="Asia/Shanghai" -- 时区
   UTC=false -- 表明时钟设置为UTC。
   ARC=false  -- 仅用于alpha表明使用ARC。

参考资料:

http://my.oschina.net/huawu/blog/4646

http://bugs.sun.com/view_bug.do?bug_id=6456628

http://zhaohaiyang.blog.51cto.com/2056753/465728