From 651d4a8969b81f7e1331fee67cd518dd55cada9f Mon Sep 17 00:00:00 2001 From: mmateu <45851518+mmateu@users.noreply.github.com> Date: Sun, 26 May 2024 01:07:00 +0200 Subject: [PATCH 1/2] Synchronize date output between calev-core and systemd-analyze * Fixes #553 --- .../scala/com/github/eikek/calev/Value.scala | 2 +- .../eikek/calev/internal/DefaultTrigger.scala | 44 ++++++++++---- .../com/github/eikek/calev/CalEventTest.scala | 60 +++++++++++++++++++ 3 files changed, 93 insertions(+), 13 deletions(-) diff --git a/modules/core/src/main/scala/com/github/eikek/calev/Value.scala b/modules/core/src/main/scala/com/github/eikek/calev/Value.scala index 0a55abe..1048e37 100644 --- a/modules/core/src/main/scala/com/github/eikek/calev/Value.scala +++ b/modules/core/src/main/scala/com/github/eikek/calev/Value.scala @@ -52,7 +52,7 @@ object Value { def contains(n: Int): Boolean = n >= start && n <= end && - (rep == None || Single(start, rep).contains(n)) + (rep.isEmpty || Single(start, rep).contains(n)) def asString: String = rep match { diff --git a/modules/core/src/main/scala/com/github/eikek/calev/internal/DefaultTrigger.scala b/modules/core/src/main/scala/com/github/eikek/calev/internal/DefaultTrigger.scala index 20cef93..6b8de17 100644 --- a/modules/core/src/main/scala/com/github/eikek/calev/internal/DefaultTrigger.scala +++ b/modules/core/src/main/scala/com/github/eikek/calev/internal/DefaultTrigger.scala @@ -1,7 +1,6 @@ package com.github.eikek.calev.internal import java.time._ - import com.github.eikek.calev._ /** Generate the next date-time that matches a calendar event and is closest but after a @@ -72,20 +71,38 @@ object DefaultTrigger extends Trigger { } case _ => - val (ref, comp) = calc.components - val prevFlag = calc.flag + val (ref: Int, comp: Component) = calc.components + val prevFlag: Flag = calc.flag - if (comp.contains(ref) && prevFlag != Flag.First) + if (comp.contains(ref) && prevFlag != Flag.First) { run(calc.copy(flag = Flag.Exact).nextPos) - else - comp.findFirst(ref + 1, calc.maxValue) match { + } else + comp.findFirst(min = ref + 1, max = calc.maxValue) match { case Some(v) => run(calc.set(v, Flag.Next).atStartBelowCurrent.nextPos) case None => - val n = - comp.findFirst(calc.minValue, calc.maxValue).getOrElse(calc.minValue) - run(calc.set(n, Flag.First).nextPos) + if (calc.isMonth) { + comp.findFirst(min = calc.minValue, max = calc.maxValue) match { + case Some(v) => + run(calc.set(v, Flag.First).atStartBelowCurrent.nextPos) + case None => + val pos = calc + .set( + comp + .findFirst(calc.minValue, calc.maxValue) + .getOrElse(calc.minValue), + Flag.First + ) + .nextPos + run(pos) + } + } else { + val n = + comp.findFirst(calc.minValue, calc.maxValue).getOrElse(calc.minValue) + run(calc.set(n, Flag.First).nextPos) + } + } } @@ -112,7 +129,7 @@ object DefaultTrigger extends Trigger { } case class DateTime(date: Date, time: Time) { - def toLocalDateTime = + def toLocalDateTime: LocalDateTime = LocalDateTime.of(date.toLocalDate, time.toLocalTime) def toZonedDateTime(zone: ZoneId): ZonedDateTime = @@ -171,7 +188,7 @@ object DefaultTrigger extends Trigger { } case class Calc(flag: Flag, date: DateTime, pos: DateTime.Pos, ce: CalEvent) { - def components = + def components: (Int, Component) = pos match { case DateTime.Pos.Sec => (date.time.second, ce.time.seconds) @@ -228,7 +245,7 @@ object DefaultTrigger extends Trigger { def set(value: Int, flag: Flag): Calc = set(value, pos).copy(flag = flag) - private def set(value: Int, pos: DateTime.Pos): Calc = + def set(value: Int, pos: DateTime.Pos): Calc = pos match { case DateTime.Pos.Sec => copy(date = date.copy(time = date.time.copy(second = value))) @@ -243,6 +260,9 @@ object DefaultTrigger extends Trigger { case DateTime.Pos.Year => copy(date = date.copy(date = date.date.copy(year = value))) } + + def isMonth: Boolean = + pos == DateTime.Pos.Month } object Calc { diff --git a/modules/core/src/test/scala/com/github/eikek/calev/CalEventTest.scala b/modules/core/src/test/scala/com/github/eikek/calev/CalEventTest.scala index 9b8ff95..7085af2 100644 --- a/modules/core/src/test/scala/com/github/eikek/calev/CalEventTest.scala +++ b/modules/core/src/test/scala/com/github/eikek/calev/CalEventTest.scala @@ -106,6 +106,66 @@ class CalEventTest extends FunSuite { assertEquals(next, ZonedDateTime.parse("2024-02-01T00:00+01:00")) } + test( + "expression for the daily run on some month with potential next run on next year should start at the beginning of the month next year" + ) { + val expression = CalEvent.unsafe("*-2-* 10:00:00") + + val next = expression.nextElapse(LocalDateTime.parse("2024-03-20T10:01:00")) + assertEquals( + next.get, + LocalDateTime.parse("2025-02-01T10:00") + ) + } + + test( + "expression for the daily run on some month with ref date before (1 month before) aforementioned month should start at the beginning of the month of the same year" + ) { + val expression = CalEvent.unsafe("*-2-* 10:00:00") + + val next = expression.nextElapse(LocalDateTime.parse("2024-01-20T10:01:00")) + assertEquals( + next.get, + LocalDateTime.parse("2024-02-01T10:00") + ) + } + + test( + "expression for the daily run on some month with ref date before (few months before) aforementioned month should start at the beginning of the month of the same year" + ) { + val expression = CalEvent.unsafe("*-4-* 10:00:00") + + val next = expression.nextElapse(LocalDateTime.parse("2024-01-20T10:01:00")) + assertEquals( + next.get, + LocalDateTime.parse("2024-04-01T10:00") + ) + } + + test( + "expression for the daily run on some month with ref date before (on the same month) aforementioned month should start at the beginning of the month of the same year" + ) { + val expression = CalEvent.unsafe("*-4-25 10:00:00") + + val next = expression.nextElapse(LocalDateTime.parse("2024-04-20T10:01:00")) + assertEquals( + next.get, + LocalDateTime.parse("2024-04-25T10:00") + ) + } + + test( + "expression for the monthly run on some month with potential next run on next year should start at the beginning of the month next year" + ) { + val expression = CalEvent.unsafe("*-4-25 10:00:00") + + val next = expression.nextElapse(LocalDateTime.parse("2024-08-20T10:01:00")) + assertEquals( + next.get, + LocalDateTime.parse("2025-04-25T10:00") + ) + } + private def zdt(y: Int, month: Int, d: Int, h: Int, min: Int, sec: Int): ZonedDateTime = ZonedDateTime.of(LocalDate.of(y, month, d), LocalTime.of(h, min, sec), ZoneOffset.UTC) } From 77e8bedd2ec581bc372b9c024bf3586a3e73b666 Mon Sep 17 00:00:00 2001 From: mmateu <45851518+mmateu@users.noreply.github.com> Date: Sun, 26 May 2024 21:57:35 +0200 Subject: [PATCH 2/2] sbt lint --- .../scala/com/github/eikek/calev/internal/DefaultTrigger.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/core/src/main/scala/com/github/eikek/calev/internal/DefaultTrigger.scala b/modules/core/src/main/scala/com/github/eikek/calev/internal/DefaultTrigger.scala index 6b8de17..ff2caef 100644 --- a/modules/core/src/main/scala/com/github/eikek/calev/internal/DefaultTrigger.scala +++ b/modules/core/src/main/scala/com/github/eikek/calev/internal/DefaultTrigger.scala @@ -1,6 +1,7 @@ package com.github.eikek.calev.internal import java.time._ + import com.github.eikek.calev._ /** Generate the next date-time that matches a calendar event and is closest but after a