-计算Android中重复发生的事件时还剩1469913天

-计算Android中重复发生的事件时还剩1469913天,android,date,calendar,gregorian-calendar,Android,Date,Calendar,Gregorian Calendar,对于重复发生的事件,我想在我的Android日历应用程序中显示距离下一次事件的剩余天数 示例: Today: 2012-06-12 Reoccurring event: 19th June => 13 days left public int getDaysLeft() { Date next = this.getNextOccurrence(); if (next == null) { return -1; } else {

对于重复发生的事件,我想在我的Android日历应用程序中显示距离下一次事件的剩余天数

示例:

Today: 2012-06-12
Reoccurring event: 19th June
=> 13 days left
public int getDaysLeft() {
    Date next = this.getNextOccurrence();
    if (next == null) {
        return -1;
    }
    else {
        long differenceInMilliseconds = next.getTime()-System.currentTimeMillis();
        double differenceInDays = (double) differenceInMilliseconds/DateUtils.DAY_IN_MILLIS;
        return (int) Math.ceil(differenceInDays);
    }
}
public Date getNextOccurrence() {
    if (this.cal == null) {
        return null;
    }
    else {
        Calendar today = new GregorianCalendar();
        Calendar next = new GregorianCalendar();
        next.setTime(this.cal.getTime());
        next.set(Calendar.YEAR, today.get(Calendar.YEAR));
        if ((today.get(Calendar.MONTH) > this.cal.get(Calendar.MONTH)) || ((today.get(Calendar.MONTH) == this.cal.get(Calendar.MONTH)) && (today.get(Calendar.DAY_OF_MONTH) > this.cal.get(Calendar.DAY_OF_MONTH)))) {
            next.add(Calendar.YEAR, 1);
        }
        return next.getTime();
    }
}
(new SimpleDateFormat("yyyy-MM-dd")).parse(INPUT_DATE_STRING)
为了实现这一点,我保存了数据类型为
Calendar
的对象中的第一个事件:

private Calendar cal;
...
cal = new GregorianCalendar();
cal.set(Calendar.YEAR, USER_INPUT_YEAR);
cal.set(Calendar.MONTH, USER_INPUT_MONTH);
...
要计算剩余天数,我使用此函数:

Today: 2012-06-12
Reoccurring event: 19th June
=> 13 days left
public int getDaysLeft() {
    Date next = this.getNextOccurrence();
    if (next == null) {
        return -1;
    }
    else {
        long differenceInMilliseconds = next.getTime()-System.currentTimeMillis();
        double differenceInDays = (double) differenceInMilliseconds/DateUtils.DAY_IN_MILLIS;
        return (int) Math.ceil(differenceInDays);
    }
}
public Date getNextOccurrence() {
    if (this.cal == null) {
        return null;
    }
    else {
        Calendar today = new GregorianCalendar();
        Calendar next = new GregorianCalendar();
        next.setTime(this.cal.getTime());
        next.set(Calendar.YEAR, today.get(Calendar.YEAR));
        if ((today.get(Calendar.MONTH) > this.cal.get(Calendar.MONTH)) || ((today.get(Calendar.MONTH) == this.cal.get(Calendar.MONTH)) && (today.get(Calendar.DAY_OF_MONTH) > this.cal.get(Calendar.DAY_OF_MONTH)))) {
            next.add(Calendar.YEAR, 1);
        }
        return next.getTime();
    }
}
(new SimpleDateFormat("yyyy-MM-dd")).parse(INPUT_DATE_STRING)
使用此功能的:

Today: 2012-06-12
Reoccurring event: 19th June
=> 13 days left
public int getDaysLeft() {
    Date next = this.getNextOccurrence();
    if (next == null) {
        return -1;
    }
    else {
        long differenceInMilliseconds = next.getTime()-System.currentTimeMillis();
        double differenceInDays = (double) differenceInMilliseconds/DateUtils.DAY_IN_MILLIS;
        return (int) Math.ceil(differenceInDays);
    }
}
public Date getNextOccurrence() {
    if (this.cal == null) {
        return null;
    }
    else {
        Calendar today = new GregorianCalendar();
        Calendar next = new GregorianCalendar();
        next.setTime(this.cal.getTime());
        next.set(Calendar.YEAR, today.get(Calendar.YEAR));
        if ((today.get(Calendar.MONTH) > this.cal.get(Calendar.MONTH)) || ((today.get(Calendar.MONTH) == this.cal.get(Calendar.MONTH)) && (today.get(Calendar.DAY_OF_MONTH) > this.cal.get(Calendar.DAY_OF_MONTH)))) {
            next.add(Calendar.YEAR, 1);
        }
        return next.getTime();
    }
}
(new SimpleDateFormat("yyyy-MM-dd")).parse(INPUT_DATE_STRING)
顺便说一句,要获取初始日期,我希望找到一个YYYY-MM-DD值,并像这样解析它:

Today: 2012-06-12
Reoccurring event: 19th June
=> 13 days left
public int getDaysLeft() {
    Date next = this.getNextOccurrence();
    if (next == null) {
        return -1;
    }
    else {
        long differenceInMilliseconds = next.getTime()-System.currentTimeMillis();
        double differenceInDays = (double) differenceInMilliseconds/DateUtils.DAY_IN_MILLIS;
        return (int) Math.ceil(differenceInDays);
    }
}
public Date getNextOccurrence() {
    if (this.cal == null) {
        return null;
    }
    else {
        Calendar today = new GregorianCalendar();
        Calendar next = new GregorianCalendar();
        next.setTime(this.cal.getTime());
        next.set(Calendar.YEAR, today.get(Calendar.YEAR));
        if ((today.get(Calendar.MONTH) > this.cal.get(Calendar.MONTH)) || ((today.get(Calendar.MONTH) == this.cal.get(Calendar.MONTH)) && (today.get(Calendar.DAY_OF_MONTH) > this.cal.get(Calendar.DAY_OF_MONTH)))) {
            next.add(Calendar.YEAR, 1);
        }
        return next.getTime();
    }
}
(new SimpleDateFormat("yyyy-MM-dd")).parse(INPUT_DATE_STRING)
这在大多数情况下都可以正常工作,但一些用户报告说,他们将诸如
-1469913
之类的数字视为“剩余天数”。这怎么会发生

我认为日期(
cal
)可能未设置或无效,但它会显示
-1
或类似的内容,因为所有部分都有空检查,对吗

-1469913
的意思是几年前的
-4027
!由于这是一个反复发生的事件,我认为“剩余天数”信息应该始终在0到366之间。是什么导致此代码生成这样一个数字?这是否意味着
getNextOccurrence()
返回的数据是过去4027年的数据?我无法解释这种行为

我希望你能帮助我。提前非常感谢

编辑:可能会有所帮助:使用
DateFormat.getDateInstance().format()
时,错误日期的年份总是输出为
1
,例如
1年1月3日
。然而,
getDaysLeft()
的结果大约是4k年

编辑#2:我发现像
1--22199-1
这样的日期可以产生“剩余4k年”的输出。但是,它被
(新的SimpleDataFormat(“yyyy-MM-dd”))成功解析。parse()
。类似地,
-1-1-91-
被正确解析为
Jan 1,2


编辑#3:结果是,像“0000-01-03”这样简单的日期造成了所有的麻烦。当我以毫秒为单位输出时间时,它会显示
-621672228000000
。然后,当我将其输出到GMT字符串时,它会说
0001-01-03
-奇怪,不是吗?当我将年份设置为1900时,以毫秒为单位的时间突然变成了12209504040000。为什么?

在处理日期时,在这些模糊的错误发生在野外用户身上之前,很难找出它们。在很多情况下,花点时间做一个小单元测试是值得的,它会在机器中抛出数千万个日期,看看是否会出现任何极端的答案

也可能值得一读。在尝试更好的方法之前,您不会意识到java date类有多糟糕

编辑:如果用户提供了非常高的输入值,那么在
getDaysLeft()
中将结果转换为整数时,可能会出现数字溢出。把它留长一点。或者更好:只接受合理的输入值,如果用户输入了20120年或类似的年份,则警告用户:)

EDIT2:我上次编辑时出错,
.ceil()
可防止数字溢出。老实说,我已经不知道这个错误是怎么发生的了

EDIT3:对第三次编辑的响应:记住,
Date
Calendar
使用。这意味着零表示的时间是1970年。1970年之前的一切都将用负值表示

EDIT4:记住javas日历类很糟糕。此代码段说明错误实际上在Calendar类中:

Calendar next = new GregorianCalendar();
long date1 = -62167222800000L;
long date2 = -62135600400000L;

next.setTimeInMillis(date1);
next.set(Calendar.YEAR, 2012);
System.out.println(next.getTimeInMillis());

next.setTimeInMillis(date2);
next.set(Calendar.YEAR, 2012);
System.out.println(next.getTimeInMillis());
输出:

-125629491600000
1325545200000
然而,很难找到导致这种情况的确切错误。这些bug之所以依然存在,是因为修复它们可能会破坏世界各地的遗留系统。我的猜测是,这个错误源于无法给出负的年份。例如,这将给出输出“2013”:


我只是建议您不要在输入中使用这种极端值。确定可接受的范围,如果值超出这些边界,则给出错误消息。如果您想在将来的应用程序中处理所有可能的日期,只需使用。您不会后悔:)

您在天内得到负值,这可能是因为用户输入了下一次发生的日期,即之前的任何日期

我想你应该这样算算你的一天

            String inputDateString = "19/06/2012";
            Calendar calCurr = Calendar.getInstance();//current date
            Calendar calNext = Calendar.getInstance();// for next date
            calNext.setTime(new Date(inputDateString)); // or do set Day,Month,Year like in your Question

            if(calNext.after(calCurr)) // if the next date is after current
            {
                long timeDiff = calNext.getTimeInMillis() - calCurr.getTimeInMillis(); // time of next year if today is 15 june and some one enter 16 june for next occurance
                int daysLeft = (int) (timeDiff/DateUtils.DAY_IN_MILLIS); // Days Left
            }
            else
            {
                long timeDiff = calCurr.getTimeInMillis() - calNext.getTimeInMillis();
                timeDiff = DateUtils.YEAR_IN_MILLIS - timeDiff; // time of next year if today is 15 june and some one enter 14 june for next occurance
                int daysLeft = (int) (timeDiff/DateUtils.DAY_IN_MILLIS); // Days Left
            }

乔达附议——但这不是很容易调试吗?为什么是乔达?
Calendar
类实际上非常有用,而且很容易处理,不是吗?但这对我来说并不容易调试,因为我没有要测试的输入数据。但这只能是一个无效的日期,因为再次发生的事件总是在未来366天或更短的时间内发生,或者我会冲撞基础数学吗?@MarcoW。因为这样的事情在乔达是微不足道的。我不理解“没有输入数据”来测试;你有足够的时间在4000年前得到一些东西,所以这似乎是一个很好的起点。即使你没有,我几乎可以肯定日期数学在正确重构后是可以测试的。问题是:我只知道输出(4k年前),但我不知道是哪个输入(日期字符串)产生了这个输出。我怀疑这是否相关,但是:-1469913实际上是4024年前(因为一年大约是365.25天)。我注意到这是2*2012。你有没有可能在某个地方有一个否定的年份号,用-2012而不是2012?(看看你的代码,我看不出一个明显的方法来实现这一点。)谢谢:)总的来说,有几千万个日期的测试单元是个好主意。但是由于
DateFormat.parse()
只能生成
null
或有效的
Date
对象,导致此错误的笨拙输入只能是一个日期字符串,它被错误地解释为4k年前的日期,对吗?如果日期是过去的,getNextOccurrence()似乎应该返回null,所以