Enhance Rule Machine-Required Expression-"Between Two Dates" Condition

Please consider adding the following type of capability:

  • At 30 minutes to sunset each night, when the date is between [2 days before Mother's Day], and [1 day after Mother's Day]. Run some action.

  • Mothers Day is the 2nd Sunday in May, and therefore a different date each year.

I can think of 2 ways to do this:

  1. In the "Between Two Dates" condition of a Required Expression: Add the logic to select a Periodic Date (similar to the logic already existing in the "Periodic Schedule" within a Trigger) plus an offset to each selected date.
  2. Since the logic to use a Variable already exists in the "Between Two Dates" condition of a Required Expression, it would be more robust to add a DateTime offset capability in Between Two Dates, and then add the capability in a Rule Machine Action to set a Variable to a Periodic Date (similar to the logic already existing in the "Periodic Schedule" within a Trigger). The Variable would be set to the next immediately subsequent date as determined by the selected Periodic Schedule at the time the action is run. The ability to set a Variable to "Current Date" etc already exists in Rule Machine, but not a "Periodic Date".

Using method 1 would allow a straight forward selection of the 2nd Sunday in May.

Using method 2 allows the user to set a dynamically calculated DateTime variable in Rule Machine which could be set to the 2nd Sunday in May for use in the Required Expression, but also opens up this capability for a lot of other interesting use cases.

You can already come up with something that does what you want to do using a Cron string and a rule that sets two variables. That rule would have this Cron string as its Periodic Schedule trigger:

0 0 0 ? 5 1#1 *

That fires on the first Sunday of May every year. What we want is a variable date that is five days later, and one 9 days later (midnight after the Monday after Mothers Day). Like this, only this should use Hub Variables not Local Variables (I used Local so you could see what happens).

I used Run Actions to set the two variables today, just to demonstrate what happens. You can see that Two Days Before is set to 5 days from now, and One Day After to 9 days from now. These two variables become the Between Two Dates condition for the Mothers Day rule.

Each year, these are reset, and the Mothers Day rule only runs during that period.

Like this:

I forgot one thing, I probably should only have used 8 days after, because Between Two Dates runs to the end of the second date, which is what we want.

With respect to your suggested additions to RM:

Periodic Schedule creates a Cron string. The Scheduler in the hub uses Cron strings for scheduling. As you can see above, Periodic Schedule also allows user specified Cron strings. While it's a nice idea to be able to set a DateTime variable from a Cron string, it's a bit of a challenge to convert a Cron String to a specific date and time -- essentially replicate the code that exists in the scheduler, or expose a method in the hub that does that. I'm pretty sure I don't want to take on the former, and don't know if the latter is feasible or not. However, as demonstrated above, it's easy enough already to accomplish the same thing by other means.

1 Like

Thanks for the quick response @bravenel. Amazing!

As usual, you have a very clever way to achieve a similar result via another method.

To be a little more generalized in the opportunity, do you see a way to use the workaround for a target central date that is the Last Day of Week, in a month. To use the workaround, it seems we would need the 2nd to last Day of Week in the month to be the trigger to set the interval variables, and I haven't been able to find how to write that in Cron itself.

For example, Memorial Day is the Last Monday in May.

I was wondering what the Periodic Schedule code was doing behind the scenes. Based on your description, Periodic Schedule is a wrapper to translate human input into Cron, and the system is fundamentally using Cron for the trigger. I was thinking you may have been using a home-brew converter that takes the input and makes a Unix TimeStamp (seconds since Epoch) and storing that in a database as the trigger. If Cron is the core of Periodic Schedule, then as you suggest, it is a bit more difficult to get the next date out in a simple way. If you are interested, there is a PHP method doing just this, but is likely not reasonable to implement.

https://github.com/dragonmantank/cron-expression

Using: $cron->getNextRunDate()

I have created a few Rule Machine Rules that act like functions to store a Unix TimeStamp in a variable, translated from a "MM-DD-YYYY" type format input in another variable (also does last , and Nth Weekday etc). These work quite well, as the trigger is any change to the input variable, and automatically out pops the Unix timestamp in another variable via Rule Machine. I was just getting ready to migrate those Rule "Functions" to the use new Hub Variable from the old Rule Machine variables, and thought I'd check to see if this could be done natively now without re-writing those rules in RM 5.1. If you have any interest in seeing if this might be something to implement in Hubitat behind the scenes for general use in Rule Machine, I would be happy to share those rules that do that math.

If not, I will likely start typing up my new rules in RM 5.1 :slight_smile:

This is correct.

Agree.

RM can do this directly with setting a number variable from a DateTime variable:

It is also possible to set a DateTime variable from an Epoch time:

Agree if one already has the simple "MM-DD-YYYY" type input, and/or seconds since Epoch already figured out for a date.

The part that is still missing (unless I am missing something) is to determine the time since Epoch (or Date) for the Last Monday in May, and store it in a variable, and do that before the last Monday in May so that an interval around that date can be specified for triggering around it.

The little Rule "function" that I wrote takes an input like L-DOW-MM-YYYY, (like L-1-5-2021 for Last-Monday-May-2021) and calculates the timestamp (since Epoch) for it, and stores it in a variable, and can do that at any time (for example on the first day of the year) so that interval variables around the timestamp can be created for triggering.