Here’s another option using org.joda.time.Interval, but it doesn’t quite fit into the current DP. Intervals are half-open (start inclusive, end exclusive). I’ve added some other examples in too, for people who use Astro.
import java.util.LinkedHashMap
rule "Mode: Update Mode"
when
System started
or
Time cron "0 0 7 * * ?"
or
Time cron "0 0 9 * * ?"
or
Time cron "0 55 17 * * ?"
or
Time cron "0 0 21 * * ?"
then
val LinkedHashMap<String,Interval> modeIntervals = newLinkedHashMap(
"Morning" -> new Interval(now.withTime(7,0,0,0),now.withTime(9,0,0,0)),
"Day" -> new Interval(now.withTime(9,0,0,0),now.withTime(17,55,0,0)),
//"Day" -> new Interval(now.withTime(9,0,0,0),new DateTime((nauticDuskStart.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)),
//"Day" -> new Interval(new Duration(java.util.concurrent.TimeUnit.HOURS.toMillis(5)),new DateTime((nauticDuskStart.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)),
"Evening" -> new Interval(now.withTime(17,55,0,0),now.withTime(21,0,0,0))
//"Evening" -> new Interval(new DateTime((nauticDuskStart.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli),now.withTime(21,0,0,0))
)
var String newMode = "Night"// it was easiest to do it this way, since this Mode wraps around midnight
for (mode : modeIntervals.keySet) {
if (modeIntervals.get(mode).contains(now)) {
newMode = mode
}
logDebug("Rules", "Update Mode: interval=[{}], name=[{}]",modeIntervals.get(mode),mode)
}
if (newMode != Mode.state.toString) {
Mode.sendCommand(newMode)
logDebug("Rules", "Update Mode: Mode changed to [{}]",newMode)
}
end
I use something similar for audio alerts. An Interval can be Interval(Instant, Instant), or Interval(Duration, Instant). When our Mode changes, I play a status alert which includes these…
val String tempTotalSolarEclipse = if (new Interval(new Duration(java.util.concurrent.TimeUnit.DAYS.toMillis(7)),new DateTime((Sun_Eclipse_Total.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)).contains(now)) "\nSpecial Event! There is a Total Solar Eclipse this week on " + Sun_Eclipse_Total.state.format("%1$tA at %1$tl:%1$tM%1$tp.") else ""
val String tempPartialSolarEclipse = if (new Interval(new Duration(java.util.concurrent.TimeUnit.DAYS.toMillis(7)),new DateTime((Sun_Eclipse_Partial.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)).contains(now)) "\nSpecial Event! There is a Partial Solar Eclipse this week on " + Sun_Eclipse_Partial.state.format("%1$tA at %1$tl:%1$tM%1$tp.") else ""
val String tempRingSolarEclipse = if (new Interval(new Duration(java.util.concurrent.TimeUnit.DAYS.toMillis(7)),new DateTime((Sun_Eclipse_Ring.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)).contains(now)) "\nSpecial Event! There is a Ring Solar Eclipse this week on " + Sun_Eclipse_Ring.state.format("%1$tA at %1$tl:%1$tM%1$tp.") else ""
val String tempTotalLunarEclipse = if (new Interval(new Duration(java.util.concurrent.TimeUnit.DAYS.toMillis(7)),new DateTime((Moon_Eclipse_Total.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)).contains(now)) "\nSpecial Event! There is a Total Lunar Eclipse this week on " + Moon_Eclipse_Total.state.format("%1$tA at %1$tl:%1$tM%1$tp.") else ""
val String tempPartialLunarEclipse = if (new Interval(new Duration(java.util.concurrent.TimeUnit.DAYS.toMillis(7)),new DateTime((Moon_Eclipse_Partial.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)).contains(now)) "\nSpecial Event! There is a Total Lunar Eclipse this week on " + Moon_Eclipse_Partial.state.format("%1$tA at %1$tl:%1$tM%1$tp.") else ""
val String tempSeasonSpring = if (new Interval(new Duration(java.util.concurrent.TimeUnit.DAYS.toMillis(7)),new DateTime((Season_Spring.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)).contains(now)) "\nSpecial Event! Spring starts this week on " + Season_Spring.state.format("%1$tA at %1$tl:%1$tM%1$tp.") else ""
val String tempSeasonSummer = if (new Interval(new Duration(java.util.concurrent.TimeUnit.DAYS.toMillis(7)),new DateTime((Season_Summer.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)).contains(now)) "\nSpecial Event! Summer starts this week on " + Season_Summer.state.format("%1$tA at %1$tl:%1$tM%1$tp.") else ""
val String tempSeasonAutumn = if (new Interval(new Duration(java.util.concurrent.TimeUnit.DAYS.toMillis(7)),new DateTime((Season_Autumn.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)).contains(now)) "\nSpecial Event! Autumn starts this week on " + Season_Autumn.state.format("%1$tA at %1$tl:%1$tM%1$tp.") else ""
val String tempSeasonWinter = if (new Interval(new Duration(java.util.concurrent.TimeUnit.DAYS.toMillis(7)),new DateTime((Season_Winter.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)).contains(now)) "\nSpecial Event! Winter starts this week on " + Season_Winter.state.format("%1$tA at %1$tl:%1$tM%1$tp.") else ""
val String tempStartDST = if (new Interval(new Duration(java.util.concurrent.TimeUnit.DAYS.toMillis(7)),parse(nthDayWithinMonth.apply(2, 7, 3) + "T00:00")).contains(now)) "\nSpecial Event! Daylight Savings Time starts this week." else ""
val String tempEndDST = if (new Interval(new Duration(java.util.concurrent.TimeUnit.DAYS.toMillis(7)),parse(nthDayWithinMonth.apply(1, 7, 11) + "T00:00")).contains(now)) "\nSpecial Event! Daylight Savings Time ends this week." else ""
val String tempSapFlow = if (now.getMonthOfYear < 5 && ((Weather_Temp_Max_F_0.state > 32 && Weather_Temp_Min_F_0.state <= 32) || (Weather_Temp_Max_F_1.state > 32 && Weather_Temp_Min_F_1.state <= 32) || (Weather_Temp_Max_F_2.state > 32 && Weather_Temp_Min_F_2.state <= 32) || (Weather_Temp_Max_F_3.state > 32 && Weather_Temp_Min_F_3.state <= 32) || (Weather_Temp_Max_F_4.state > 32 && Weather_Temp_Min_F_4.state <= 32) || (Weather_Temp_Max_F_5.state > 32 && Weather_Temp_Min_F_5.state <= 32) || (Weather_Temp_Max_F_6.state > 32 && Weather_Temp_Min_F_6.state <= 32) || (Weather_Temp_Max_F_7.state > 32 && Weather_Temp_Min_F_7.state <= 32)) && Weather_Temp_F.maximumSince(now.minusDays(7)).state <= 32) "\nSpecial Event! Sap will be flowing this week." else ""
val String tempGymnastics = if (Mode.state.toString == "Night" && new Interval(new Duration(java.util.concurrent.TimeUnit.DAYS.toMillis(1)),new DateTime((Calendar_Upcoming_Gymnastics.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)).contains(now)) "\nReminder: Anya has gymnastics tomorrow at " + Calendar_Upcoming_Gymnastics.state.format("%1$tl:%1$tM%1$tp.") else ""
val String tempSchool = if (Mode.state.toString == "Night" && new Interval(new Duration(java.util.concurrent.TimeUnit.DAYS.toMillis(1)),new DateTime((Calendar_Upcoming_School.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)).contains(now)) "\nReminder: Anya has school tomorrow at " + Calendar_Upcoming_School.state.format("%1$tl:%1$tM%1$tp.") else ""
Straight milliseconds can be used instead of java.util.concurrent.TimeUnit.DAYS.toMillis(1), but it is MUCH easier to see it this way when looking at the rule. Intervals are pretty handy!