求大神帮我看看Date的一个问题

sam__fang 2013-07-17 02:32:35

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()));
,对结果却是没有影响的,
跪求大家给我看看是为什么,难道是闰年的原因?
...全文
283 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
Date很多都过时了
sam__fang 2013-07-19
  • 打赏
  • 举报
回复
引用 14 楼 yousteely 的回复:
* 首先我得承认小看了这个问题,以为只是小菜提的一般问题,结果花了我大半天调试仍然没有查出为什么。后来就去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
谢谢了,我们老师说是设置时间字段要按照顺序来,那个顺序在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
Rac_javac 2013-07-18
  • 打赏
  • 举报
回复
看下System的api里面有这么一句话 当返回值的时间单位是毫秒时,值的粒度取决于底层操作系统,并且粒度可能更大。例如,许多操作系统以几十毫秒为单位测量时间 所以你运算一下这个代码 long now = System.currentTimeMillis(); long time = new Date().getTime(); System.out.println(now + "___" + time); 你会发现有时候这两个值不一样,会有几十毫秒的差距。
sam__fang 2013-07-18
  • 打赏
  • 举报
回复
引用 11 楼 yousteely 的回复:
表示很想帮忙,而且能帮上忙。但不知道楼主的问题是什么。 把没注释前的代码和结果贴出来,再把注释后的代码和结果贴出来,然后告诉大家你的疑问是什么。
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
*/
这是不注释掉倒数第二个输出语句的结果,前后结果相差一周。
steely_chen 2013-07-18
  • 打赏
  • 举报
回复
还有一编漏了 http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18083#c6
steely_chen 2013-07-18
  • 打赏
  • 举报
回复
* 首先我得承认小看了这个问题,以为只是小菜提的一般问题,结果花了我大半天调试仍然没有查出为什么。后来就去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
steely_chen 2013-07-17
  • 打赏
  • 举报
回复
表示很想帮忙,而且能帮上忙。但不知道楼主的问题是什么。 把没注释前的代码和结果贴出来,再把注释后的代码和结果贴出来,然后告诉大家你的疑问是什么。
sam__fang 2013-07-17
  • 打赏
  • 举报
回复
另外我们要注意的一点是,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()方法会立即计算时间值,但是结果却是没有立即调用,很费解
sam__fang 2013-07-17
  • 打赏
  • 举报
回复
引用 6 楼 my_panpan 的回复:
确有蹊跷。 API中说add后是立即重新计算时间的,但是单步跟踪代码,如果add后不调用getTime,这个时间是一直不变的。 继续关注。
我debug都开始头疼了,太麻烦
sam__fang 2013-07-17
  • 打赏
  • 举报
回复
引用 3 楼 ysjian_pingcx 的回复:
我试了楼主的这个程序结果是正确的呢:

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,楼主再试试看,调试一下编译环境等,应该没有什么问题的。
额,我知道你这样是可以的,因为你输出的时候调用了getTime()方法,但是如果不getTime的话就是出错了
dahlwuyn 2013-07-17
  • 打赏
  • 举报
回复
不要用Date,用Calendar
my_panpan 2013-07-17
  • 打赏
  • 举报
回复
确有蹊跷。 API中说add后是立即重新计算时间的,但是单步跟踪代码,如果add后不调用getTime,这个时间是一直不变的。 继续关注。
叶落归秋 2013-07-17
  • 打赏
  • 举报
回复

set(f, value) 将日历字段 f 更改为 value。此外,它设置了一个内部成员变量,以指示日历字段 f 已经被更改。尽管日历字段 f 是立即更改的,但是直到下次调用 get()、getTime()、getTimeInMillis()、add() 或 roll() 时才会重新计算日历的时间值(以毫秒为单位)。
API里看到Calendar类的说明里有这段,不是太懂,应该是你把第二个getTime()注释掉的话,set()在重新计算毫秒数前改变了日期 具体的也不太懂,坐等高人
花木兰1闪21A 2013-07-17
  • 打赏
  • 举报
回复
1374134082741
2013-12-17
2018-12-17
2018-12-17
成功构建 (总时间: 0 秒)
铁运行结果
  • 打赏
  • 举报
回复
我试了楼主的这个程序结果是正确的呢:

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,楼主再试试看,调试一下编译环境等,应该没有什么问题的。
OPPPPOP 2013-07-17
  • 打赏
  • 举报
回复
顶一下 同关注

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧