如何从UTC时间和时区ID计算出墙上时间?

4
我一直在搜索这个问题,但找不到明确和确定的文档。
假设我有一个UTC时间和一个时区ID,在Java中如何计算墙上时间(= UTC时间+时区偏移量+夏令时),知道夏令时在一年中会改变?
我正在寻找一个经过测试的代码示例。谢谢。
2个回答

3

当你在Java中使用日期时,它总是以UTC时间内部表示。而时区包括夏令时设置,所以实际上很容易处理。

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

3
当你说你有协调世界时(UTC)的时间,我假设你把它保存在 Calendar (虽然 DatetoString()方法,但没有时区概念)。如果你有以字符串形式表示的时间,你可以像这里一样轻松解析或使用日历实例:
Calendar summer = new GregorianCalendar(DateUtils.UTC_TIME_ZONE);
summer.set(2011, Calendar.JUNE, 27, 9, 0, 0);

summer代表的是2011年6月27日上午9:00 UTC。现在,您需要做的就是将时区从UTC更改为澳大利亚墨尔本:

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(加11小时)。

这种差异表明,在Calendar上更改时区时要考虑夏令时。在UTC时区的六月份,澳大利亚正值冬季,因此他们不遵循夏令时规定。

但是,在UTC的冬季,澳大利亚正值夏季,它们会将时钟向前调整一个小时以进入夏令时。这就是为什么在冬季UTC期间,时差为+11小时,而在夏季UTC期间,时差为+10小时的原因。


但是! 当涉及到观察夏令时的多个时区时,事情变得更加有趣。首先,我在欧洲/奥斯陆时区创建了相同的日期:

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);

实际上是UTC时间7:00和墨尔本时间17:00!时差为+8小时!有些人认为两个时区之间的差异总是恒定的("奥斯陆和墨尔本之间的差异总是10小时")-这是不正确的,特别是当考虑到不同的半球时。

实际上,在冬季,奥斯陆(没有夏令时,UTC+1)观察到墨尔本(UTC+11)的夏令时。另一方面,当奥斯陆处于夏季并且观察到夏令时(UTC+2)时,墨尔本则没有观察到夏令时(UTC+10)。现在很明显,为什么差异会根据一年中的日期而变化在8到10小时之间。

还要记住,夏令时的第一天和最后一天不是全球性的,而是为每个时区任意选择的。这意味着9小时的差异也是可能的!例如,看看今年4月1日。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接