如何使用 Joda Time 计算事件发生次数?
How to calculate number of event occurrences with Joda Time?
给定一个示例事件重现计划,其定义如下:
StartTime: Monday, 2016-June-06 09:00H
EndTime: Monday, 2016-August-29 10:00H
Period: Bi-weekly
这意味着,每 2 周的星期一 09:00H,直到 2016 年 8 月 29 日。但是结束时间是 8 月 29 日星期一,也就是新一周的开始,但应该是包含在时间表中(因为它在 10:00H 结束)。所以我预计该事件会发生 7 次。
相反,如果结束时间是 8 月 29 日 08:00H,那么我预计该事件只会发生 6 次。
现在,我使用 Joda Time 计算出现次数:
Weeks.weeksBetween(startTime, endTime).dividedBy(multiplier).getWeeks()
当然,这只给了我 6 次而不是 7 次,因为持续时间实际上只有 12 周,最后一次出现是在上周之后的星期一(星期日结束)。所以这不算整周。这同样适用于任何其他类型的时间表 - 月、日、年等。
我怎样才能可靠地计算两次之间事件的发生次数?
谢谢
使用伪代码,因为我对 Yoda 不太熟悉我是:
- counter = 1, someDate = 开始时间, increment = 两周
- 循环: someDate = someDate + increment
- if someDate < 结束时间: then counter++ else break loop
或者,对于不喜欢循环的人:
- 计算开始日期和结束日期之间的确切小时数
- 算出 24 * 7 * 2 适合上述小时数的频率
使用 JodaTime 库的示例代码:
int multiple = 2; //or whatever periodicity is needed
ReadablePeriod jodaPeriod;
switch (mPeriodType){
case DAY:
jodaPeriod = Days.days(multiple);
break;
case WEEK:
jodaPeriod = Weeks.weeks(multiple);
break;
case MONTH:
jodaPeriod = Months.months(multiple);
break;
case YEAR:
jodaPeriod = Years.years(multiple);
break;
default:
jodaPeriod = Months.months(multiple);
}
int count = 0;
LocalDateTime startTime = new LocalDateTime(mPeriodStart.getTime());
while (startTime.toDateTime().getMillis() < mPeriodEnd.getTime()){
++count;
startTime = startTime.plus(jodaPeriod);
}
return count;
刚刚在 Joda 关注 GhostCat。通过从日期时间中删除 "H" 来采取一些快捷方式。我相信它可以解决。谢谢 Ghostcat :)
import java.util.Locale;
import org.joda.time.DateTime;
import org.joda.time.Hours;
import org.joda.time.Period;
import org.joda.time.Weeks;
import org.joda.time.format.DateTimeFormat;
public class TestDateJoda {
public static void main(String[] args) {
String startTime = "Monday, 2016-June-06 09:00";
String endTime = "Monday, 2016-August-29 10:00";
DateTime startDateTime = DateTimeFormat.forPattern("E, yyyy-MMM-dd HH:mm").withLocale(Locale.ENGLISH)
.parseDateTime(startTime);
DateTime endDateTime = DateTimeFormat.forPattern("E, yyyy-MMM-dd HH:mm").withLocale(Locale.ENGLISH)
.parseDateTime(endTime);
System.out.println(startDateTime);
System.out.println(endDateTime);
Period period = new Period(startDateTime,endDateTime);
Hours hours = Hours.hoursBetween(startDateTime, endDateTime);
Weeks weeks = Weeks.weeksBetween(startDateTime, endDateTime);
//starting first week add 1 follow ghost cat
System.out.println(hours.getHours()/(24*7*2) + 1);
System.out.println(weeks.getWeeks()/(2) + 1);
}
}
在我看来,您只需要在所有情况下将计算结果加 1,除非结束日期 正好 在同一时间之后的同一时间间隔(除非您将其计算为一个事件)。
╔══════════════════╤══════════════════╤══════════════╤══════════════╤════════════╗
║ Start Date │ End Date │ result of │ result of │ Expected ║
║ │ │ weeksBetween │ dividedBy(2) │ result ║
╠══════════════════╪══════════════════╪══════════════╪══════════════╪════════════╣
║ 2016-06-07 09:00 │ 2016-08-30 10:00 │ 12 │ 6 │ 7 ║
╟──────────────────┼──────────────────┼──────────────┼──────────────┼────────────╢
║ 2016-06-07 09:00 │ 2016-08-30 08:00 │ 11 │ 5 │ 6 ║
╟──────────────────┼──────────────────┼──────────────┼──────────────┼────────────╢
║ 2016-06-07 09:00 │ 2016-08-30 09:00 │ 12 │ 6 │ 6 or 7 ║
║ │ │ │ │ you decide ║
╟──────────────────┼──────────────────┼──────────────┼──────────────┼────────────╢
║ 2016-06-07 09:00 │ 2016-08-23 10:00 │ 11 │ 5 │ 6 ║
╟──────────────────┼──────────────────┼──────────────┼──────────────┼────────────╢
║ 2016-06-07 09:00 │ 2016-08-23 08:00 │ 10 │ 5 │ 6 ║
╟──────────────────┼──────────────────┼──────────────┼──────────────┼────────────╢
║ 2016-06-07 09:00 │ 2016-08-23 09:00 │ 11 │ 5 │ 6 ║
╚══════════════════╧══════════════════╧══════════════╧══════════════╧════════════╝
采用第一个组合 - 结束日期略晚于假设的最后一次出现:
Start
──╂──────┼──────┼──────┼──────┼──────┼──────┼─┰╴
end
1 2 3 4 5 6
Joda 计算的是 差距。您要计算的是滴答声。而且跳动总是比跳空多一个。
在第二种情况下,结尾比下一次出现早一点:
Start
──╂──────┼──────┼──────┼──────┼──────┼─────┰┼─╴
end
1 2 3 4 5
这次Joda说开始和结束之间有5个整"periods",但是你要算的是那些ends,所以永远是一个。
您可能想要决定不添加一个的唯一情况是,如果结尾恰好下一次,在这种情况下,您可能希望在考虑时将其排除"already ended".
如果是这样,您只需为其添加一个测试:
Weeks weeks = Weeks.weeksBetween(startDateTime, endDateTime);
int occurrences = weeks.dividedBy(2).getWeeks();
if ( ! startDateTime.plus(weeks).equals(endDateTime) ) {
occurrences++;
}
给定一个示例事件重现计划,其定义如下:
StartTime: Monday, 2016-June-06 09:00H EndTime: Monday, 2016-August-29 10:00H Period: Bi-weekly
这意味着,每 2 周的星期一 09:00H,直到 2016 年 8 月 29 日。但是结束时间是 8 月 29 日星期一,也就是新一周的开始,但应该是包含在时间表中(因为它在 10:00H 结束)。所以我预计该事件会发生 7 次。
相反,如果结束时间是 8 月 29 日 08:00H,那么我预计该事件只会发生 6 次。
现在,我使用 Joda Time 计算出现次数:
Weeks.weeksBetween(startTime, endTime).dividedBy(multiplier).getWeeks()
当然,这只给了我 6 次而不是 7 次,因为持续时间实际上只有 12 周,最后一次出现是在上周之后的星期一(星期日结束)。所以这不算整周。这同样适用于任何其他类型的时间表 - 月、日、年等。
我怎样才能可靠地计算两次之间事件的发生次数?
谢谢
使用伪代码,因为我对 Yoda 不太熟悉我是:
- counter = 1, someDate = 开始时间, increment = 两周
- 循环: someDate = someDate + increment
- if someDate < 结束时间: then counter++ else break loop
或者,对于不喜欢循环的人:
- 计算开始日期和结束日期之间的确切小时数
- 算出 24 * 7 * 2 适合上述小时数的频率
使用 JodaTime 库的示例代码:
int multiple = 2; //or whatever periodicity is needed
ReadablePeriod jodaPeriod;
switch (mPeriodType){
case DAY:
jodaPeriod = Days.days(multiple);
break;
case WEEK:
jodaPeriod = Weeks.weeks(multiple);
break;
case MONTH:
jodaPeriod = Months.months(multiple);
break;
case YEAR:
jodaPeriod = Years.years(multiple);
break;
default:
jodaPeriod = Months.months(multiple);
}
int count = 0;
LocalDateTime startTime = new LocalDateTime(mPeriodStart.getTime());
while (startTime.toDateTime().getMillis() < mPeriodEnd.getTime()){
++count;
startTime = startTime.plus(jodaPeriod);
}
return count;
刚刚在 Joda 关注 GhostCat。通过从日期时间中删除 "H" 来采取一些快捷方式。我相信它可以解决。谢谢 Ghostcat :)
import java.util.Locale;
import org.joda.time.DateTime;
import org.joda.time.Hours;
import org.joda.time.Period;
import org.joda.time.Weeks;
import org.joda.time.format.DateTimeFormat;
public class TestDateJoda {
public static void main(String[] args) {
String startTime = "Monday, 2016-June-06 09:00";
String endTime = "Monday, 2016-August-29 10:00";
DateTime startDateTime = DateTimeFormat.forPattern("E, yyyy-MMM-dd HH:mm").withLocale(Locale.ENGLISH)
.parseDateTime(startTime);
DateTime endDateTime = DateTimeFormat.forPattern("E, yyyy-MMM-dd HH:mm").withLocale(Locale.ENGLISH)
.parseDateTime(endTime);
System.out.println(startDateTime);
System.out.println(endDateTime);
Period period = new Period(startDateTime,endDateTime);
Hours hours = Hours.hoursBetween(startDateTime, endDateTime);
Weeks weeks = Weeks.weeksBetween(startDateTime, endDateTime);
//starting first week add 1 follow ghost cat
System.out.println(hours.getHours()/(24*7*2) + 1);
System.out.println(weeks.getWeeks()/(2) + 1);
}
}
在我看来,您只需要在所有情况下将计算结果加 1,除非结束日期 正好 在同一时间之后的同一时间间隔(除非您将其计算为一个事件)。
╔══════════════════╤══════════════════╤══════════════╤══════════════╤════════════╗ ║ Start Date │ End Date │ result of │ result of │ Expected ║ ║ │ │ weeksBetween │ dividedBy(2) │ result ║ ╠══════════════════╪══════════════════╪══════════════╪══════════════╪════════════╣ ║ 2016-06-07 09:00 │ 2016-08-30 10:00 │ 12 │ 6 │ 7 ║ ╟──────────────────┼──────────────────┼──────────────┼──────────────┼────────────╢ ║ 2016-06-07 09:00 │ 2016-08-30 08:00 │ 11 │ 5 │ 6 ║ ╟──────────────────┼──────────────────┼──────────────┼──────────────┼────────────╢ ║ 2016-06-07 09:00 │ 2016-08-30 09:00 │ 12 │ 6 │ 6 or 7 ║ ║ │ │ │ │ you decide ║ ╟──────────────────┼──────────────────┼──────────────┼──────────────┼────────────╢ ║ 2016-06-07 09:00 │ 2016-08-23 10:00 │ 11 │ 5 │ 6 ║ ╟──────────────────┼──────────────────┼──────────────┼──────────────┼────────────╢ ║ 2016-06-07 09:00 │ 2016-08-23 08:00 │ 10 │ 5 │ 6 ║ ╟──────────────────┼──────────────────┼──────────────┼──────────────┼────────────╢ ║ 2016-06-07 09:00 │ 2016-08-23 09:00 │ 11 │ 5 │ 6 ║ ╚══════════════════╧══════════════════╧══════════════╧══════════════╧════════════╝
采用第一个组合 - 结束日期略晚于假设的最后一次出现:
Start ──╂──────┼──────┼──────┼──────┼──────┼──────┼─┰╴ end 1 2 3 4 5 6
Joda 计算的是 差距。您要计算的是滴答声。而且跳动总是比跳空多一个。
在第二种情况下,结尾比下一次出现早一点:
Start ──╂──────┼──────┼──────┼──────┼──────┼─────┰┼─╴ end 1 2 3 4 5
这次Joda说开始和结束之间有5个整"periods",但是你要算的是那些ends,所以永远是一个。
您可能想要决定不添加一个的唯一情况是,如果结尾恰好下一次,在这种情况下,您可能希望在考虑时将其排除"already ended".
如果是这样,您只需为其添加一个测试:
Weeks weeks = Weeks.weeksBetween(startDateTime, endDateTime);
int occurrences = weeks.dividedBy(2).getWeeks();
if ( ! startDateTime.plus(weeks).equals(endDateTime) ) {
occurrences++;
}