【问题标题】:How to calculate number of event occurrences with Joda Time?如何使用 Joda Time 计算事件发生的次数?
【发布时间】:2016-08-31 06:50:51
【问题描述】:

给定一个示例事件重复计划,其定义如下:

开始时间:2016年6月6日星期一09:00H 结束时间:2016年8月29日星期一10:00H 时间:双周

这意味着,每 2 周的星期一 09:00H,直到 2016 年 8 月 29 日。但是 endTime 是在 8 月 29 日星期一,正好是新一周的开始,但应该包含在时间表中(因为它在 10:00H 结束)。所以我预计该事件会发生 7 次。

相反,如果 endTime 是 8 月 29 日 08:00H,那么我预计该事件只会发生 6 次。

现在,我使用 Joda Time 计算出现次数,如下所示: Weeks.weeksBetween(startTime, endTime).dividedBy(multiplier).getWeeks()

当然,这给了我 6 次而不是 7 次,因为持续时间实际上只有 12 周,最后一次出现是在上周之后的星期一(在星期日结束)。所以这不算完整的一周。任何其他类型的时间表也是如此 - 月、日、年等。

如何可靠地计算两次之间事件的发生次数?

谢谢

【问题讨论】:

  • 使用石英调度器,你可以这样做nextSync = trigger.getNextFireTime();
  • @MasterAzazel 理想情况下,我不希望添加另一个库依赖项

标签: java jodatime


【解决方案1】:

使用伪代码,因为我对尤达不太熟悉:

  1. 计数器 = 1,someDate = 开始时间,增量 = 两周
  2. 循环:someDate = someDate + 增量
  3. if someDate then counter++ else break loop

另外,对于不喜欢循环的人:

  1. 计算开始日期和结束日期之间的确切小时数
  2. 计算 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;

【讨论】:

  • 我认为这可行。谢谢鬼猫。我想我是在无意识地试图避免循环,因为我必须在循环中分别处理每种类型的时间段(天、周、月、年等),同时避免时区陷阱。
  • 循环的问题在于你得到的计算时间取决于间隔的长度。由于这应该是一个简单的计算,我们都可以在同一时间用笔和纸进行 100 年的时间和 2 周的时间,我认为循环不是一个好主意。
  • 加入一些其他的非循环方法。
  • 啊,但这种方法不适用于数月,只能数周,并且在夏令时边界上也会失败。
  • @RealSkeptic 好吧,这里是一个免费网站。随时添加您更好的答案;-) 我不介意支持它。
【解决方案2】:

刚刚在 Joda 跟随 GhostCat。通过从日期时间中删除“H”来获取一些快捷方式。我确信它可以解决。谢谢鬼猫 :)

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

    }

}

【讨论】:

  • 现在尝试其他 OP 示例,例如 08:00 的结束时间,以及夏令时更改的时间段。
【解决方案3】:

在我看来,在所有情况下,您只需要在计算结果中加 1,除非结束日期恰好在同一时间间隔后的同一小时(除非您计算这是一个事件)。

╔══════════════════╤══════════════════╤═══════════ ═══╤══════════════╤════════════╗ ║ 开始日期 │ 结束日期 │ 结果 │ 结果 │ 预期 ║ ║ │ │ weekBetween │ 分割(2) │ 结果 ║ ╠══════════════════╪══════════════════╪═══════════ ═══╪══════════════╪════════════╣ ║ 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 或 7 ║ ║ │ │ │ 由你决定║ ╟──────────────────┼──────────────────┼──────────── ────┼──────────────┼────────────╢ ║ 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 ║ ╚══════════════════╧══════════════════╧═══════════ ═══╧══════════════╧════════════╝

采用第一个组合 - 结束日期稍晚于假定的最后一次出现:

开始 ──╂──────┼──────┼──────┼──────┼──────┼──────┼─┰╴ 结尾 1 2 3 4 5 6

Joda 重视的是差距。你要计算的是蜱虫。而且总是比间隔多一个。

在第二种情况下,结束在下一次出现之前一点点:

开始 ──╂──────┼──────┼──────┼──────┼──────┼──────┰┼──╴ 结尾 1 2 3 4 5

这次 Joda 说在开始和结束之间有 5 个完整的“句点”,但您要计算的是这些句点的结束,所以它总是多一个。

您可能想要决定不添加一个的唯一情况是,如果结尾恰好在下一次出现时落下,在这种情况下,您可能希望排除它,因为您认为它“已经结束”。

如果是这样,您只需为其添加一个测试:

Weeks weeks = Weeks.weeksBetween(startDateTime, endDateTime);
int occurrences = weeks.dividedBy(2).getWeeks();
if ( ! startDateTime.plus(weeks).equals(endDateTime) ) {
    occurrences++;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-14
    • 1970-01-01
    • 2011-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-04
    相关资源
    最近更新 更多