Date-Time Calculation issue OH2 to OH3

I have a rule for calculating the minutes until sunset, this is quite useful for switching off heavier load items as the day ends and solar power diminishes.

The rule below worked fine with OH2, but with the migration to OH3(I did a clean install) this rule does not work. It is the ONLY thing that does not work with OH3 thus far, which quite impressed me.

Items:

Number MinutesUntilSunset "Minutes Until Sunset [%.0f min]"

Rule:

rule "Minutes Until Sunset"
when
    Time cron "0/30 * * * * ?"
then
MinutesUntilSunset.postUpdate((new DateTime(Sunset_Time.state.toString).millis - new DateTime(Current_DateTime.state.toString).millis) / 60000)
end  

I am aware that OH3 now uses Javas native date/time format but I just cannot get my head around it. Any help appreciated!

As documented in the release notes, DateTime no longer exists in openHAB 3. It’s been replaced by ZonedDateTime. See Rules | openHAB and DateTime Conversion (openHAB 3.x) for lots of examples of working with ZonedDateTime.

Given that we have ZonedDateTimes now, the best approach would probably be to use the stuff built into the classes anyway.

java.time.temporal.ChronoUnit

// in the rule

    var minsToSunset = ChronoUnit.MINUTES.between(now, Sunset_Time.state.getZonedDateTime)

You might need to cast Sunset_Time.state to a DateTimeType.

2 Likes

Hi Rick,

I have a similar problem to calculate the minutes between the last state change (saved in a DateTime item) and now. I want to write the rule as ECMA script but I can not calculate with the variable now and the DateTime item.

ECMA code:

var logger = Java.type(“org.slf4j.LoggerFactory”).getLogger(“org.openhab.model.script.Rules.Experiments”);

var now = new Date(new Date() - 10000)
var lastAction = itemRegistry.getItem(‘Spuelmaschine_OpStateLastChange’).getState()

logger.info("now = " + now)
logger.info("lastAction = " + lastAction)

logger.info("now = " + now)
logger.info("lastAction = " + lastAction)

diff = lastAction - now

logger.info("minutes= " + diff)

2021-02-13 13:15:03.808 [INFO ] [enhab.model.script.Rules.Experiments] - now = Sat Feb 13 2021 13:14:53 GMT+0100 (CET)
2021-02-13 13:15:03.808 [INFO ] [enhab.model.script.Rules.Experiments] - lastAction = 2021-02-12T19:14:05.614500+0100
2021-02-13 13:15:03.816 [INFO ] [enhab.model.script.Rules.Experiments] - diff= NaN

How can I convert the dates to caculate a time difference (in minutes)?

Thank you for your help!

Thanks @rlkoshak appreciate the pointer, although Java Time is quite a big change(for me) it certainly has benefits and a lot more built in functionality. You were correct Sunset_Time.state needed to be cast.

Working rule:

import java.time.temporal.ChronoUnit

rule "Minutes Until Sunset"
when
    Time cron "0/30 * * * * ?"
then
    var minsToSunset = ChronoUnit.MINUTES.between(now, (Sunset_Time.state as DateTimeType).getZonedDateTime)
        MinutesUntilSunset.postUpdate(minsToSunset)
    var minsPastSunrise = ChronoUnit.MINUTES.between((Sunrise_Time.state as DateTimeType).getZonedDateTime, now)
        MinutesPastSunrise.postUpdate(minsPastSunrise)
end  

Why my question gets the solution tag???

@johannesbonn apologies, I fat fingered that one

1 Like

There is no more DateTime. It has been replaced with ZonedDateTime. To get now use ZonedDateTime.now(). Once oyu do that the above will work in all the languages.

var ZonedDateTime = Java.type("java.time.ZonedDateTime");
var ChronoUnit = Java.type("java.time.temporal.ChronoUnit"0;

var now = ZonedDateTime.now();
var minsToSunset = ChronoUnit.MINUTES.between(now, (Sunset_Time.state as DateTimeType).getZonedDateTime());
1 Like

Thank you Rick,
this was the solution. One last Question:-)
My timestamp (here Sunset_Time) is in the past, so the result is negativ between jetzt1 (now) and my timestamp. When I change the two parts in the expression I get the following error in the log:

Script execution of rule with UID 'Java_Test' failed: TypeError: (itemRegistry.getItem("Spuelmaschine_OpStateLastChange").getState() ,> jetzt1).getZonedDateTime is not a function in <eval> at line number 45

And here my expression:

var laufzeitMinuten = ChronoUnit.MINUTES.between((itemRegistry.getItem('Spuelmaschine_OpStateLastChange').getState(), jetzt1).getZonedDateTime());

Do you have an idea what my failure is?

If this is JavaScript, that line is a little overly complex. All the Item’s current states are stored in an items dict. Also, the state of a DateTime Item is not a ZonedDateTime. But you can get a ZonedDateTime from it. So

var laufzeitMinuten = ChronoUnit.MINUTES.between(items['Spuelmaschine_OpStateLastChange'].getZonedDateTime(), jetzt1);

Not I’m assuming that jetzt1 is itself also already a ZonedDateTime.

Even if that wasn’t a problem, your parens are in the wrong place and the expression is essentially meaningless.

1 Like

Thank You!!! Now its running like it should!