反复出现的事件逻辑

我正在开发一个Groovy / Java日历类型的应用程序,允许用户输入具有开始日期和可选重复的事件。 如果它是一个反复出现的事件,它可能会重现:

  • 每月与对应于开始日期的月份日期
  • 每周一周,对应于开始日期
  • 对应于开始日期的每周的每两周一次
  • 等等

我最初计划使用Google日历API来执行所有重复逻辑,但事实certificate这是一个巨大的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时间”不会获得任何奖励)。

谢谢,唐

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

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

我知道这对你来说似乎有些过分,甚至可能不适用,但是Quartz Scheduler可以很好地处理所有这些重复和事件相关的规则。 您无法使用其调度function,只需使用Trigger类(如CronTrigger )为您计算事件日期。

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

“0 0 12 L *?” – 在每个月的最后一天中午触发事件(没有闰年等的头痛)

还处理夏令时问题。

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

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

希望这可能有用。

我对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());