improve edgecases for reminder scheduling

This commit is contained in:
Phillip Thelen 2025-01-14 14:44:52 +01:00
parent d91be2d7fe
commit 3254ce9f96
2 changed files with 298 additions and 279 deletions

View file

@ -368,12 +368,13 @@ open class Task : RealmObject, BaseMainObject, Parcelable, BaseTask {
*/
fun getNextReminderOccurrences(
remindersItem: RemindersItem?,
occurrences: Int
occurrences: Int,
today: ZonedDateTime? = null
): List<ZonedDateTime>? {
if (remindersItem == null) return null
val reminderTime = remindersItem.time?.parseToZonedDateTime() ?: return null
var dateTimeOccurenceToSchedule: ZonedDateTime
var nextOccurence: ZonedDateTime
val occurrencesList = mutableListOf<ZonedDateTime>()
// If the reminder is a todo, only schedule sole dueDate/time occurrence. Otherwise, schedule multiple occurrences in advance
@ -385,7 +386,7 @@ open class Task : RealmObject, BaseMainObject, Parcelable, BaseTask {
)
return occurrencesList
}
val now = ZonedDateTime.now().withZoneSameInstant(ZoneId.systemDefault())
val now = today ?: ZonedDateTime.now().withZoneSameInstant(ZoneId.systemDefault())
var startDate = this.startDate?.toInstant()?.atZone(ZoneId.systemDefault()) ?: return null
val weekInMonth = getWeeksOfMonth()?.firstOrNull()?.toLong()
val weekdayInMonth = startDate.dayOfWeek
@ -396,52 +397,52 @@ open class Task : RealmObject, BaseMainObject, Parcelable, BaseTask {
}
val repeatDays = this.repeat
startDate = startDate.withHour(reminderTime.hour).withMinute(reminderTime.minute)
dateTimeOccurenceToSchedule = startDate
nextOccurence = startDate
if (frequency == Frequency.MONTHLY) {
daysOfMonth?.let {
if (it.isEmpty()) return@let
dateTimeOccurenceToSchedule = dateTimeOccurenceToSchedule.withDayOfMonth(it.first())
if (dateTimeOccurenceToSchedule.isBefore(startDate)) {
dateTimeOccurenceToSchedule = dateTimeOccurenceToSchedule.plusMonths(1)
nextOccurence = nextOccurence.withDayOfMonth(it.first())
if (nextOccurence.isBefore(startDate)) {
nextOccurence = nextOccurence.plusMonths(1)
}
}
}
while (occurrencesList.size < occurrences) {
// Increment currentDate based on the frequency
dateTimeOccurenceToSchedule =
nextOccurence =
when (frequency) {
Frequency.DAILY -> {
while (dateTimeOccurenceToSchedule.isBefore(now)) {
dateTimeOccurenceToSchedule = dateTimeOccurenceToSchedule.plusDays(everyX)
while (nextOccurence.isBefore(now)) {
nextOccurence = nextOccurence.plusDays(everyX)
}
val todayWithTime = dateTimeOccurenceToSchedule
val todayWithTime = nextOccurence
.withHour(reminderTime.hour).withMinute(reminderTime.minute)
dateTimeOccurenceToSchedule = if (occurrencesList.isEmpty() && todayWithTime.isAfter(now)) {
nextOccurence = if (occurrencesList.isEmpty() && todayWithTime.isAfter(now)) {
todayWithTime
} else {
dateTimeOccurenceToSchedule.plusDays(everyX)
nextOccurence.plusDays(everyX)
.withHour(reminderTime.hour).withMinute(reminderTime.minute)
}
dateTimeOccurenceToSchedule
nextOccurence
}
Frequency.WEEKLY -> {
// Set to start date if current date is earlier
if (repeatDays?.hasAnyDaySelected() == true) {
if (dateTimeOccurenceToSchedule.isBefore(now)) {
dateTimeOccurenceToSchedule =
dateTimeOccurenceToSchedule.plusDays(1)
while (!dateTimeOccurenceToSchedule.matchesRepeatDays(repeatDays)) {
dateTimeOccurenceToSchedule =
dateTimeOccurenceToSchedule.plusDays(1)
if (nextOccurence.isBefore(now)) {
var occurenceNowWeekday = nextOccurence.minusDays((nextOccurence.dayOfWeek.value - now.dayOfWeek.value).toLong())
while (occurenceNowWeekday.isBefore(now) && occurenceNowWeekday.dayOfYear != now.dayOfYear) {
occurenceNowWeekday = occurenceNowWeekday.plusDays(everyX * 7)
}
nextOccurence = occurenceNowWeekday
while (!nextOccurence.matchesRepeatDays(repeatDays)) {
nextOccurence =
nextOccurence.plusDays(1)
}
}
while (dateTimeOccurenceToSchedule.isBefore(now)) {
dateTimeOccurenceToSchedule = dateTimeOccurenceToSchedule.plusDays(everyX * 7)
}
var nextDueDate =
dateTimeOccurenceToSchedule.withHour(reminderTime.hour)
nextOccurence.withHour(reminderTime.hour)
.withMinute(reminderTime.minute)
// If the next due date already happened for today, increment it by one day. Otherwise, it will be scheduled for today.
if (nextDueDate.isBefore(now) && occurrencesList.size == 0) {
@ -475,58 +476,58 @@ open class Task : RealmObject, BaseMainObject, Parcelable, BaseTask {
}
}
dateTimeOccurenceToSchedule = nextDueDate
nextOccurence = nextDueDate
}
// Set time to the reminder time
dateTimeOccurenceToSchedule.withHour(reminderTime.hour)
nextOccurence.withHour(reminderTime.hour)
.withMinute(reminderTime.minute)
}
Frequency.MONTHLY -> {
while (dateTimeOccurenceToSchedule.isBefore(now)) {
dateTimeOccurenceToSchedule = dateTimeOccurenceToSchedule.plusMonths(everyX)
while (nextOccurence.isBefore(now)) {
nextOccurence = nextOccurence.plusMonths(everyX)
if (weekInMonth != null && weekdayInMonth != null) {
dateTimeOccurenceToSchedule = dateTimeOccurenceToSchedule.withDayOfMonth(1)
while (dateTimeOccurenceToSchedule.dayOfWeek != weekdayInMonth) {
dateTimeOccurenceToSchedule = dateTimeOccurenceToSchedule.plusDays(1)
nextOccurence = nextOccurence.withDayOfMonth(1)
while (nextOccurence.dayOfWeek != weekdayInMonth) {
nextOccurence = nextOccurence.plusDays(1)
}
dateTimeOccurenceToSchedule = dateTimeOccurenceToSchedule.plusWeeks(weekInMonth)
nextOccurence = nextOccurence.plusWeeks(weekInMonth)
}
}
val todayWithTime = dateTimeOccurenceToSchedule
val todayWithTime = nextOccurence
.withHour(reminderTime.hour).withMinute(reminderTime.minute)
if (occurrencesList.isEmpty() && todayWithTime.isAfter(now)) {
todayWithTime
} else if (weekInMonth != null && weekdayInMonth != null) {
dateTimeOccurenceToSchedule = dateTimeOccurenceToSchedule.plusMonths(everyX)
nextOccurence = nextOccurence.plusMonths(everyX)
.withHour(reminderTime.hour).withMinute(reminderTime.minute)
.withDayOfMonth(1)
while (dateTimeOccurenceToSchedule.dayOfWeek != weekdayInMonth) {
dateTimeOccurenceToSchedule = dateTimeOccurenceToSchedule.plusDays(1)
while (nextOccurence.dayOfWeek != weekdayInMonth) {
nextOccurence = nextOccurence.plusDays(1)
}
dateTimeOccurenceToSchedule.plusWeeks(weekInMonth)
nextOccurence.plusWeeks(weekInMonth)
} else {
dateTimeOccurenceToSchedule.plusMonths(everyX)
nextOccurence.plusMonths(everyX)
.withHour(reminderTime.hour).withMinute(reminderTime.minute)
}
}
Frequency.YEARLY -> {
while (dateTimeOccurenceToSchedule.isBefore(now)) {
dateTimeOccurenceToSchedule = dateTimeOccurenceToSchedule.plusYears(everyX)
while (nextOccurence.isBefore(now)) {
nextOccurence = nextOccurence.plusYears(everyX)
}
val todayWithTime = dateTimeOccurenceToSchedule
val todayWithTime = nextOccurence
.withHour(reminderTime.hour).withMinute(reminderTime.minute)
if (occurrencesList.isEmpty() && todayWithTime.isAfter(now)) {
todayWithTime
} else {
dateTimeOccurenceToSchedule.plusYears(everyX)
nextOccurence.plusYears(everyX)
.withHour(reminderTime.hour).withMinute(reminderTime.minute)
}
}
}
occurrencesList.add(dateTimeOccurenceToSchedule)
occurrencesList.add(nextOccurence)
}
return occurrencesList

View file

@ -8,286 +8,304 @@ import io.kotest.core.spec.style.WordSpec
import io.kotest.matchers.shouldBe
import java.time.format.DateTimeFormatter
import java.util.Calendar
import java.util.Date
class TaskTest : WordSpec({
"getNextReminderOccurrences" When {
var daily = Task()
var reminder = RemindersItem()
var calendar = Calendar.getInstance()
beforeEach {
daily = Task()
daily.type = TaskType.DAILY
reminder = RemindersItem()
calendar = Calendar.getInstance()
}
"dailies repeating daily" should {
listOf(
Date(),
Calendar.getInstance().apply {
set(2025, 1, 1)
}.time,
Calendar.getInstance().apply {
set(2024, Calendar.DECEMBER, 23)
}.time
).forEach { day ->
"getNextReminderOccurrences on $day" When {
var daily = Task()
var reminder = RemindersItem()
var calendar = Calendar.getInstance()
calendar.time = day
val fakeZDT = day.toZonedDateTime()
beforeEach {
daily.frequency = Frequency.DAILY
daily = Task()
daily.type = TaskType.DAILY
reminder = RemindersItem()
calendar = Calendar.getInstance()
calendar.time = day
}
"return occurrences according to everyX = 2" {
calendar.add(Calendar.DATE, -2)
daily.startDate = calendar.time
daily.everyX = 2
calendar.add(Calendar.DATE, 4)
reminder.time = calendar.time.toZonedDateTime()?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4)
occurrences?.size shouldBe 4
occurrences?.forEach {
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
calendar.add(Calendar.DATE, 2)
"dailies repeating daily" should {
beforeEach {
daily.frequency = Frequency.DAILY
}
}
"return occurrences according to everyX = 2" {
calendar.add(Calendar.DATE, -2)
daily.startDate = calendar.time
daily.everyX = 2
calendar.add(Calendar.DATE, 4)
reminder.time = fakeZDT?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
"return occurrences according to everyX = 1" {
calendar.add(Calendar.DATE, -2)
daily.startDate = calendar.time
daily.everyX = 1
calendar.add(Calendar.DATE, 3)
reminder.time = calendar.time.toZonedDateTime()?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4)
occurrences?.size shouldBe 4
occurrences?.forEach {
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
calendar.add(Calendar.DATE, 1)
val occurrences = daily.getNextReminderOccurrences(reminder, 4, fakeZDT)
occurrences?.size shouldBe 4
occurrences?.forEach {
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
calendar.add(Calendar.DATE, 2)
}
}
}
"return occurrences according to everyX = 5" {
calendar.add(Calendar.DATE, -33)
daily.startDate = calendar.time
daily.everyX = 5
reminder.time = calendar.time.toZonedDateTime()?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
"return occurrences according to everyX = 1" {
calendar.add(Calendar.DATE, -2)
daily.startDate = calendar.time
daily.everyX = 1
calendar.add(Calendar.DATE, 3)
reminder.time = fakeZDT?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4)
occurrences?.size shouldBe 4
calendar.add(Calendar.DATE, 35)
occurrences?.forEach {
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
calendar.add(Calendar.DATE, 5)
}
}
}
"dailies repeating weekly" should {
beforeEach {
daily.frequency = Frequency.WEEKLY
}
"return occurrences if active every day" {
daily.startDate = calendar.time
daily.repeat = Days()
daily.everyX = 1
reminder.time = calendar.time.toZonedDateTime()?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4)
occurrences?.size shouldBe 4
calendar.add(Calendar.DATE, 1)
occurrences?.forEach {
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
calendar.add(Calendar.DATE, 1)
}
}
"return occurrences if active tuesdays" {
calendar.add(Calendar.DATE, -63)
daily.startDate = calendar.time
daily.repeat = Days(t = true, default = false)
daily.everyX = 1
reminder.time = calendar.time.toZonedDateTime()?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4)
occurrences?.size shouldBe 4
calendar.add(Calendar.DATE, 63)
while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.TUESDAY) {
calendar.add(Calendar.DATE, 1)
}
occurrences?.forEach {
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
calendar.add(Calendar.DATE, 7)
}
}
"return occurrences if active every second friday" {
calendar.add(Calendar.DATE, -23)
daily.startDate = calendar.time
daily.repeat = Days(f = true, default = false)
daily.everyX = 2
reminder.time = calendar.time.toZonedDateTime()?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4)
occurrences?.size shouldBe 4
while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.FRIDAY) {
calendar.add(Calendar.DATE, 1)
}
calendar.add(Calendar.DATE, 28)
occurrences?.forEach {
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
calendar.add(Calendar.DATE, 14)
}
}
"return occurrences if active multiple days a week" {
calendar.add(Calendar.DATE, -23)
daily.startDate = calendar.time
daily.repeat = Days(t = true, f = true, s = true, default = false)
daily.everyX = 1
reminder.time = calendar.time.toZonedDateTime()?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4)
occurrences?.size shouldBe 4
calendar.add(Calendar.DATE, 23)
occurrences?.forEach {
while (!calendar.matchesRepeatDays(daily.repeat)) {
val occurrences = daily.getNextReminderOccurrences(reminder, 4, fakeZDT)
occurrences?.size shouldBe 4
occurrences?.forEach {
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
calendar.add(Calendar.DATE, 1)
}
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
calendar.add(Calendar.DATE, 1)
}
"return occurrences according to everyX = 5" {
calendar.add(Calendar.DATE, -33)
daily.startDate = calendar.time
daily.everyX = 5
reminder.time = fakeZDT?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4, fakeZDT)
occurrences?.size shouldBe 4
calendar.add(Calendar.DATE, 35)
occurrences?.forEach {
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
calendar.add(Calendar.DATE, 5)
}
}
}
}
"dailies repeating weekly" should {
beforeEach {
daily.frequency = Frequency.WEEKLY
}
"return occurrences if active every day" {
daily.startDate = calendar.time
daily.repeat = Days()
daily.everyX = 1
"dailies repeating monthly" should {
beforeEach {
daily.frequency = Frequency.MONTHLY
}
reminder.time = fakeZDT?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
"return occurrences if active every 10th of the month" {
daily.startDate = calendar.time
daily.everyX = 1
daily.setDaysOfMonth(listOf(10))
reminder.time = calendar.time.toZonedDateTime()?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4)
occurrences?.size shouldBe 4
occurrences?.forEach {
while (calendar.get(Calendar.DAY_OF_MONTH) != 10) {
val occurrences = daily.getNextReminderOccurrences(reminder, 4, fakeZDT)
occurrences?.size shouldBe 4
occurrences?.forEach {
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
calendar.add(Calendar.DATE, 1)
}
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
it.year shouldBe calendar.get(Calendar.YEAR)
calendar.add(Calendar.DATE, 1)
}
}
"return occurrences if active every third month on the 5th" {
calendar.add(Calendar.MONDAY, -8)
daily.startDate = calendar.time
daily.everyX = 3
daily.setDaysOfMonth(listOf(5))
"return occurrences if active tuesdays" {
calendar.add(Calendar.DATE, -63)
daily.startDate = calendar.time
daily.repeat = Days(t = true, default = false)
daily.everyX = 1
reminder.time = calendar.time.toZonedDateTime()?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
reminder.time = fakeZDT?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4)
calendar.add(Calendar.MONTH, 9)
occurrences?.size shouldBe 4
occurrences?.forEach {
while (calendar.get(Calendar.DAY_OF_MONTH) != 5) {
calendar.add(Calendar.DATE, 1)
}
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
it.year shouldBe calendar.get(Calendar.YEAR)
calendar.add(Calendar.MONTH, 3)
}
}
"return occurrences if active every month on the third tuesday" {
calendar.set(Calendar.YEAR, 2025)
calendar.set(Calendar.MONTH, Calendar.JANUARY)
calendar.set(Calendar.DAY_OF_MONTH, 21)
daily.startDate = calendar.time
daily.everyX = 1
daily.setWeeksOfMonth(listOf(2))
reminder.time = calendar.time.toZonedDateTime()?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4)
occurrences?.size shouldBe 4
calendar.set(Calendar.DAY_OF_MONTH, 1)
occurrences?.forEach {
val occurrences = daily.getNextReminderOccurrences(reminder, 4, fakeZDT)
occurrences?.size shouldBe 4
calendar.add(Calendar.DATE, 63)
while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.TUESDAY) {
calendar.add(Calendar.DATE, 1)
}
calendar.add(Calendar.DATE, 14)
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
it.year shouldBe calendar.get(Calendar.YEAR)
calendar.add(Calendar.MONTH, 1)
calendar.set(Calendar.DAY_OF_MONTH, 1)
occurrences?.forEach {
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
calendar.add(Calendar.DATE, 7)
}
}
"return occurrences if active every second friday" {
daily.startDate = calendar.time
daily.repeat = Days(f = true, default = false)
daily.everyX = 2
reminder.time = fakeZDT?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4, fakeZDT)
occurrences?.size shouldBe 4
while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.FRIDAY) {
calendar.add(Calendar.DATE, 1)
}
occurrences?.forEach {
it.dayOfMonth shouldBe calendar.get(Calendar.DAY_OF_MONTH)
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
calendar.add(Calendar.DATE, 14)
}
}
"return occurrences if active multiple days a week" {
calendar.add(Calendar.DATE, -23)
daily.startDate = calendar.time
daily.repeat = Days(t = true, f = true, s = true, default = false)
daily.everyX = 1
reminder.time = fakeZDT?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4, fakeZDT)
occurrences?.size shouldBe 4
// One day in the future since the time for today is already too late
calendar.add(Calendar.DATE, 23)
occurrences?.forEach {
while (!calendar.matchesRepeatDays(daily.repeat)) {
calendar.add(Calendar.DATE, 1)
}
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
calendar.add(Calendar.DATE, 1)
}
}
}
"return occurrences if active every fifth month on the second wednesday" {
calendar.add(Calendar.MONTH, -8)
calendar.set(Calendar.DAY_OF_MONTH, 1)
while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.WEDNESDAY) {
calendar.add(Calendar.DATE, 1)
"dailies repeating monthly" should {
beforeEach {
daily.frequency = Frequency.MONTHLY
}
calendar.add(Calendar.DATE, 7)
daily.startDate = calendar.time
daily.everyX = 5
daily.setWeeksOfMonth(listOf(1))
reminder.time = calendar.time.toZonedDateTime()?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
"return occurrences if active every 10th of the month" {
daily.startDate = calendar.time
daily.everyX = 1
daily.setDaysOfMonth(listOf(10))
val occurrences = daily.getNextReminderOccurrences(reminder, 4)
occurrences?.size shouldBe 4
calendar.add(Calendar.MONTH, 10)
calendar.set(Calendar.DAY_OF_MONTH, 1)
occurrences?.forEach {
reminder.time = fakeZDT?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4, fakeZDT)
occurrences?.size shouldBe 4
occurrences?.forEach {
while (calendar.get(Calendar.DAY_OF_MONTH) != 10) {
calendar.add(Calendar.DATE, 1)
}
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
it.year shouldBe calendar.get(Calendar.YEAR)
calendar.add(Calendar.DATE, 1)
}
}
"return occurrences if active every third month on the 5th" {
calendar.add(Calendar.MONDAY, -8)
daily.startDate = calendar.time
daily.everyX = 3
daily.setDaysOfMonth(listOf(5))
reminder.time = fakeZDT?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4, fakeZDT)
calendar.add(Calendar.MONTH, 9)
occurrences?.size shouldBe 4
occurrences?.forEach {
while (calendar.get(Calendar.DAY_OF_MONTH) != 5) {
calendar.add(Calendar.DATE, 1)
}
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
it.year shouldBe calendar.get(Calendar.YEAR)
calendar.add(Calendar.MONTH, 3)
}
}
"return occurrences if active every month on the third tuesday" {
val storedTime = calendar.time
calendar.set(Calendar.YEAR, 2024)
calendar.set(Calendar.MONTH, Calendar.DECEMBER)
calendar.set(Calendar.DAY_OF_MONTH, 17)
daily.startDate = calendar.time
daily.everyX = 1
daily.setWeeksOfMonth(listOf(2))
calendar.time = storedTime
if (calendar.get(Calendar.DAY_OF_MONTH) > 17) {
calendar.add(Calendar.MONTH, 1)
}
reminder.time = fakeZDT?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4, fakeZDT)
occurrences?.size shouldBe 4
calendar.set(Calendar.DAY_OF_MONTH, 1)
occurrences?.forEach {
while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.TUESDAY) {
calendar.add(Calendar.DATE, 1)
}
calendar.add(Calendar.DATE, 14)
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
it.year shouldBe calendar.get(Calendar.YEAR)
calendar.add(Calendar.MONTH, 1)
calendar.set(Calendar.DAY_OF_MONTH, 1)
}
}
"return occurrences if active every fifth month on the second wednesday" {
calendar.add(Calendar.MONTH, -8)
calendar.set(Calendar.DAY_OF_MONTH, 1)
while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.WEDNESDAY) {
calendar.add(Calendar.DATE, 1)
}
calendar.add(Calendar.DATE, 7)
print(daily.startDate)
print(it)
println(calendar.time)
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
it.year shouldBe calendar.get(Calendar.YEAR)
calendar.add(Calendar.MONTH, 5)
daily.startDate = calendar.time
daily.everyX = 5
daily.setWeeksOfMonth(listOf(1))
reminder.time = fakeZDT?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4, fakeZDT)
occurrences?.size shouldBe 4
calendar.add(Calendar.MONTH, 10)
calendar.set(Calendar.DAY_OF_MONTH, 1)
occurrences?.forEach {
while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.WEDNESDAY) {
calendar.add(Calendar.DATE, 1)
}
calendar.add(Calendar.DATE, 7)
print(daily.startDate)
print(it)
println(calendar.time)
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
it.year shouldBe calendar.get(Calendar.YEAR)
calendar.add(Calendar.MONTH, 5)
calendar.set(Calendar.DAY_OF_MONTH, 1)
}
}
}
}
"dailies repeating yearly" should {
beforeEach {
daily.frequency = Frequency.YEARLY
}
"return occurrences if active every year" {
daily.startDate = calendar.time
daily.everyX = 1
reminder.time = calendar.time.toZonedDateTime()?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
"dailies repeating yearly" should {
beforeEach {
daily.frequency = Frequency.YEARLY
}
"return occurrences if active every year" {
daily.startDate = calendar.time
daily.everyX = 1
reminder.time = fakeZDT?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
val occurrences = daily.getNextReminderOccurrences(reminder, 4)
occurrences?.size shouldBe 4
calendar.add(Calendar.YEAR, 1)
occurrences?.forEach {
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
it.year shouldBe calendar.get(Calendar.YEAR)
val occurrences = daily.getNextReminderOccurrences(reminder, 4, fakeZDT)
occurrences?.size shouldBe 4
calendar.add(Calendar.YEAR, 1)
occurrences?.forEach {
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
it.year shouldBe calendar.get(Calendar.YEAR)
calendar.add(Calendar.YEAR, 1)
}
}
}
"return occurrences if active every 3 years" {
calendar.add(Calendar.YEAR, -3)
calendar.add(Calendar.DATE, 1)
daily.startDate = calendar.time
daily.everyX = 3
reminder.time = calendar.time.toZonedDateTime()?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
"return occurrences if active every 3 years" {
calendar.add(Calendar.YEAR, -3)
calendar.add(Calendar.DATE, 1)
daily.startDate = calendar.time
daily.everyX = 3
reminder.time = fakeZDT?.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
calendar.add(Calendar.YEAR, 3)
val occurrences = daily.getNextReminderOccurrences(reminder, 4)
occurrences?.size shouldBe 4
occurrences?.forEach {
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
it.year shouldBe calendar.get(Calendar.YEAR)
calendar.add(Calendar.YEAR, 3)
val occurrences = daily.getNextReminderOccurrences(reminder, 4, fakeZDT)
occurrences?.size shouldBe 4
occurrences?.forEach {
it.dayOfYear shouldBe calendar.get(Calendar.DAY_OF_YEAR)
it.year shouldBe calendar.get(Calendar.YEAR)
calendar.add(Calendar.YEAR, 3)
}
}
}
}