一、问题描述
当软件需要国际化的时候,我们不得不考虑时间的问题。不同的地方有不同的时区,从而显示的时间是不一样的。而且很多国家在某一段时间还可能会实行夏令时,显示的时间又不一样。为了保证时间的正确性,必须有统一的基线,从而不得不考虑下列时间之间的转换。
a、long timeToUTC(time,timezone) //把给定的时间根据给定的时区转化为UTC
b、String UTCToTime(long,timezone) //把给定的UTC转化为制定时区的时间
c、timeToTime(time,timezone1,timezone2) //把给定的时间根据制定的时区转化为另指定时区的时间
//考虑到数据的存储,还必须考虑数据库对于时间字段的格式。
二、解决方法
显示时间的不同,主要原因的是时区不同。如果不考虑自定义时区的问题,JODA包就能很好解决上面的问题,但是如果考虑自定义时区(很多软件由于考虑夏令时,从而增加了自定义时区的功能来设置夏令时),则我们必须自己来写转换函数。
a、JODA
1public long timeToUTC(String theSourceTime, int sourceWbxTZID)
2 throws Exception {
3 DateTime targDate;
4 if (sourceWbxTZID == (-1)) { //UTC
5 //mdyFormatter:org.joda.time.format.DateTimeFormatter
6 targDate = mdyFormatter.withZone(DateTimeZone.UTC).parseDateTime(theSourceTime);//
7 } else {
8 targDate = mdyFormatter.withZone(
9 DateTimeZone.forID(convertTimezone(sourceWbxTZID)))
10 .parseDateTime(theSourceTime);
11 }
12 return targDate.getMillis();
13 }
14 public String UTCToTime(long theUTCTime, int targetWbxTZID)
15 throws Exception {
16 DateTime theSourceTime = new DateTime(theUTCTime);
17 if (targetWbxTZID == (-1)) {
18 return mdyFormatter.withZone(DateTimeZone.UTC).print(theSourceTime);
19 } else {
20 return mdyFormatter.withZone(
21 DateTimeZone.forID(convertTimezone(targetWbxTZID))).print(
22 theSourceTime);
23 }
24 }
b、自编写
1/** *//**
2 *sourceDate:需要转换的日期,此日期必须是居于GMT的时间。
3 *timezone:
4 *gMT:是否是GMT时间
5 *isConsiderDayLight:是否考虑夏令时
6 */
7 private long convert(Date sourceDate, Timezone timezone, boolean gMT, boolean isConsiderDayLight) throws Exception {
8 int gMTOffSet = (int) timezone.getGmtOffset();//获取偏移量
9 long sourceTime = sourceDate.getTime();
10 if (gMT) {
11 targetTime = sourceTime + gMTOffSet * 60 * 1000;
12 } else {
13 targetTime = sourceTime + ( -1) * gMTOffSet * 60 * 1000;//北京偏移8个小时,如是:-8*60*1000
14 }
15 //下面是考虑夏令时
16
17 return targetTime;
18
19 }
20 public long timeToUTC(String theSourceTime, int sourceWbxTZID)
21 throws Exception {
22 SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
23 sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
24 Date date=sdf.parse(theSourceTime);
25 Timezone timezone=(Timezone)keyedByWbxTZID.get(String.valueOf(sourceWbxTZID));//此函数主要是获取Timezone相关的数据
26 return convert(date,timezone,false,true);
27 }
28 public String UTCToTime(long theUTCTime, int targetWbxTZID)
29 throws Exception {
30 Date date=new Date();
31 date.setTime(theUTCTime);
32 Timezone timezone=(Timezone)keyedByWbxTZID.get(String.valueOf(targetWbxTZID));//此函数主要是获取Timezone相关的数据
33 long time=convert(date,timezone,true,true);
34 SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
35 sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
36 return sdf.format(new Date(time));
37 }
三、相关的一些时间概念
GMT:就是格林威治标准时间的英文缩写,格林威治是伦敦泰晤士河南岸的一个地方,由于从19世纪开始,因为世界各国来往频繁,而欧洲大陆、美洲大陆和亚洲大陆都有各自的时区,所以为免混乱,各国的代表就在1884 年在美国华盛顿召开了国际大会,通过协议选出伦敦的格林威治,作为全球时间的中心点,格林威治标准时间因而诞生。所以有GMT功能的腕表就是说腕表拥有其中的小时表盘可以显示GMT时间。
UTC:短波传送很远,可能经过许多国家、许多不同时区,所以需要有一统时间作标准, 这个标准时间Co-ordinated Universal Time 缩写UTC 或称 UT。过去称为格林威治时间(GMT),虽然有些地方有冬令时间或夏令时间,但UTC时间是不会改的,大家都以它为标准。
DST:Daylight saving time .(夏令时,各个国家开始和结束时间的计算方法是不一样的)
美国,加拿大夏令时起止时间:每年3月份第二个星期天到11月份第一个星期天(亚利桑那州、夏威夷、波多黎各、维尔京群岛和美属萨摩亚除外)。
德国、意大利等多数欧洲国家夏令时起止时间:每年3月份最后一个星期天到10月份最后一个星期天。
MST:Mountain Standard Time
PST:Pacific Standard Time
EST:Eastern Standard Time
很多朋友对于美剧官方网站上的时间表达方式不是很理解。
这里说明一下,以Prison Break为例:Monday 8/7c
它指的是:星期一 东部时间8点 中部时间7点。两地同时播放,不过因为时差问题,钟表上显示的时间有一个小时的差别。
尽管官网的播放时间对于美国以外的朋友来说意义不大,不过如果你愿意查出相对应的北京时间,可以使用http://www.worldtimeserver.com 的服务,我相信国内也有很多类似的时间转换网站,包括google,百度都可以,这里就不再罗嗦了。至少目前来说,美东时间和北京时间相差12小时,也就是说,我们比美东快12个小时。Prison Break的播放时间就是北京时间第二天的早上8点,也就是星期二 8:00AM.
相对于美国,我们国家的时区划分相对简单很多,特别是取消夏令时后,不出国,我们基本上不用考虑时差问题。
美国本土大陆地区采用的时区自东向西为:
东岸标准时区 (Eastern Standard Time; EST; UTC-5; R区),包括大西洋沿岸各州、墨西哥湾及密西西比河以东地区。
中部标准时区 (Central Standard Time; CST; UTC-6; S区),包括密西西比河沿岸以及以西州份的大部份。
山部标准时区 (Mountain Standard Time; MST; UTC-7; T区), 沿大陆分水岭—洛矶山一线的州份、大盆地及科罗拉多河流淢。
太平洋标准时区 (Pacific Standard Time; PST; UTC-8; U区),包括太平洋沿岸地区及内华达州。
美国本土大陆地区以外地区采用的时区
阿拉斯加标准时区 (Alaska Standard Time; AKST; UTC-9; V区) 包括阿拉斯加州大部份地区。
夏威夷—阿留申时区 (Hawaii-Aleutian Standard Time,非正式:夏威夷标准时 Hawaii Standard Time; HST; UTC-10; W区),包括夏威夷州及169°30'W以西的阿留申群岛。
美国属土采用的时区
大西洋标准时区 (Atlantic Standard Time; AST, UTC-4; Q区) 包括波多黎各及美属处女岛。
萨摩亚时区 (Samoa Standard Time; UTC-11, X区)包括美属萨摩亚。
查莫罗时区 (Chamorro Standard Time; UTC+10, Zone K)包括关岛及北马里亚纳群岛。
中国的时区:我们使用北京时间,以前称中原标准时间,现在台湾依然使用这个名称,是中国大陆、香港、澳門和台湾的标准时间。在时区划分上,属东八区,比世界协调时早8小时,记为UTC+8。
严格地讲,北京时间并不是北京(东经116°)地方的时间,而是东经120°度地方的地方时间。而北京时间也不是在北京确定的,而是由位于中国版图几何中心位置陕西临潼的中国科学院国家授时中心的9台铯原子钟和2台氢原子钟组通过精密比对和计算实现,并通过卫星与世界各国授时部门进行实时比对。
清光绪28年(公元1902年),中国海关曾制定海岸时,以东经120度之时刻为标准。公元1912年,位于北京的中央观象台将全国分为五个时区,民国28年3月9日中华民国内政部召集标准时间会议,确认1912年划分之时区为中华民国标准时区。分别为:
1昆仑时区 UTC+5.5 新疆西部与部分西藏
2新藏时区 UTC+6 新疆及西藏
3陇蜀时区 UTC+7 中国中部
4中原标准时区 UTC+8 中国海岸
5长白时区 UTC+9 中国东北
1949年之后,中国大陆将“中原标准时间”改称“北京时间”,并在全国统一使用该时间作为标准时间。台湾则维持“中原标准时间”之名称,也有称“台北时间”或“国家标准时间”。
由于中国大陆全境都采用北京时间作为标准时,因此在中国西部的陕西、甘肃、新疆等省和自治区造成了生活不便,比如在乌鲁木齐,北京时间比当地时间提前两个小时,北京时间早8时30分(中国大陆公务机关通行的上班时间)相当于当地时间早晨6时30分。作为解决措施,一些新疆地区居民使用乌鲁木齐时间,即东六区(UTC+6)时间。
2005年,一些中华人民共和国全国人民代表大会代表提出将中国大陆时区加以细分的建议,提议分为以北京时间为基础的东部时间(UTC+8)、以陕西地区时间为基础的中部时间(UTC+7)和以新疆、西藏地区时间为基础的西部时间(UTC+6)。后又将该提议改为分为两个时区,即UTC+8和UTC+7两个时区,陕西、四川、重庆、贵州、云南及以西各省采用UTC+7的西部时间。但该提案尚未赴诸表决。