Calendar在有31号的月份时注意事项

先说下我的情况:

    /**
     * 获得某一年某一季度的最后一天日期
     * @param year
     * @param quarter
     * 该方法和lastDayOfQuarter方法功能一样,只不过后者假设在10月31号执行代码时,会出现异常,日期不对。
     * @return 
     * @author yutao
     * @date 2016年10月13日下午1:24:06
     */
    public static Date lastDayOfQuarter(Integer year, Integer quarter) {
        if (quarter < 1 || quarter > 4) {
            return null;
        }
        Calendar cal = Calendar.getInstance();
        if (year != null && year > 0) {
            cal.set(Calendar.YEAR, year);
        }
        if (quarter == 1) {
            cal.set(Calendar.MONTH, 2);
        } else if (quarter == 2) {
            cal.set(Calendar.MONTH, 5);
        } else if (quarter == 3) {
            cal.set(Calendar.MONTH, 8);
        } else {
            cal.set(Calendar.MONTH, 11);
        } 
cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 000);
        return cal.getTime();
    }

假设现在我们有这么一个main方法:

public static void main(String[] args) {
System.out.println(DateUtil.dateToString(lastDayOfQuarter(2016,1), "yyyy-MM-dd"));
System.out.println(DateUtil.dateToString(lastDayOfQuarter(2016,2), "yyyy-MM-dd"));
System.out.println(DateUtil.dateToString(lastDayOfQuarter(2016,3), "yyyy-MM-dd"));
System.out.println(DateUtil.dateToString(lastDayOfQuarter(2016,4), "yyyy-MM-dd"));
}
正常情况下,它应该打印出:
2016-03-31
2016-06-30
2016-09-30
2016-12-31

但如果是在31号去执行这段代码,就变成了:
2016-03-31
2016-07-01
2016-10-01
2016-12-31

我试过,只要是31号,执行该代码,就出现这个问题。

已经一系列调试,得出结论:首先你要知道set()方法是有延迟,就是当你写这么一段代码时
`cal.set(Calendar.MONTH, 5);` 它是没有立即生效的。
当调用get()、getTime()、getTimeInMillis()、add() 或 roll()方法时,
才会重新计算日历的时间值(以毫秒为单位)。
所以当我们在31号调用`lastDayOfQuarter(2016,2), "yyyy-MM-dd")`
走到这句时:
cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
虽然它走了
else if (quarter == 2) {
            cal.set(Calendar.MONTH, 5);
        } 
也就是说,此处已经把MONTH设置为5(也就是6月),但是由于此时没有刷新calender,
`Calendar.DAY_OF_MONTH`它获取到的是今天(10月31号)的日期,DAY为31号。
也就是说Calendar里面目前被set成了6月31号。
又由于使用的是set方法,它会自动调整日期,变成7月1号。
所以getActualMaximum获得的最大值为31。


看了下文档该方法解释:
`返回指定日历字段可能拥有的最大值。`

(我猜测,由于今天是31号,所以Calendar中DAY_OF_MONTH保存的依然也是31号。
也就是说它里面目前被set成了6月31号,即7月1号。当调用:
`cal.getActualMaximum(Calendar.DAY_OF_MONTH))`的时候,
获取到的是7月份的最大值。后来我做了测试验证了我的猜测是对的)

如果使用的是cal.add()的方法,则月份不会变,而是调整日期。
也就是变成6月30号。所以一般我们都使用set()。

解决办法上面问题也很简单,在调用`getActualMaximum`方法之前,把`DAY_OF_MONTH`,
设置为1号(反正别为31号,考虑二月份的问题,最后还是设置为1号)。
cal.set(Calendar.DAY_OF_MONTH, 1);
获取某个最后一天还可以有另一种写法:
上面的代码关键的地方是使用`getActualMaximum(Calendar.DAY_OF_MONTH)`来获取值。
我们也可以现获取后一个月的1号日期,再使用add的方法减一天就可以啦。
    /**
     * 获得某一年某一季度的最后一天日期
     * @param year
     * @param quarter
     * @return 
     * @author yutao
     * @date 2016年10月13日下午1:24:06
     */
    public static Date lastDayOfQuarterByAdd(Integer year, Integer quarter) {
        if (quarter < 1 || quarter > 4) {
            return null;
        }
        Calendar cal = Calendar.getInstance();
        if (year != null && year > 0) {
            cal.set(Calendar.YEAR, year);
        }
        if (quarter == 1) {
            cal.set(Calendar.MONTH, 3);
        } else if (quarter == 2) {
            cal.set(Calendar.MONTH, 6);
        } else if (quarter == 3) {
            cal.set(Calendar.MONTH, 9);
        } else {
            cal.set(Calendar.MONTH, 0);
        } 
//      cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        cal.set(Calendar.DAY_OF_MONTH, 1);//设置该月1号
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 000);
        cal.add(Calendar.DATE, -1);//使用add减一天
        return cal.getTime();
    }
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java 中,大于小于操作符不能直接用于 `Calendar` 类型,因为 `Calendar` 类型不是基本数据类型或实现了 `Comparable` 接口的类。如果需要比较两个 `Calendar` 对象的大小,可以使用它们的 `compareTo` 方法来进行比较。 `compareTo` 方法是 `Calendar` 类的一个成员方法,用于比较两个日期的先后顺序。它的返回值为整型,如果两个日期相等,返回 0;如果当前日期在参数日期之前,返回负数;如果当前日期在参数日期之后,返回正数。 下面是一个使用 `compareTo` 方法进行比较的示例: ```java import java.util.Calendar; public class CalendarComparisonExample { public static void main(String[] args) { Calendar cal1 = Calendar.getInstance(); Calendar cal2 = Calendar.getInstance(); // 将 cal1 设置为 2022 年 1 月 1 日,cal2 设置为 2022 年 2 月 1 日 cal1.set(2022, Calendar.JANUARY, 1); cal2.set(2022, Calendar.FEBRUARY, 1); // 比较两个日期 int result = cal1.compareTo(cal2); if (result == 0) { System.out.println("cal1 和 cal2 日期相同"); } else if (result < 0) { System.out.println("cal1 日期在 cal2 日期之前"); } else { System.out.println("cal1 日期在 cal2 日期之后"); } } } ``` 在上述示例中,我们使用 `set` 方法设置了两个 `Calendar` 对象的日期,然后使用 `compareTo` 方法比较它们的先后顺序,并根据比较结果输出不同的信息。注意,`set` 方法中的月份需要使用 `Calendar` 类中定义的常量,例如 `Calendar.JANUARY` 表示 1 月份

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山鬼谣me

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值