Calendar对象

importjava.text.ParseException;importjava.text.SimpleDateFormat;importjava.util.Calen... import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
* 计算20年后当周的星期六,一周从星期日开始
* @author Administrator
*
*/
public class Test {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
Date date=sdf.parse("2006-02-14");
System.out.println(sdf.format(date));

Calendar c=Calendar.getInstance();
c.setTime(date);
c.add(Calendar.YEAR, 20);
//System.out.println(c.get(Calendar.DAY_OF_WEEK));//有就正确,没有就错误:输出2026-02-21
c.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY); //正确日期2026-02-14
System.out.println("入职20周年纪念日派对日期:"+sdf.format(c.getTime()));
}
}
感觉Calendar对象get方法后内部更新了一下set方法才正确设置星期几,不懂原因,有点小bug,求大神指点。
就是最终的
System.out.println("入职20周年纪念日派对日期:"+sdf.format(c.getTime()));
输出有两个结果,影响因素却是一个get方法是否运行在set方法前面。
展开
 我来答
ifeilong
2016-08-31 · TA获得超过8068个赞
知道大有可为答主
回答量:1187
采纳率:100%
帮助的人:811万
展开全部

这个故事有点复杂,听我慢慢道来


1.如果 你注释 //System.out.println(c.get(Calendar.DAY_OF_WEEK));

即,你只有这几行代码:

c.setTime(date);
c.add(Calendar.YEAR, 20);
c.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);


1.1 你会发现,你的时间如果设置的是  "2006-02-12" ,"2006-02-13" ,"2006-02-15" ,"2006-02-16" ,"2006-02-17","2006-02-18"



他们的输出结果都是:

入职20周年纪念日派对日期:2026-02-21


1.2 如果你设置的是 "2006-02-11"


那么结果是 :

入职20周年纪念日派对日期:2026-02-14



1.3 你会发现一个规律


"2006-02-12" ,"2006-02-13" ,"2006-02-15" ,"2006-02-16" ,"2006-02-17","2006-02-18" 这几个日期在当前月中第三周



对应的结果  2026-02-21 也是第三周的周六



而  "2006-02-11" 是当前月的第二周, 结果  2026-02-14 也是当前月的第二周


2. 原因


When computing time (milliseconds), GregorianCalendar leaves some fields inconsistent. Then, after the last set(DAY_OF_WEEK), an invalid (older) WEEK_OF_MONTH value is used in the last getTime() call.


When you set DAY_OF_WEEK, the calendar expects a week field (WEEK_OF_MONTH, DAY_OF_WEEK_IN_MONTH or WEEK_OF_YEAR) has also been set. So, avoid setting DAY_OF_WEEK without setting one of the week fields.


当你设置  DAY_OF_WEEK 的时候,  

你需要设置  WEEK_OF_MONTH 或者 DAY_OF_WEEK_IN_MONTH  或者 WEEK_OF_YEAR

否则会使用老的 WEEK_OF_MONTH 字段


这就是上述的  

  • "2006-02-11" 是当前月的第二周, 结果  2026-02-14 也是第二周(old WEEK_OF_MONTH=2)的周六

  • "2006-02-12" ,..."2006-02-18" 在 当前月是第三周,结果 2026-02-21 也是第三周(old WEEK_OF_MONTH=3 )的周六


3.那么为毛 加上 System.out.println(c.get(Calendar.DAY_OF_WEEK)); 结果就对了呢?


嘿嘿嘿, 


  • 你换成 System.out.println(c.get(Calendar.ERA)); 结果也会对

  • 你换成System.out.println("啦啦啦啦:" + sdf.format(c.getTime())); 结果也对



这个原因在于 ,当你调用了这些方法的时候 



Calendar 会调用 java.util.Calendar.complete() 方法, 



这个方法会把已经设置的参数,把 Calendar 的 17个字段都计算一下 (包括WEEK_OF_MONTH )


此时,  "2006-02-14" 20年后的日期是  2026-02-14 ,  WEEK_OF_MONTH 是当月的第二周, 都算完成了



如果没有那句调用, 那么使用的WEEK_OF_MONTH  会使用 老的第三周 ,结果就会是  2026-02-21



4.最佳实践 (推荐指南)


真心不建议自己来写 Calendar SimpleDateFormat 来操作 ,坑比较多. 

建议使用 apache commons-lang3 jar 


示例: 对我来说就三步


    public static void main(String[] args) throws ParseException{
        //1.转成date
        Date date = DateUtils.parseDate("2006-02-14", "yyyy-MM-dd");

        //2.20年后的日期
        Date d20 = DateUtils.addYears(date, 20);

        //3.20年后的日期所在周的 周六 ,
        Calendar calendar = DateUtils.toCalendar(d20);
        calendar.set(DAY_OF_WEEK, SATURDAY);
        System.out.println("入职20周年纪念日派对日期:" + DateFormatUtils.format(calendar.getTime(), "yyyy-MM-dd"));
    }



推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式