【问题标题】:recurring event logic重复事件逻辑
【发布时间】:2010-10-20 11:58:15
【问题描述】:

我正在开发一个 Groovy/Java 日历类型的应用程序,该应用程序允许用户输入带有开始日期和可选重复周期的事件。如果是经常性事件,它可能会再次发生:

  • 每月在与开始日期对应的月份的某个日期
  • 每周在与开始日期相对应的一周中的某一天
  • 每 2 周对应开始日期的一周中的某一天

我最初计划使用 Google 日历 API 来执行所有重复逻辑,但事实证明它是一个巨大的 PITA,如果有人关心,我会进一步讨论原因。

所以现在,我决定推出自己的解决方案。给定一个日期,我想知道在这个日期是否发生了重复性事件。我的逻辑(伪代码)如下:

public boolean occursOnDate(def date, def event) {

  def firstDate = event.startDate

  if (firstDate > date) {
    return false;

  } else if (event.isWeekly()) {
    return event.dayOfWeek() == date.dayOfWeek()

  } else if (event.isMonthly()) {
    return event.dayOfMonth() == date.dayOfMonth()

  } else {
    // At this point we know the event occurs every X weeks where X > 1
    // Increment firstDate by adding X weeks to it as many times as possible, without
    // going past date
    return firstDate == date
  }  
}

这个逻辑看起来很合理,但当您考虑到所有奇怪的边缘情况(例如,如何处理 2 月第一次发生在 1 月 31 日的每月重复事件)时,实际上会付出相当多的努力来实现。

有没有图书馆可以帮助我实现这个?一些细节将不胜感激(例如,“使用 Joda 时间”不会获得积分)。

谢谢, 唐

【问题讨论】:

标签: java groovy calendar


【解决方案1】:

RFC-2445(基本上是 iCal 规范)中相当明确地规定了您想要的那种重复规则。获得这个正确的细节可能非常复杂。我建议为此使用 google-rfc-2445 库,或者使用该规范的其他实现,例如 iCal4J

【讨论】:

    【解决方案2】:

    我对 Groovy 一无所知,我的第一个建议是 Joda,但你知道。

    我知道这对你来说可能有点过头了,甚至可能不适用,但Quartz Scheduler 可以很好地处理所有这些重复发生和事件相关的规则。您不能使用它的调度功能,而只能使用 Trigger 类(如 CronTrigger)为您计算事件日期。

    上面的 CronTrigger 链接显示了一些可用于处理事件的表达式示例,例如这种特别令人讨厌的情况:

    "0 0 12 L * ?" - 在每个月的最后一天中午触发一个事件(闰年等不会让人头疼)

    夏令时问题也得到处理。

    至于代码,使用所需的重复创建触发器,然后您可以提取所有您希望的触发时间:

    Date firstFireTime = myTrigger.getNextFireTime();
    ...
    while (...) {
        Date nextFireTime = myTrigger.getFireTimeAfter(previousFireTime);
        ...
    }
    

    希望这能有用。

    【讨论】:

    • 如果您有更多关于如何使用 Joda/Quartz 来实现我的目标的具体信息,我很想听听。
    【解决方案3】:

    我对 Groovy 库不是很熟悉,但由于 Groovy 是在 JVM 上运行的,所以我想您应该也可以使用 Java / Scala 库。

    您需要的是像 Lamma(http://lamma.io) 这样的专业日程生成库,而不是像 Joda 这样的通用日期时间库。

        // monthly on a date of the month that corresponds to the start date
        // output: [Date(2014,6,10), Date(2014,7,10), Date(2014,8,10), Date(2014,9,10), Date(2014,10,10)]
        System.out.println(Dates.from(2014, 6, 10).to(2014, 10, 10).byMonth().build());
    
        // weekly on a day of the week of that corresponds to the start date
        // output: [Date(2014,6,10), Date(2014,6,17), Date(2014,6,24), Date(2014,7,1), Date(2014,7,8)]
        System.out.println(Dates.from(2014, 6, 10).to(2014, 7, 10).byWeek().build());
    
        // every 2 weeks on a day of the week of that corresponds to the start date
        // output: [Date(2014,6,10), Date(2014,6,24), Date(2014,7,8)]
        System.out.println(Dates.from(2014, 6, 10).to(2014, 7, 10).byWeeks(2).build());
    
        // edge cases are handled properly, for example, leap day
        // output: [Date(2012,2,29), Date(2013,2,28), Date(2014,2,28), Date(2015,2,28), Date(2016,2,29)]
        System.out.println(Dates.from(2012, 2, 29).to(2016, 2, 29).byYear().build());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-12
      • 2010-10-09
      • 2015-05-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多