关于使用java.util.GregorianCalendar类的奇怪问题---烦请高手给以解答

sagittariusvirgo 2006-02-26 07:40:15
大家好:

目前我正在总结使用java求两个时间点日期差的问题,我自己写了一个类以实现该功能,却遇到了一个
十分奇怪的问题:
我的源码如下:
package com.bf.admin;
import java.util.*;
import java.text.*;
public class EclipseDate {
private GregorianCalendar gc1,gc2;
public static final int ACCMODE = 0; //ACC-->Accurate 精确模式,即严格时间单位 --->
public static final int UNACCMODE = 1; //非精确模式,即时间单位变化

public EclipseDate(Calendar g1,Calendar g2){
SetTime(g1,g2);
}
public void SetTime(Calendar g1,Calendar g2){
if(g2.after(g1)){
gc1 = (GregorianCalendar)g1.clone();
gc2 = (GregorianCalendar)g2.clone();
}
else{
gc1 = (GregorianCalendar)g2.clone();
gc2 = (GregorianCalendar)g1.clone();
}
}
public void SetTime(Calendar g1){
this.gc1 = (GregorianCalendar)g1.clone();
SetTime(g1,this.gc2);
}

public int GetYears(){
int iYearCount =0;
DateFormat a= DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.FULL);
GregorianCalendar g2 = (GregorianCalendar)gc2.clone();
System.out.println(a.format(g2.getTime()));
g2.clear(Calendar.MILLISECOND);
System.out.println(a.format(g2.getTime()));
g2.clear(Calendar.SECOND);
System.out.println(a.format(g2.getTime()));
g2.clear(Calendar.MINUTE);
System.out.println(a.format(g2.getTime()));
g2.clear(Calendar.HOUR);
System.out.println(a.format(g2.getTime()));
g2.clear(Calendar.HOUR_OF_DAY);
System.out.println(a.format(g2.getTime()));
g2.clear(Calendar.DATE);
System.out.println(a.format(g2.getTime()));
g2.clear(Calendar.MONTH);
System.out.println(a.format(g2.getTime()));

System.out.println(a.format(g1.getTime()));
g1.clear(Calendar.MILLISECOND);
g1.clear(Calendar.SECOND);
g1.clear(Calendar.MINUTE);
g1.clear(Calendar.HOUR);
g1.clear(Calendar.HOUR_OF_DAY);
g1.clear(Calendar.DATE);
g1.clear(Calendar.MONTH);
System.out.println(a.format(g1.getTime()));
while(g1.before(g2)){
g1.add(Calendar.YEAR,1);
iYearCount++;
}
return iYearCount;
}
public static void main(String[] args) throws Exception{
GregorianCalendar g1 = new GregorianCalendar(2006,3,28,16,38);
GregorianCalendar g2 = new GregorianCalendar();
EclipseDate ed1 = new EclipseDate(g1,g2);
System.out.println("The Eclipse Years is "+ed1.GetYears());

}
}
运行后为:
2006年4月28日 星期五 下午04时38分16秒 CST

2006年4月28日 星期五 下午04时38分16秒 CST

2006年4月28日 星期五 下午04时38分00秒 CST

2006年4月28日 星期五 下午04时00分00秒 CST

2006年4月28日 星期五 下午04时00分00秒 CST

2006年4月28日 星期五 上午12时00分00秒 CST

2006年4月1日 星期六 上午12时00分00秒 CST

2006年1月1日 星期日 上午12时00分00秒 CST

2006年10月12日 星期四 下午04时46分33秒 CST

2006年1月12日 星期四 上午12时00分00秒 CST

The Eclipse Years is 0

显然如果日期对象是通过GregorianCalendar的0参数构造函数的话,调用相映的clear(Calendar.Date)
,clear(Calendar.Month)时,該函數功能失效,我真是百思不得其解,烦请高手赐教
...全文
452 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
sagittariusvirgo 2006-03-07
  • 打赏
  • 举报
回复
請問是不是以下注釋中的<RULE 2>
/**
* Adds the specified (signed) amount of time to the given time field,
* based on the calendar's rules.
* <p><em>Add rule 1</em>. The value of <code>field</code>
* after the call minus the value of <code>field</code> before the
* call is <code>amount</code>, modulo any overflow that has occurred in
* <code>field</code>. Overflow occurs when a field value exceeds its
* range and, as a result, the next larger field is incremented or
* decremented and the field value is adjusted back into its range.</p>
*
* <p><em>Add rule 2</em>. If a smaller field is expected to be
* invariant, but it is impossible for it to be equal to its
* prior value because of changes in its minimum or maximum after
* <code>field</code> is changed, then its value is adjusted to be as close
* as possible to its expected value. A smaller field represents a
* smaller unit of time. <code>HOUR</code> is a smaller field than
* <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
* that are not expected to be invariant. The calendar system
* determines what fields are expected to be invariant.</p>
* @param field the time field.
* @param amount the amount of date or time to be added to the field.
* @exception IllegalArgumentException if an unknown field is given.
*/
public void add(int field, int amount) {
......}
難道所有小於DATE的field,都是invariant的嗎,還是有些困惑,希望高手指點一下
kingfish 2006-03-02
  • 打赏
  • 举报
回复
看看GregorianCalendar.java的注释
sagittariusvirgo 2006-03-01
  • 打赏
  • 举报
回复
你的算法只是計算日期的一種情況,我的源碼如下:
package com.foxconn.date;
import java.util.*;
import java.text.*;

/**怎樣計算出任意兩個日期之間相差的年數,月數,天數,小時,分鐘.....?
* 例如:2005-5-21 到 2008-10-3
* 日期格式:2005-5-20
*/
public class EclipseDate {

private GregorianCalendar gc1,gc2;

public static final int ACCMODE = 0; //ACC-->Accurate 精確模式,即嚴格時間單位 --->對應於
public static final int UNACCMODE = 1; //非精確模式,即時間單位變化

public EclipseDate(Calendar g1,Calendar g2){
SetTime(g1,g2);
}
public void SetTime(Calendar g1,Calendar g2){
if(g2.after(g1)){ //注:在JDK源碼中,是通過比較這兩個日期所對應的Date()的毫秒數來計算的,既從1970年1月1日至今的毫秒數
gc1 = (GregorianCalendar)g1.clone();
gc2 = (GregorianCalendar)g2.clone();
}
else{
gc1 = (GregorianCalendar)g2.clone();
gc2 = (GregorianCalendar)g1.clone();
}
}
public void SetTime(Calendar g1){
this.gc1 = (GregorianCalendar)g1.clone();
SetTime(g1,this.gc2);
}

public int GetYears(){
int iYearCount =0;
GregorianCalendar g1 = (GregorianCalendar)gc1.clone();
GregorianCalendar g2 = (GregorianCalendar)gc2.clone();
g1.clear(Calendar.MILLISECOND);
g1.clear(Calendar.SECOND);
g1.clear(Calendar.MINUTE);
g1.clear(Calendar.HOUR);
g1.clear(Calendar.HOUR_OF_DAY);
//g1.clear(Calendar.DATE);
g1.set(Calendar.DATE,1);
g1.clear(Calendar.MONTH);
System.out.println(g1.getTime());

g2.clear(Calendar.MILLISECOND);
g2.clear(Calendar.SECOND);
g2.clear(Calendar.MINUTE);
g2.clear(Calendar.HOUR);
g2.clear(Calendar.HOUR_OF_DAY);
// g2.clear(Calendar.DAY_OF_MONTH);
g2.set(Calendar.DATE,1);
g2.clear(Calendar.MONTH);
System.out.println(g2.getTime());

while(g1.before(g2)){
g1.add(Calendar.YEAR,1);
iYearCount++;
}
return iYearCount;
}

public int GetMonths(){
int iMonthCount = 0;
GregorianCalendar g1 = (GregorianCalendar)gc1.clone();
GregorianCalendar g2 = (GregorianCalendar)gc2.clone();

g1.clear(Calendar.MILLISECOND);
g1.clear(Calendar.SECOND);
g1.clear(Calendar.MINUTE);
g1.clear(Calendar.HOUR);
g1.clear(Calendar.DATE);

g2.clear(Calendar.MILLISECOND);
g2.clear(Calendar.SECOND);
g2.clear(Calendar.MINUTE);
g2.clear(Calendar.HOUR);
g2.clear(Calendar.DATE);

while(g1.before(g2)){
g1.add(Calendar.MONTH,1);
iMonthCount ++;
}
return iMonthCount;
}

public int GetDays(int iMode){ //iMode的取值範圍是{ACCMODE,UNACCMODE},所以如果用戶輸入其他的非法值,系統應拋出異常
switch(iMode){
case ACCMODE:
return GetDaysMode1();
case UNACCMODE:
return GetDaysMode2();
}
return 0;
}

private int GetDaysMode1(){
long lt1 = this.gc1.getTimeInMillis();
long lt2 = this.gc2.getTimeInMillis();
long lResult = Math.abs(lt2-lt1) /(24*60*60*1000);
return (int)lResult;
}

private int GetDaysMode2(){
int iDays = 0;
GregorianCalendar g1 = (GregorianCalendar)this.gc1.clone();
GregorianCalendar g2 = (GregorianCalendar)this.gc2.clone();

g1.clear(Calendar.MILLISECOND);
g1.clear(Calendar.SECOND);
g1.clear(Calendar.MINUTE);
g1.clear(Calendar.HOUR);

g2.clear(Calendar.MILLISECOND);
g2.clear(Calendar.SECOND);
g2.clear(Calendar.MINUTE);
g2.clear(Calendar.HOUR);

while(g1.before(g2)){
g1.add(Calendar.DATE,1);
iDays++;
}
return iDays;
}
public int GetHours(int iMode){ //iMode的取值範圍是{ACCMODE,UNACCMODE},所以如果用戶輸入其他的非法值,系統應拋出異常
switch(iMode){
case ACCMODE:
return GetHoursMode1();
case UNACCMODE:
return GetHoursMode2();
}
return 0;
}

private int GetHoursMode1(){
long lt1 = this.gc1.getTimeInMillis();
long lt2 = this.gc2.getTimeInMillis();

long iEclipseSeconds =(long) (lt2 -lt1)/1000;
int iResult =(int) iEclipseSeconds / (60*60);
return iResult;

}

private int GetHoursMode2(){
int iHours = 0;
GregorianCalendar g1 = (GregorianCalendar)this.gc1.clone();
GregorianCalendar g2 = (GregorianCalendar)this.gc2.clone();

g1.clear(Calendar.MILLISECOND);
g1.clear(Calendar.SECOND);
g1.clear(Calendar.MINUTE);

g2.clear(Calendar.MILLISECOND);
g2.clear(Calendar.SECOND);
g2.clear(Calendar.MINUTE);

while(g1.before(g2)){
g1.add(Calendar.HOUR,1);
iHours++;
}
return iHours;
}
public void GetEclipsedTime(){
long iDays,iHours,iMinutes,iSeconds;
long lt1 = this.gc1.getTimeInMillis();
long lt2 = this.gc2.getTimeInMillis();
long lEclipseSeconds = Math.abs(lt2-lt1)/1000;
iDays = (int)lEclipseSeconds/(24*60*60); //Take Care :the "()" is required;^_^
lEclipseSeconds = lEclipseSeconds % (24*60*60);
iHours = lEclipseSeconds / 3600;
lEclipseSeconds = lEclipseSeconds %3600;
iMinutes = lEclipseSeconds / 60;
iSeconds = lEclipseSeconds %60;
System.out.println("The Eclipse time is "+iDays+" days, "+iHours+" hours, "+iMinutes+" minutes, "+iSeconds+" seconds");
}

public static void main(String[] args) throws Exception{
GregorianCalendar g1 = new GregorianCalendar(2005,Calendar.FEBRUARY,23,14,58,40);
GregorianCalendar g2 = new GregorianCalendar();
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.FULL);
System.out.println("The Original Dates is "+"\n"+df.format(g1.getTime())+"\n"+df.format(g2.getTime())+"\n");
EclipseDate ed1 = new EclipseDate(g1,g2);
System.out.println("The Eclipse Years is "+ed1.GetYears());
System.out.println("The Eclipse Months is"+ed1.GetMonths());
System.out.println("The Eclipse Days in Accurate Mode is"+ed1.GetDays(EclipseDate.ACCMODE));
System.out.println("The Eclipse Days in UNAccurate Mode is"+ed1.GetDays(EclipseDate.UNACCMODE));
System.out.println("The Eclispe Hours in Accurate Mode is"+ed1.GetHours(EclipseDate.ACCMODE));
System.out.println("The Eclipse Hours in UNAccurate Mode is" +ed1.GetHours(EclipseDate.UNACCMODE));
System.out.println("The Eclipse Minutes in Accurate Mode is"+ed1.GetMinutes(EclipseDate.ACCMODE));
System.out.println("The Eclipse Minutes in UNAccurate Mode is"+ed1.GetMinutes(EclipseDate.UNACCMODE));
System.out.println("The Eclpse Seconds is "+ed1.GetSeconds());
}

}
treeClimber 2006-02-28
  • 打赏
  • 举报
回复
求两个日期的时间差有必要这么麻烦吗?看我写的一个方法:
/**
* 返回两个日期间的天数
* @param fromDate 起始日期
* @param toDate 截止日期
* @return 相隔天数
*/
public static int getInterval(Date fromDate,Date toDate){
return (int)((toDate.getTime()-fromDate.getTime())/1000/3600/24);
}
public static int getInterval(int fYear,int fMonth,int fDay,
int tYear,int tMonth,int tDay){
Date fromDate = new GregorianCalendar(fYear,fMonth-1,fDay).getTime();
Date toDate = new GregorianCalendar(tYear,tMonth-1,tDay).getTime();
return getInterval(fromDate,toDate);
}
public static int getInterval(String strDate,String strEndDate){
Date fromDate = getDateFromString(strDate);
Date toDate = getDateFromString(strEndDate);
return getInterval(fromDate,toDate);
}
kingfish 2006-02-27
  • 打赏
  • 举报
回复
Default values are not applicable for the fields(包括DATE)
sagittariusvirgo 2006-02-27
  • 打赏
  • 举报
回复
首先,非常感谢你能答复我的问题,不过可能是我表述上有问题,所以我的疑问仍然没有解决,下面我把我的问题重述一下:
JDK 1.4 源码:
public GregorianCalendar() {
this(TimeZone.getDefault(), Locale.getDefault());
}
public GregorianCalendar(int year, int month, int date) {
super(TimeZone.getDefault(), Locale.getDefault());
this.set(ERA, AD);
this.set(YEAR, year);
this.set(MONTH, month);
this.set(DATE, date);
}
public final void clear(int field)
{
int[] tempFields = {
1, 1970, JANUARY, 1, 1, 1, 1, THURSDAY, 1, AM, 0, 0, 0,
0, 0, zone.getRawOffset(), 0
};
isTimeSet = false;
areFieldsSet = false;
isSet[field] = false;
fields[field] = tempFields[field];
}
我的程序源码:
System.out.println(a.format(g1.getTime()));
g1.clear(Calendar.MILLISECOND);
g1.clear(Calendar.SECOND);
g1.clear(Calendar.MINUTE);
g1.clear(Calendar.HOUR);
g1.clear(Calendar.HOUR_OF_DAY);
g1.clear(Calendar.DATE);
g1.clear(Calendar.MONTH);
System.out.println(a.format(g1.getTime()));
程序结果:
2006年10月12日 星期四 下午04时46分33秒 CST

2006年1月12日 星期四 上午12时00分00秒 CST

显然如果GregorianCalendar对象是通过 new GregorianCalendar()来生成的,仍可以掉用其clear() 函数,所以才有 "2006年1月12日 星期四 上午12时00分00秒 CST",显然DATE字段调用对象的clear()函数后,不起作用.网上有关于GregorianCalendar.clear(HOUR),失效的描述:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4414844,但是却没有关于GregorianCalendar.clear(DATE)也失效的資料,所以我很想知道这个问题到底是JDK的问题,还是我的程序的问题.
f_acme 2006-02-27
  • 打赏
  • 举报
回复
源码:
public GregorianCalendar() {
this(TimeZone.getDefaultRef(), Locale.getDefault());
setZoneShared(true);
}
API中的说明:
GregorianCalendar()
--在具有默认语言环境的默认时区内使用当前时间构造一个默认的 GregorianCalendar。
所以跟g1一样的了,同样可以调用clear()的。
sagittariusvirgo 2006-02-27
  • 打赏
  • 举报
回复
Thanks a million but i'm still confused.
JDK 1.4 SourceCode:
public final void clear(int field)
{
int[] tempFields = {
1, 1970, JANUARY, 1, 1, 1, 1, THURSDAY, 1, AM, 0, 0, 0,
0, 0, zone.getRawOffset(), 0
};
isTimeSet = false;
areFieldsSet = false;
isSet[field] = false;
fields[field] = tempFields[field];
}
private static final String[] fieldNames =
{
",ERA=", ",YEAR=", ",MONTH=",
",WEEK_OF_YEAR=",
",WEEK_OF_MONTH=",
",DAY_OF_MONTH=",
",DAY_OF_YEAR=", ",DAY_OF_WEEK=",
",DAY_OF_WEEK_IN_MONTH=",
",AM_PM=", ",HOUR=",
",HOUR_OF_DAY=", ",MINUTE=",
",SECOND=", ",MILLISECOND=",
",ZONE_OFFSET=", ",DST_OFFSET="
};

public static final int DATE = 5;
public static final int DAY_OF_MONTH = 5;

So Why it doesn't take effect?
Is there any document about it,could you show me!I read all the information of Calendar in the JDK 1.5 document with no result

62,614

社区成员

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

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