package javase1day05;import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;public class DateCalDemo {
  public static void main(String[] args) {
    //时间计算的原理
    long now = System.currentTimeMillis();
    long l = now+1000L*60*60*24;//明天 
    System.out.println(l); 
    SimpleDateFormat fmt = 
      new SimpleDateFormat("yyyy-MM-dd");
    
    Calendar cal = new GregorianCalendar();
    cal.add(Calendar.MONTH, 5);
    System.out.println(fmt.format(cal.getTime()));
    cal.add(Calendar.YEAR, 5);//1387260478395
    System.out.println(fmt.format(cal.getTime()));
    cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
    System.out.println(fmt.format(cal.getTime()));  
    
    
    
  }}大家帮我看看,如果我注释掉这里(第二个输出)System.out.println(fmt.format(cal.getTime()));,得到的结果是2018年12月10日,但是从日历上来看应该 是2018年12月17日。如果我把fmt.format(cal.getTime())单独提出去的话,得到的结果是正确的。
另外,如果我注释掉第一个输出System.out.println(fmt.format(cal.getTime()));,对结果却是没有影响的,
跪求大家给我看看是为什么,难道是闰年的原因?

解决方案 »

  1.   

    我试了楼主的这个程序结果是正确的呢:public class TestDate {
    public static void main(String[] args) {
    // 时间计算的原理
    long now = System.currentTimeMillis();
    long l = now + 1000L * 60 * 60 * 24;// 明天
    System.out.println(l);
    SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd"); Calendar cal = new GregorianCalendar();
    cal.add(Calendar.MONTH, 5);
    System.out.println(fmt.format(cal.getTime()));
    cal.add(Calendar.YEAR, 5);// 1387260478395
    System.out.println(fmt.format(cal.getTime()));
    cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
    System.out.println(fmt.format(cal.getTime())); }
    }
    /*
     * 输出结果:
     *           1374133763448
     * 2013-12-17
     * 2018-12-17
     * 2018-12-17
     *
     */我用的是JDK1.7,楼主再试试看,调试一下编译环境等,应该没有什么问题的。
      

  2.   


    set(f, value) 将日历字段 f 更改为 value。此外,它设置了一个内部成员变量,以指示日历字段 f 已经被更改。尽管日历字段 f 是立即更改的,但是直到下次调用 get()、getTime()、getTimeInMillis()、add() 或 roll() 时才会重新计算日历的时间值(以毫秒为单位)。API里看到Calendar类的说明里有这段,不是太懂,应该是你把第二个getTime()注释掉的话,set()在重新计算毫秒数前改变了日期
    具体的也不太懂,坐等高人
      

  3.   

    确有蹊跷。
    API中说add后是立即重新计算时间的,但是单步跟踪代码,如果add后不调用getTime,这个时间是一直不变的。继续关注。
      

  4.   

    额,我知道你这样是可以的,因为你输出的时候调用了getTime()方法,但是如果不getTime的话就是出错了
      

  5.   

    我debug都开始头疼了,太麻烦
      

  6.   

    另外我们要注意的一点是,Calendar 为了性能原因对 set() 方法采取延缓计算的方法。在 JavaDoc 中有下面的例子来说明这个问题:Calendar cal1 = Calendar.getInstance();
    cal1.set(2000, 7, 31, 0, 0 , 0); //2000-8-31
    cal1.set(Calendar.MONTH, Calendar.SEPTEMBER); //应该是 2000-9-31,也就是 2000-10-1
    cal1.set(Calendar.DAY_OF_MONTH, 30); //如果 Calendar 转化到 2000-10-1,那么现在的结果就该是 2000-10-30
    System.out.println(cal1.getTime()); //输出的是2000-9-30,说明 Calendar 不是马上就刷新其内部的记录大家可以参考下这一段,我大致知道为什么会出错了,但是就是不知道为什么API里明明说了调用add()方法会立即计算时间值,但是结果却是没有立即调用,很费解
      

  7.   

    package javase1day05;
    import java.text.SimpleDateFormat;
    import java.util.Calendar;
    import java.util.Date;
    import java.util.GregorianCalendar;
    public class DateCalDemo {
    public static void main(String[] args) {
    // 时间计算的原理
    long now = System.currentTimeMillis();
    long l = now + 1000L * 60 * 60 * 24;// 明天
    System.out.println(l);
    SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
    System.out.println(fmt.format(new Date(l)));
    Calendar cal = new GregorianCalendar();
    cal.add(Calendar.MONTH, 5);
    System.out.println(fmt.format(cal.getTime()));
    cal.add(Calendar.YEAR, 5);
    //System.out.println(fmt.format(cal.getTime()));
    cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
    System.out.println(fmt.format(cal.getTime()));
    }
    }
    /*
     * 输出结果:
     *1374195228233
     *2013-07-19
     *2013-12-18
     *2018-12-10
     */这是把倒数第二个输出注释掉的的,package javase1day05;import java.text.SimpleDateFormat;
    import java.util.Calendar;
    import java.util.Date;
    import java.util.GregorianCalendar;public class DateCalDemo {
    public static void main(String[] args) {
    // 时间计算的原理
    long now = System.currentTimeMillis();
    long l = now + 1000L * 60 * 60 * 24;// 明天
    System.out.println(l);
    SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
    System.out.println(fmt.format(new Date(l))); Calendar cal = new GregorianCalendar();
    cal.add(Calendar.MONTH, 5);
    System.out.println(fmt.format(cal.getTime()));
    cal.add(Calendar.YEAR, 5);
    System.out.println(fmt.format(cal.getTime()));
    cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
    System.out.println(fmt.format(cal.getTime()));
    }
    }
    /*1374195414804
     *2013-07-19
     *2013-12-18
     *2018-12-18
     *2018-12-17
    */
    这是不注释掉倒数第二个输出语句的结果,前后结果相差一周。
      

  8.   

    看下System的api里面有这么一句话
    当返回值的时间单位是毫秒时,值的粒度取决于底层操作系统,并且粒度可能更大。例如,许多操作系统以几十毫秒为单位测量时间
    所以你运算一下这个代码
    long now = System.currentTimeMillis();         
    long time = new Date().getTime();
    System.out.println(now + "___" + time);
    你会发现有时候这两个值不一样,会有几十毫秒的差距。
      

  9.   

    * 首先我得承认小看了这个问题,以为只是小菜提的一般问题,结果花了我大半天调试仍然没有查出为什么。后来就去google了一下,发现这个问题已经存在很久了。
    * 官方的说法是,当你设置某个值的时候,比如cal.add(Calendar.YEAR, 5); 这时候只是更新了Calendar对象的某个field值,并没有让Calendar对象全局生效。而查看源代码发现确实如此。
    * 在调用内部computeFields 方法的时候设置的值才生效,而调用getTime方法就会调用computeFields
    ============================================
    cal.add(Calendar.YEAR, 5);cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); //这时候取的年份并不是五年后的。
    ============================================
    * 为了找出规律我调试了无数次,结果是没有找到规律,也没办法证实是由于源码中的哪一块造成的。
    不过我找了两编文章有解释这种情况的,而且解释的比较清楚,我E文半桶水。就发原文地址供大家参考
    http://stackoverflow.com/questions/6722542/java-calendar-date-is-unpredictable-after-setting-day-of-week
    http://bugs.sun.com/view_bug.do?bug_id=4655637
      

  10.   

    还有一编漏了
    http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18083#c6
      

  11.   

    谢谢了,我们老师说是设置时间字段要按照顺序来,那个顺序在API中有如果日历字段值中存在任何冲突,则 Calendar 将为最近设置的日历字段提供优先权。以下是日历字段的默认组合。将使用由最近设置的单个字段所确定的最近组合。 对于日期字段:  YEAR + MONTH + DAY_OF_MONTH
     YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
     YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
     YEAR + DAY_OF_YEAR
     YEAR + DAY_OF_WEEK + WEEK_OF_YEAR