【问题标题】:How to compute wall time from UTC time + TimeZone ID?如何根据 UTC 时间 + TimeZone ID 计算挂墙时间?
【发布时间】:2012-01-07 08:10:39
【问题描述】:

我一直在谷歌上搜索这个问题,但找不到明确和权威的文档。

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

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

【问题讨论】:

    标签: java timezone utc dst wall-time


    【解决方案1】:

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

    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 的冬天,澳大利亚有夏天 - 他们通过将时钟移动一小时来切换到 DST。这就是冬季 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 和墨尔本的 17:00! +8 小时

    不知何故,人们假设两个时区之间的差异始终是恒定的(“奥斯陆和墨尔本之间的差异是总是 10 小时) - 这不是 是的,尤其是考虑到不同的半球时。

    实际上在Oslo(无夏令时,UTC+1)的冬季,Melbourne(UTC+11)观察到夏令时。另一方面,虽然奥斯陆有夏季并且观察到 DST (UTC+2),但墨尔本没有观察到 (UTC+10)。现在很明显为什么差异会根据一年中的一天在 8 到 10 小时之间变化。

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

    【讨论】:

      【解决方案2】:

      当您在 java 中使用 Date 时,它​​始终在内部使用 UTC。并且时区包含 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
      

      【讨论】:

        猜你喜欢
        • 2014-09-29
        • 1970-01-01
        • 1970-01-01
        • 2019-11-30
        • 2015-09-25
        • 2014-02-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多