A strange behavior from java.util.Calendar on February(2 月 java.util.Calendar 的一个奇怪行为)
问题描述
我遇到了来自 java.util.Calendar 的奇怪行为:
I faced with a strange behavior from java.util.Calendar:
import static org.junit.Assert.*;
import org.junit.Test;
import java.util.Calendar;
public class Tester1 {
@Test
public void test_monthOfDate() {
assertEquals(1, monthOfDate(2013, 1, 30)); // OK
assertEquals(1, monthOfDate(2013, 1, 31)); // OK
// Start of February
assertEquals(2, monthOfDate(2013, 2, 1)); // FAIL
assertEquals(2, monthOfDate(2013, 2, 28)); // FAIL
// to the end of it
// and after that it is okay also
assertEquals(3, monthOfDate(2013, 3, 1)); // OK
}
public int monthOfDate(int year, int month, int day) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month - 1);
// just a simple get! but seems it is very important
cal.get(Calendar.MONTH);
//
cal.set(Calendar.DAY_OF_MONTH, day);
return cal.get(Calendar.MONTH) + 1;
}
}
我想知道为什么会这样?
I want to know why exactly this is happening?
推荐答案
问题是您从 2013 年 1 月 30 日开始的日历.
The problem is that you're starting off with a calendar on January 30th 2013.
然后您将年份设置为 2013 年 - 这不是问题.
You're then setting the year to 2013 - that's not a problem.
然后您将月份设置为 1(即二月).你期望在这里发生什么?实际发生的是它会记住它需要将月份设置为 1,但 不会 重新计算实际时间值.根据 文档(重点是我的):
You're then setting the month to 1 (i.e. February). What do you expect to happen here? What actually happens is that it will remember that it needs to set the month to 1, but not recompute the actual time value. The time value will be recomputed on your call to get
though, as per the documentation (emphsis mine):
set(f, value) 将日历字段 f 更改为 value.此外,它设置一个内部成员变量来指示日历字段 f 已更改.尽管日历字段 f 立即更改,但在下一次调用 get()、getTime()、getTimeInMillis()、add() 或 roll() 之前,不会重新计算日历的时间值(以毫秒为单位).因此,多次调用 set() 不会触发多次不必要的计算.作为使用 set() 更改日历字段的结果,其他日历字段也可能更改,具体取决于日历字段、日历字段值和日历系统.另外,get(f)在重新计算日历字段后,不一定会返回调用set方法设置的值.具体由具体的日历类决定.
set(f, value) changes calendar field f to value. In addition, it sets an internal member variable to indicate that calendar field f has been changed. Although calendar field f is changed immediately, the calendar's time value in milliseconds is not recomputed until the next call to get(), getTime(), getTimeInMillis(), add(), or roll() is made. Thus, multiple calls to set() do not trigger multiple, unnecessary computations. As a result of changing a calendar field using set(), other calendar fields may also change, depending on the calendar field, the calendar field value, and the calendar system. In addition, get(f) will not necessarily return value set by the call to the set method after the calendar fields have been recomputed. The specifics are determined by the concrete calendar class.
当您尝试将1 月 30 日"更改为2 月 30 日"并强制进行计算时,实际上会发生的是您在 3 月 2 日结束了我的盒子 - 但您的可能会有所不同实施.
When you try to change "January 30th" to "February 30th" and force a computation, what actually happens is that you end up on March 2nd on my box - but it may differ on your implementation.
最好的修复方法是:
- 使用
Calendar.set(year, month, date)
来避免这个排序问题 - 首先使用 Joda Time 作为更合理的 API.
- Use
Calendar.set(year, month, date)
instead to avoid this ordering issue - Use Joda Time as a more sensible API in the first place.
这篇关于2 月 java.util.Calendar 的一个奇怪行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:2 月 java.util.Calendar 的一个奇怪行为


- 转换 ldap 日期 2022-01-01
- Eclipse 的最佳 XML 编辑器 2022-01-01
- 将 Java Swing 桌面应用程序国际化的最佳实践是什么? 2022-01-01
- 如何指定 CORS 的响应标头? 2022-01-01
- 在 Java 中,如何将 String 转换为 char 或将 char 转换 2022-01-01
- 获取数字的最后一位 2022-01-01
- 如何使 JFrame 背景和 JPanel 透明且仅显示图像 2022-01-01
- 未找到/usr/local/lib 中的库 2022-01-01
- java.lang.IllegalStateException:Bean 名称“类别"的 BindingResult 和普通目标对象都不能用作请求属性 2022-01-01
- GC_FOR_ALLOC 是否更“严重"?在调查内存使用情况时? 2022-01-01