从2月的java.util.Calendar一个奇怪的行为 [英] A strange behavior from java.util.Calendar on February

查看:101
本文介绍了从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;
    }
}



我想知道为什么会发生这种情况? / p>

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(即2月)。你期望在这里发生什么?实际发生的是,它会记住它需要将月份设置为1,但重新计算实际时间值。根据, c 将重新计算 get 的时间值 /javase/7/docs/api/java/util/Calendar.html\">文档(emphsis mine):

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更改为值。此外,它设置一个内部成员变量以指示日历字段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日并强制执行计算时,实际上是什么

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.

最好的修复方法是:

  • 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一个奇怪的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆