如何根据UTC时间+ TimeZone ID计算墙体时间?

问题描述:

我一直在搜索这个问题,但找不到清晰明确的文档。如何根据UTC时间+ TimeZone ID计算墙体时间?

假设我有一个UTC时间和一个TimeZone ID,那么在Java中知道夏令时在一年中发生变化时,如何计算壁挂时间(= UTC时间+时区偏移+夏令时)?

我正在寻找一个经过测试的代码示例。谢谢。

当你说你在UTC有时间我假设你持有它在CalendarDate没有时区的概念,尽管误导toString())。如果你有时间,例如在String您可以轻松地解析它或日历实例喜欢这里:2011年6月的

Calendar summer = new GregorianCalendar(DateUtils.UTC_TIME_ZONE); 
summer.set(2011, Calendar.JUNE, 27, 9, 0, 0); 

summer代表27日上午9:00 UTC现在,所有你需要做的是把时区从UTC更改为Melbounre,澳大利亚:

summer.setTimeZone(TimeZone.getTimeZone("Australia/Melbourne")); 

我会用FastDateFormat打印正确的日期:

final FastDateFormat formatter = FastDateFormat.getDateTimeInstance(FastDateFormat.SHORT, FastDateFormat.SHORT); 

System.out.println(formatter.format(summer)); 

在墨尔本的时间是19:00(+10小时)。但日期改到冬季:

Calendar winter = new GregorianCalendar(DateUtils.UTC_TIME_ZONE); 
winter.set(2011, Calendar.DECEMBER, 27, 9, 0, 0); 
System.out.println(formatter.format(winter)); 

猛然间,在墨尔本的时间是20:00 (升小时)。

该差异证明更改Calendar的时区需要考虑DST。在UTC时区六月期间,澳大利亚有冬季,因此他们没有观察到夏令时。

但是在UTC的冬季,澳大利亚是夏季 - 他们通过将时钟移动一个小时切换到夏令时。这就是为什么在冬季,差值为+11小时,而夏季UTC时为+10。


但是等等!当考虑多个时区观察DST时,它会变得更加有趣。首先,我在欧洲/奥斯陆时区创建同一日期:

Calendar winter = new GregorianCalendar(TimeZone.getTimeZone("Europe/Oslo")); 
winter.set(2011, Calendar.DECEMBER, 27, 9, 0, 0); 

奥斯陆9:00冬季期间在墨尔本8:00 UTC但19:00(10小时)。

但同时夏季:

Calendar summer = new GregorianCalendar(TimeZone.getTimeZone("Europe/Oslo")); 
summer.set(2011, Calendar.JUNE, 27, 9, 0, 0); 

实际上是7:00 UTC和墨尔本17:00! +8小时

不知怎的,人们认为两个时区之间的差异始终保持恒定(“奥斯陆和墨尔本之间的差异总是10小时) - 这是如此,尤其是在不同的半球考虑

实际上,在冬季Oslo(无DST,UTC + 1)中观测到DST在Melbourne(UTC + 11)另一方面,当奥斯陆有夏季时,观测到DST(UTC + 2)时,在墨尔本(UTC + 10)没有观察到,现在变得很明显,为什么差异在8到10小时之间变化,这取决于当天的情况年。

还请记住,DST的第一天和最后一天不是全球性的,而是针对每个时区任意选择的。这意味着9小时的差异也是可能的(!)例如,检查今年4月1日。

当你在java中使用Date时,它总是在内部使用UTC。 Timezone包含DST设置,所以它实际上非常简单。

public static void main(String[] args) throws ParseException { 
    String stringAugust = "2011-08-01 12:00:00"; 
    String stringNovember = "2011-11-01 12:00:00"; 

    // Outputting the time in Stockholm and Santiago 
    // Stockholm has DST in August and not in November 
    // Santiago has DST in November and not in August 

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 

    // Parsing the Strings 
    sdf.setTimeZone(TimeZone.getTimeZone("UTC")); 
    Date dateAugust = sdf.parse(stringAugust); 
    Date dateNovember = sdf.parse(stringNovember); 

    // outputting the dates for Stockholm 
    sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"); 
    sdf.setTimeZone(TimeZone.getTimeZone("Europe/Stockholm")); 
    System.out.println(sdf.format(dateAugust)); 
    System.out.println(sdf.format(dateNovember)); 

    // outputting the dates for Santiago 
    sdf.setTimeZone(TimeZone.getTimeZone("America/Santiago")); 
    System.out.println(sdf.format(dateAugust)); 
    System.out.println(sdf.format(dateNovember)); 

} 

输出

2011-08-01 14:00:00 +0200 
2011-11-01 13:00:00 +0100 
2011-08-01 08:00:00 -0400 
2011-11-01 09:00:00 -0300