JDK 6日历2041年10月20日BUG

时间:2014-06-05 20:31:45

标签: java calendar

我们的系统出现错误:当我们将日期设置为2041年10月20日时,我们将日期设置为
2041年10月19日 - 23小时

    Calendar c = Calendar.getInstance();
    c.set(2041, Calendar.OCTOBER, 20, 0, 0, 0);
    System.out.println(c.getTime());

输出:

Sat Oct 19 23:00:00 BRT 2041

当我们使用JDK 6时会发生这种情况,在JDK 7中输出是正确的:

Sat Oct 20 00:00:00 BRT 2041

但我们不能在我们的系统中使用jdk 7。有人有关于这个bug的更多信息吗?

-
更多信息:这只发生在2040年之后的日期

3 个答案:

答案 0 :(得分:3)

您的本地/默认时区是否比“BRT”提前一小时?

尝试使用SimpleDateFormat输出日期。这适用于美国中部时间,将“BRT”设置为使用的时区。

  public static void main(String... args) {
    Calendar c = Calendar.getInstance();
    c.setTimeZone(TimeZone.getTimeZone("BRT"));
    c.set(2041, Calendar.OCTOBER, 20, 0, 0, 0);
    SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
    sdf.setTimeZone(TimeZone.getTimeZone("BRT"));
    System.out.println(sdf.format(c.getTime()));
    System.out.println(c.getTime());
  }

答案 1 :(得分:3)

时区& DST数据更改

answer by GriffeyDog和评论表明您因计算机和JVM上的设置而感到困惑。问题可能与Daylight Saving Time (DST)有关,因为10月20日大约是DST change for Brazildata for time zones and DST随Java更新一起更新。您可能会看到巴西的更新之间存在差异。

约达时间

使用Joda-Time的当前版本(现在为2.3)对此进行测试。比使用java.util.Date&更加困惑。 。日历。 Joda-Time中的DateTime知道自己指定的时区。 Joda-Time适用于Java 6和Java 6 7(和8)。 Joda-Time包含自己的时区和DST数据,而不是使用Java捆绑的数据。

使用UTC

正如其中一条评论所示,明确使用UTC进行比较。

Joda-Time中的示例代码

DateTimeZone timeZoneSao_Paulo = DateTimeZone.forID( "America/Sao_Paulo" );

DateTime dateTimeSao_Paulo = new DateTime( 2041, DateTimeConstants.OCTOBER, 20, 1, 2, 3, timeZoneSao_Paulo ).withTimeAtStartOfDay();
DateTime dateTimeUtc = dateTimeSao_Paulo.withZone( DateTimeZone.UTC );

DateTime dateTimeSao_PauloBeforeMidnight = new DateTime( 2041, DateTimeConstants.OCTOBER, 19, 23, 50, 0, timeZoneSao_Paulo );
DateTime dateTimeSao_PauloAfterMidnight = dateTimeSao_PauloBeforeMidnight.plusHours( 1 );

转储到控制台。

System.out.println( "dateTimeSao_Paulo: " + dateTimeSao_Paulo );
System.out.println( "dateTimeUtc: " + dateTimeUtc );
System.out.println( "dateTimeSao_PauloBeforeMidnight: " + dateTimeSao_PauloBeforeMidnight );
System.out.println( "dateTimeSao_PauloAfterMidnight: " + dateTimeSao_PauloAfterMidnight );

跑步时。

dateTimeSao_Paulo: 2041-10-20T01:00:00.000-02:00
dateTimeUtc: 2041-10-20T03:00:00.000Z
dateTimeSao_PauloBeforeMidnight: 2041-10-19T23:50:00.000-03:00
dateTimeSao_PauloAfterMidnight: 2041-10-20T01:50:00.000-02:00

通过前一天的工作进行实验,并通过plusHours方法添加小时。

正如您在上面的输出中那样, 2041年10月19日至20日午夜是DST更改的当前预定日期,其中UTC的偏移量从-03:00转移到{{ 1}}。将一小时添加到午夜之前,将wall-clock-time 两小时-02:00小时推迟到23小时,而不是{{1 }} 小时。

此外,请注意,尝试构建20日00:00:00的时间会导致Joda-Time异常,因为没有这样的日期时间。

数据库日期

JDBC ResultSet的getDate method返回java.sql.Date,这是java.util.Date的标准化版本。

java.sql.Date和java.util.Date都不包含时区信息,但假定为UTC。它们之间的区别在于01版本的时间值设置为00:00:00(午夜),但是很难与SQL data type DATE匹配。在SQL中,DATE表示仅限日期,没有时间。不幸的是,旧版本的Java和JDBC没有仅限日期的类,但应该有。这已在Java 8 the java.time package及其LocalDate class中得到纠正,但JDBC还没有赶上。

因此,如果从数据库获取java.sql.Date,则必须咨询程序员或数据库管理员以确认该日期时间是否确实意味着UTC。它应该,但正确的日期时间工作使很多程序员和管理员都没有,所以你应该验证。

如果java.sql.Date确实是UTC,则通过将其传递给DateTime构造函数来转换为Joda-Time。我强烈建议也将DateTimeZone传递给新的DateTime,而不是依赖于JVM的默认时区。

00

sql

如果您分配到非UTC时区,您可能希望将时间部分调整到该地点当天的第一时刻,以便与关注日期而不是时间的想法保持一致。要获得第一时间,请致电withTimeAtStartOfDay method(Joda-Time 2.3中的新内容,旧的“午夜”类和方法已被弃用)。

DateTime dateTimeFromDatabaseBrazil = new DateTime( myJavaSqlDate, timeZoneSao_Paulo );

如果您确定只需要日期,则可以转换为LocalDate对象。

答案 2 :(得分:0)

考虑夏令时。据我所知,你投入的时间不存在。当天午夜时钟推到凌晨1点。我不确定为什么它在Java 7中有效。也许这就是错误!

http://www.timeanddate.com/time/change/brazil/brasilia

夏令时发生在巴西每年10月的第3个星期日,其中2041年恰好在10月20日。这不是特定日期。这是十月的第三个星期天。以下是其他几个例子:

        Calendar c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("Brazil/East"));
        c.set(2017, Calendar.OCTOBER, 15, 0, 0, 0);
        System.out.println(c.getTime());
        c.set(2019, Calendar.OCTOBER, 20, 0, 0, 0);
        System.out.println(c.getTime());
        c.set(2035, Calendar.OCTOBER, 21, 0, 0, 0);
        System.out.println(c.getTime());

总的来说,我建议不要使用建议的解决方法(除了使用Joda时间并抛出异常的那个),如果你试图放入系统的时间不存在于此区域/时区中在现实生活中的应用(想想当时计划运行的日常灾难恢复工作,从未发生过)。