android - -1469913 天计算 Android 中重复发生的事件

标签 android date calendar gregorian-calendar

对于重复发生的事件,我想在我的 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 年的数据?我无法解释这种行为。

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

编辑: 因为它可能有帮助:使用 DateFormat.getDateInstance().format()< 时,错误的日期年份始终输出为 1/,例如1 月 3 日。然而,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。为什么?

最佳答案

处理日期时,很难在用户实际遇到这些隐蔽错误之前找出它们。在许多情况下,值得您花时间进行一个小的单元测试,在机器中抛出几千万个日期,看看是否会弹出任何极端的答案。

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

编辑:如果用户给出非常高的输入值,那么当您在 getDaysLeft() 中将结果转换为整数时,可能会出现数字溢出。保持它尽可能长。甚至更好:只接受合理的输入值,如果用户输入 20120 年或类似的内容,则警告用户 :)

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

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

EDIT4:请记住,javas 日历类很糟糕。此代码 fragment 表明错误实际上是在 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

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

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

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

关于android - -1469913 天计算 Android 中重复发生的事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10996881/

相关文章:

android - android中有没有订阅支付api,用户必须每两个月支付一次,才能访问应用程序服务?

java - 从其他类调用 MainActivity 的方法

php - 显示错误数据的 mysql 代码问题

jquery - 完整日历 jQuery!点击只能选择一个时段吗?

java - 如何在java中获取一年中每个月的第一个工作日

android - 如何在 View 底部绘制圆段[android]?

android - returnKeyLabel 与 returnKeyType react native ?

mysql - DATE_ADD 和 INTERVAL 函数中的语法错误

java - 在 Jform(GUI) 的 3 个组合框中显示来自 java DB 的日期字段

Java 日期比较差一天