2

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

例子:

Today: 2012-06-12
Reoccurring event: 19th June
=> 13 days left

为了实现这一点,我将第一次出现保存在数据类型的对象中Calendar

private Calendar cal;
...
cal = new GregorianCalendar();
cal.set(Calendar.YEAR, USER_INPUT_YEAR);
cal.set(Calendar.MONTH, USER_INPUT_MONTH);
...

为了计算剩下的天数,我使用这个函数:

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();
    }
}

顺便说一句,要获得初始日期,我希望找到一个 YYYY-MM-DD 值并像这样解析它:

(new SimpleDateFormat("yyyy-MM-dd")).parse(INPUT_DATE_STRING)

这在大多数情况下都可以正常工作,但一些用户报告说他们看到了诸如-1469913“剩余天数”之类的数字。这怎么可能发生?

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

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

我希望你能帮助我。非常感谢您!

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

编辑#2:我发现一个日期1--22199-1,比如产生“还剩 4k 年”的输出。尽管如此,它还是被成功解析了(new SimpleDateFormat("yyyy-MM-dd")).parse()。同样,-1-1-1-91-被正确解析为Jan 1, 2.

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

4

2 回答 2

1

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

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

编辑:如果用户提供了非常高的输入值,那么当您将结果放入getDaysLeft(). 只要保持它很长。甚至更好:只接受合理的输入值,如果用户输入了 20120 年或类似的东西,则警告用户 :)

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

EDIT3:回应您的第三次编辑:记住,DateCalendar使用Unix time。这意味着用零表示的时间是 1970 年。1970 年之前的所有内容都将用负值表示。

EDIT4: 请记住,javas 日历类很烂。此代码片段表明错误实际上是在日历类中:

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

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

Calendar next = new GregorianCalendar();
next.set(Calendar.YEAR, -2012);
System.out.println(next.get(Calendar.YEAR));

我只是建议您不要在输入中允许这样的极端值。确定一个可接受的跨度,如果值超出这些边界,则给出错误消息。如果您想在其他应用程序中处理所有可能的日期,只需使用joda time。你不会后悔的:)

于 2012-06-12T13:31:13.910 回答
0

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

我认为你应该这样计算你的 daysLeft,

            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
            }
于 2012-06-15T07:22:14.033 回答