-计算Android中重复发生的事件时还剩1469913天
对于重复发生的事件,我想在我的Android日历应用程序中显示距离下一次事件的剩余天数 示例:-计算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 {
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,所以