【问题标题】:Why does this Calendar fail?为什么这个日历会失败?
【发布时间】:2025-12-10 13:15:01
【问题描述】:

所以我有一个尊重您的时区的 Java 应用程序,我注意到一些时区的日期无效...

我正在使用SimpleDateFormatter('yyyyMMdd') 进行解析...并发现它在某些时区日期组合中以ParseException 失败。

我查看了内部结构,看起来它失败了,因为 Calendar 类正在抛出 IllegalArgumentException

我正在使用setLenient(false),因为我不希望解析做出假设。默认使用setLenient(true) 假定缺少字段并且不会抛出IllegalArgumentException

为什么这个有效:

 public void testCalendarPass() {
    Calendar cal = Calendar.getInstance();
    cal.clear();
    cal.setLenient(false);
    cal.set(Calendar.YEAR, 1995);
    cal.set(Calendar.MONTH, Calendar.JANUARY);
    cal.set(Calendar.DAY_OF_MONTH,1);

    //This call will pass
    cal.getTime();
}

虽然太平洋/基里蒂马蒂的这个失败了:

public void testCalendarFailure() {
    Calendar cal = Calendar.getInstance();
    cal.clear();
    cal.setTimeZone(TimeZone.getTimeZone("Pacific/Kiritimati"));
    cal.setLenient(false);
    cal.set(Calendar.YEAR, 1995);
    cal.set(Calendar.MONTH, Calendar.JANUARY);
    cal.set(Calendar.DAY_OF_MONTH,1);

    //This call will fail
    cal.getTime();
}

Kiritimati 不存在 1995 年 1 月 1 日吗?他们如何参考该差距内的时间?

目前,当我遇到ParseException 时,我默认使用服务器的时区进行解析。但这会引入长达 24 小时的偏移量(取决于时区)。

以下是在其他时区失败的其他日期列表:

19930820 FAILS on Kwajalein
19930820 FAILS on Pacific/Kwajalein
20111230 FAILS on MIT
20111230 FAILS on Pacific/Apia
19950101 FAILS on Pacific/Enderbury
20111230 FAILS on Pacific/Fakaofo
19950101 FAILS on Pacific/Kiritimati

【问题讨论】:

    标签: java date calendar


    【解决方案1】:

    这是因为 Kirimati 在 1 月 1 日遭遇了 24 小时轮班。 The Republic of Kiribati, in the Central Pacific, introduced a change of date for its eastern half on 1 January 1995, from time zones UTC−11 and UTC−10 to UTC+13 and UTC+14. Before this, the country was divided by the IDL. After the change, the IDL in effect moved eastwards to go around this country. http://en.wikipedia.org/wiki/International_Date_Line#Eastern_Kiribati.

    另外,我看了一下阿皮亚,似乎是:At 0000 local 30 December 2011 the clocks were moved 24 hours aheadhttp://en.wikipedia.org/wiki/Apia

    显然,由于 24 小时轮班,这两个日期实际上并不存在于各自时区的日历中。对所有其他人来说可能都是如此。

    【讨论】:

    • 这太疯狂了!所以......人们通常不会在改变时区时改变他们的生日......所以如果我出生于 1995 年 1 月 1 日......然后我搬到了基里巴斯......我的生日不再存在......现在我'我只是想通过使用我提到的默认时区来解决它......有没有更好的方法来解决这个冲突? (也许我应该假设最接近的解释?)也许打开宽大处理会更好?
    【解决方案2】:

    编辑:我最初认为 Java 无法识别“Pacific/Kiritimati”的含义。但事实证明确实如此。要获取 Java 将识别的所有字符串的列表,请使用:

    Set<String> ids = new TreeSet<String>();
    for (String id : TimeZone.getAvailableIDs())
       ids.add(id);
    for (String id : ids)
      System.out.println(id);
    

    【讨论】: