【问题标题】:Java TimeZone with DST带有 DST 的 Java 时区
【发布时间】:2013-03-13 23:39:21
【问题描述】:

我有以下代码:

    public static void main(String[] args) {
       DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
   //get current date time with Date()
       Date date = new Date();
       String currentDate = dateFormat.format(date);

       final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         try {
            System.out.println(sdf.format(getSomeDate(currentDate,TimeZone.getTimeZone("Asia/Omsk"))));
         } catch (ParseException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
       }  
    }

    public static Date getSomeDate(final String str, final TimeZone tz) throws ParseException {
       final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
       sdf.setTimeZone(tz);
       return sdf.parse(str);
    }

现在的问题是,如果我使用我想要的时区(即“美国/芝加哥”),我会得到完全错误的时间。它执行当前时间 +6 而不是 -6。

那么我该如何解决这个问题,因为现在我必须从 GMT + 6 开始设置一个时区,才能为我的程序获取正确的时间和日期。

另外,Java 会自动合并 DST 设置吗?由于世界各地的人们都在使用它,因此有些人使用不同的 DST 时间,因此很难保持正确的时间。

【问题讨论】:

  • 为什么不遵循这个答案? java-how-to-change-gmt-time-to-local-time
  • 是的,Java 处理夏令时。实际上,TimeZone 类有几个与 DST 相关的方法。 Calendar 类也使用所有 DST 设置。
  • 您没有在 sdf 上设置 TZ,因此它会像在本地 TZ(JVM 的默认 TZ)中一样格式化日期。

标签: java timezone dst


【解决方案1】:

java.time

现代方法使用 java.time 类。您正在使用糟糕的日期时间类,几年前随着 JSR 310 的采用而过时。

String input = "2020-01-23 15:00:00" ;

这样的输入缺少时区指示符或与 UTC 的偏移量。所以我们必须解析为LocalDateTime。这样的物体代表一个时刻,因为我们不知道您是指东京、图卢兹还是托莱多的下午 3 点——相隔几个小时的不同时刻。

LocalDateTime ldt = LocalDateTime.parse( input.replace( " " , "T" ) ) ;

您似乎确定该日期和时间是针对America/Chicago 时区的。

ZoneId z = ZoneId.of( "America/Chicago" ) ;
ZonedDateTime zdt = ZonedDateTime.of( ldt , z ) ;

让我们生成一个标准 ISO 8601 格式的字符串,以检查该区域当时正在使用的偏移量。 ZonedDateTime::toString 方法明智地扩展了标准,将区域名称附加在方括号中。

String output = zdt.toString() ;

输出:2020-01-23T15:00-06:00[美国/芝加哥]

现在我们已经确定了一个时刻,在我们的ZonedDateTime 对象中。我们在时间线上有一点,芝加哥地区的挂钟时间似乎是下午 3 点。正如我们在-06:00 中看到的那样,这比 UTC 晚了六个小时。

我们可以通过提取Instant 对象来适应UTC。这将使一天中的时间似乎提前六个小时到晚上 9 点。同一时刻,时间轴上的同一点,但挂钟时间不同。就像来自冰岛(使用 UTC 作为时区)和芝加哥的两个人在打电话一样:如果两个人同时抬头看墙上的时钟,一个看到下午 3 点,另一个看到下午 6 点。

Instant instant = zdt.toInstant() ;

instant.toString(): 2020-01-23T21:00:00Z

您询问了“来自世界各地的人们,其中有些人的夏令时时间不同”。您可以轻松地将时刻调整到其他时区。也许东京的某个人希望在他们的时区看到同一时刻,比 UTC提前几个小时而不是落后。

ZoneId zTokyo = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdtTokyo = zdt.withZoneSameInstant( zTokyo ) ; 

或者:

ZonedDateTime zdtTokyo = instant.atZone( z ) ;

zdtTokyo.toString(): 2020-01-24T06:00+09:00[亚洲/东京]

请注意日期如何从 23 日跳到 24 日,以及一天中的时间跳变。同样,同一时刻,不同的挂钟时间。

看到这个code run live at IdeOne.com



关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

    【解决方案2】:

    我想问题是您在 getSomeDate() 方法中只为 SimpleDateFormat 设置了一次 TimeZone。尝试对所有 SimpleDateFormat 实例执行此操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-17
      • 2019-05-06
      • 2019-04-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多