您的位置:首页 > 编程语言 > Java开发

详解Java中的时区类TimeZone的用法

2017-11-22 19:05 316 查看
详解Java中的时区类TimeZone的用法
一、TimeZone 简介
TimeZone 表示时区偏移量,也可以计算夏令时。
在操作 Date, Calendar等表示日期/时间的对象时,经常会用到TimeZone;因为不同的时区,时间不同。

下面说说TimeZone对象的 2种常用创建方式。
1.获取默认的TimeZone对象
使用方法:
TimeZone tz = TimeZone.getDefault()

2.使用 getTimeZone(String id) 方法获取TimeZone对象
使用方法:
String[] ids = TimeZone.getAvailableIDs();
for (String id:ids)
System.out.printf(id+", ");

输出结果:
Etc/GMT+12, Etc/GMT+11, Pacific/Midway, Pacific/Niue ....等等

例如,创建上面第2个打印值“Etc/GMT+11”对应的TimeZone。方法如下:
TimeZone tz = TimeZone.getTimeZone("Etc/GMT+11");
TimeZone的函数接口
// 构造函数

TimeZone():
Object    clone()
synchronized static String[] getAvailableIDs()
synchronized static String[] getAvailableIDs(int offsetMillis)
int    getDSTSavings()
synchronized static TimeZone getDefault()
final String   getDisplayName(Locale locale)
String    getDisplayName(boolean daylightTime, int style, Locale locale)
final String   getDisplayName()
final String   getDisplayName(boolean daylightTime, int style)
String    getID()
abstract int   getOffset(int era, int year, int month, int day, int dayOfWeek, int timeOfDayMillis)
int    getOffset(long time)
abstract int   getRawOffset()
synchronized static TimeZone getTimeZone(String id)
boolean    hasSameRules(TimeZone timeZone)
abstract boolean   inDaylightTime(Date time)
synchronized static void  setDefault(TimeZone timeZone)
void    setID(String id)
abstract void   setRawOffset(int offsetMi

二、TimeZone示例:
下面通过示例演示在Date中使用TimeZone。
参考代码如下(TimeZoneTest.java):

import java.text.DateFormat;
import java.util.Date;
import java.util.TimeZone;

/**
* TimeZone的测试程序
*/
public class TimeZoneTest {

public static void main(String[] args) {

// 测试创建TimeZone对象的3种方法
showUsageOfTimeZones() ;

// 测试TimeZone的其它API
testOtherAPIs() ;

// 打印getTimeZone(String id)支持的所有id
//printAllTimeZones() ;
}

/**
* 测试创建TimeZone对象的3种方法
*/
public static void showUsageOfTimeZones() {
TimeZone tz;

// (01) 默认时区
tz = TimeZone.getDefault();
printDateIn(tz) ;

// (02) 设置时区为"GMT+08:00"
tz = TimeZone.getTimeZone("GMT+08:00");
printDateIn(tz) ;

// (03) 设置时区为""
tz = TimeZone.getTimeZone("Asia/Chongqing");
printDateIn(tz) ;
}

/**
* 打印 tz对应的日期/时间
*/
private static void printDateIn(TimeZone tz) {
// date为2013-09-19 14:22:30
Date date = new Date(113, 8, 19, 14, 22, 30);
// 获取默认的DateFormat,用于格式化Date
DateFormat df = DateFormat.getInstance();
// 设置时区为tz
df.setTimeZone(tz);
// 获取格式化后的字符串
String str = df.format(date);

System.out.println(tz.getID()+" :"+str);
}

/**
* 测试TimeZone的其它API
*/
public static void testOtherAPIs() {
// 默认时区
TimeZone tz = TimeZone.getDefault();

// 获取“id”
String id = tz.getID();

// 获取“显示名称”
String name = tz.getDisplayName();

// 获取“时间偏移”。相对于“本初子午线”的偏移,单位是ms。
int offset = tz.getRawOffset();
// 获取“时间偏移” 对应的小时
int gmt = offset/(3600*1000);

System.out.printf("id=%s, name=%s, offset=%s(ms), gmt=%s\n",
id, name, offset, gmt);
}

/**
* 打印getTimeZone(String id)支持的所有id
*/
public static void printAllTimeZones() {

String[] ids = TimeZone.getAvailableIDs();
for (String id:ids) {
//int offset = TimeZone.getTimeZone(avaIds[i]).getRawOffset();
//System.out.println(i+" "+avaIds[i]+" "+offset / (3600 * 1000) + "\t");
System.out.printf(id+", ");
}
System.out.println();
}
}

三、关于TimeZone和时间校准
涉及有关时间区域信息时Java和Solaris很相似。每个时间区域都有一个时间区域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规则。在Solaris中, 这些时间区域数据文件是以二进制形式存
放的,不是文本文件,因此你不能看它们。 在J2SE 1.4中的时间区域数据文件和在Solaris中是不同的。
java.util.TimeZone类中getDefault方法的源代码显示,它最终是会调用sun.util.calendar.ZoneInfo类的getTimeZone
方法。这个方法为需要的时间区域返回一个作为ID的String参数。这个默认的时间区域ID是从 user.timezone (system)
属性那里得到。如果user.timez
4000
one没有定义,它就会尝试从user.country和java.home (System)属性来得到ID。 如果它
没有成功找到一个时间区域ID,它就会使用一个"fallback" 的GMT值。换句话说, 如果它没有计算出你的时间区域ID,
它将使用GMT作为你默认的时间区域。
注意,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 -Duser.timezone=Asia/Shanghai DateTest
这个命令启动DateTest类,并设置 user.timezone属性到Asia/Shanghai。你也能够通过使用java.lang.System
类的setProperty方法来设置user.timezone 属性:
System.setProperty("user.timezone","Asia/Shanghai");
如果没有一个可用的时间区域ID适合你,那么就你可以创建一个自定义TimeZone 使用java.util.TimeZone 类的 setDefault
方法将它设置为默认的时间区域----就象我先前在ItsInitializer 类中所做的操作一样。
记住,在J2SE中,大多数日期和时间相关的类都包含时间区域信息,包括那些格式类,如java.text.DateFormat,
因此它们都会被JVM的默认时间区域所影响。然而,在你创建这些类的实例时,你能为它们确保正确的时间区域信息,
使得你可以更容易来设置整个JVM的默认时间区域。并且一旦设置好,就可以确保所有的这些类都将使用同一个默认的时间区域。

四、
今天遇到了一个比较有意思的问题,从服务器上封装好的java.sql.timestamp对象返回到本地客户端程序后与数据库中的
时间相差了整整14个小时。因为跟客户的时差是14个小时,所以大体怀疑是时差问题。所以计划在客户端程序执行之前
首先设置默认的TimeZone:
timezone,TimeZone.setDefault(TimeZone);
但是我服务器上的TimeZone是什么呢?于是我写了个程序来看看服务器的默认TimeZone:
import java.util.TimeZone;
public class TestTimeStamp {
public static void main(String[] args) {
TimeZone timeZone=TimeZone.getDefault();
System.out.println(timeZone.getID());
}
}
假设输出是: kk,
这样我就获得了服务器上的默认TimeZone:kk,然后所需要做的就是把在客户端程序执行前设置客户端程序的TimeZone:
timezone,TimeZone.setDefault(TimeZone.getTimeZone("kk"));
然后取得的时间如果打印出来就跟服务器一致了,当然你要是如果还是按照java.sql.TimeStamp的类型返回服务器的话,时间还是原来的时间。
另外如果远程服务器封装对象的时候如果直接使用String,我想就不会有这种问题了。

转载:http://www.jb51.net/article/85930.htm  感谢分享!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: