How to calculate the delta between two DateTime objects?

I try to write a rule that checks if all sensors are sending updates.
Therefore I need to calculate the delta between the current DateTime and the last update of the sensor.
This is what I have so far:

var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);
var NotificationAction = org.openhab.io.openhabcloud.NotificationAction;
var ZonedDateTime = Java.type("java.time.ZonedDateTime");

var currentDateTime = ZonedDateTime.now();

//get the required item states
var lightSensorEastLastUpdated = itemRegistry.getItem('LichtsensorOsten_LastUpdated').getState();
var lightSensorSouthLastUpdated = itemRegistry.getItem('LichtsensorSuden_LastUpdated').getState();
var lightSensorWestLastUpdated = itemRegistry.getItem('LichtsensorWesten_LastUpdated').getState();

logger.info("currentDateTime: " + currentDateTime);
logger.info("lightSensorEastLastUpdated: " + lightSensorEastLastUpdated);
logger.info("lightSensorSouthLastUpdated: " + lightSensorSouthLastUpdated);
logger.info("lightSensorWestLastUpdated: " + lightSensorWestLastUpdated);

logger.info(typeof currentDateTime);
logger.info(typeof lightSensorWestLastUpdated);

//this does not work :(
//var deltaTimeLightSensorWestLastUpdated = currentDateTime - lightSensorWestLastUpdated;
//logger.info("deltaTimeLightSensorWestLastUpdated: " + deltaTimeLightSensorWestLastUpdated);

This produces this output:

currentDateTime: 2021-06-24T09:26:05.508409+02:00[Europe/Berlin]
lightSensorEastLastUpdated: 2021-06-24T09:25:30.362+0200
lightSensorSouthLastUpdated: 2021-06-24T09:21:19.005+0200
lightSensorWestLastUpdated: 2021-06-21T22:07:19.313+0200
object
object

I tried to subtract the LastUpdate-DateTime object from the Current-DateTime object. But the result is “NaN” :frowning:

//this does not work :(
var deltaTimeLightSensorWestLastUpdated = currentDateTime - lightSensorWestLastUpdated;
logger.info("deltaTimeLightSensorWestLastUpdated: " + deltaTimeLightSensorWestLastUpdated);

How can I get the delta?

Regards
Bernd

This should work according to Stackoverflow:

Is the problem related to the different format of the DateTime objects?

currentDateTime: 2021-06-24T09:26:05.508409+02:00[Europe/Berlin]
lightSensorWestLastUpdated: 2021-06-21T22:07:19.313+0200

OK, I just learned about the differences of ZonedDateTime, LocalDateTime and ZoneOffset.
This is my new code:

var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);
var NotificationAction = org.openhab.io.openhabcloud.NotificationAction;
var ZonedDateTime = Java.type("java.time.ZonedDateTime");
var LocalDateTime = Java.type("java.time.LocalDateTime");
var ZoneOffset = Java.type("java.time.ZoneOffset");

var currentZonedDateTime = ZonedDateTime.now();
var currentLocalDateTime = LocalDateTime.now();
var currentLocalDateTimeConverted = currentLocalDateTime.atOffset(ZoneOffset.of("+02:00")).toZonedDateTime();
var currentLocalDateTimeConverted2 = currentLocalDateTime.atOffset(ZoneOffset.of("+0200")).toZonedDateTime();

//get the required item states
var lightSensorWestLastUpdated = itemRegistry.getItem('LichtsensorWesten_LastUpdated').getState();

logger.info("currentZonedDateTime: " + currentZonedDateTime);
logger.info("currentLocalDateTime: " + currentLocalDateTime);
logger.info("currentLocalDateTimeConverted: " + currentLocalDateTimeConverted);
logger.info("currentLocalDateTimeConverted2: " + currentLocalDateTimeConverted2);
logger.info("lightSensorWestLastUpdated: " + lightSensorWestLastUpdated);

Produces this output:

currentZonedDateTime: 2021-06-24T14:15:46.969628+02:00[Europe/Berlin]
currentLocalDateTime: 2021-06-24T14:15:46.993178
currentLocalDateTimeConverted: 2021-06-24T14:15:46.993178+02:00
currentLocalDateTimeConverted2: 2021-06-24T14:15:46.993178+02:00
lightSensorWestLastUpdated: 2021-06-21T22:07:19.313+0200

But I cannot produce the current time in the same format as reported by my light sensor item :frowning:

Do you though?

if(lightSensorEastLastUpdated.getZonedDateTime().isBefore(currentDateTime.minusMinutes(10))) {

You are working with JavaScript Objects though. currentDateTime is a java.time.ZonedDateTime and lightSensorWestLastUpdated is an org.openhab.core.library.types.DateTimeType.

Pretty much everything you are working with in openHAB rules, no matter the scripting language, is working with Java Objects, not native to the scripting language Objects.

Well, as I said, the Item’s state isn’t a ZonedDateTime, it’s a DateTimeType. But as I showed above, there is a getZonedDateTime() method you can call to get one which you can use in comparisons and such with currentZonedDateTime etc.

As I indicated above, I think your original question is an XY Problem. You don’t need to calculate the difference between two date times, you just need to compare two date times to see if the Item’s state is before a certain amount of time in the past.

But there can be cases where it is necessary to calculate the difference between two date times and for that you’d use Duration (Java SE 11 & JDK 11 ).

1 Like

Thank you @rlkoshak . Works great!

I tried to find out about the different types by using ‘typeof’.

logger.info(typeof currentDateTime);

but this only returned ‘object’. How can I find out the real type?

Regards
Bernd

.class

logger.info(currentDateTime.class.toString());
1 Like

Hi there,

sorry to hijack this thread but I have “exactly” the same issue and not able to figure it out.
I am in process of moving from 2.x to 3.
I just copied my old rules (text files) into OH3. I try to update them rather than rewriting everything. Changing the items and things already took days.
Anyhow, this is what I have:

rule one, which updates with a new timestamp every time the sensor is updated:

rule "Wetterstation2"
	when 
		Item roofTemp01 changed
	then
		postUpdate(Temp_Roof_LastUpdate, new DateTimeType())
	end

second rule which shall compare if it was updated within last 15 minutes.
According to @rlkoshak this should work:

var currentDateTime = LocalDateTime.now();
if(Temp_Roof_LastUpdate.getZonedDateTime().isBefore(currentDateTime.minusMinutes(15))){
//do something
}

But it is not. getting this

failed: 'getZonedDateTime' is not a member of 'org.openhab.core.library.items.DateTimeItem'

any idea? It shouldn’t be so complicated to do a simple comparison.

No, but this would work


if(Temp_Roof_LastUpdate.state.getZonedDateTime()...

Notice the .state. As has always been the case, to access the state of an Item one must call .state. In Python and JavaScript there is a dict that has all the states of Items using the Item name as the key.

thank you but still not ok. this time the error message is a bit different:

failed: 'getZonedDateTime' is not a member of 'org.openhab.core.types.State'

just to clarify: do I need to declare something, somewhere? just adapted the code in my old rule files (oh2.x).

It looks like in this case you need to cast the state to a DateTimeType first.

if((Temp_Roof_LastUpdate.state as DateTimeType).getZonedDateTime()...
1 Like

@rlkoshak you are my hero. Thank you very much, it worked. I don’t know how many hours I looked into that
 getting closer to the OH3 migration

Looks to me like your hidden attempt contained a typo, State/state

I don’t think that’s the case. By default MyItem.state returns an Object of type State. That’s why we need to cast it so often when we want to do stuff with the state. org.openhab.core.types.State doesn’t define a method called getZonedDateTime which, of course it doesn’t. That’s specific to DateTimeType which is itself of type State.

This is one area where JavaScript and Jython do a little better than Rules DSL. In both of these languages they are much better able to look down, not just up. For example, given a hierarchy like:

Object
    \_State
        \_DateTimeType

Rules DSL will see the State and only look up to see that it’s also an Object. But it won’t look down to see DateTimeType and see that it does in fact implement getZonedDateTime(). It’s one of my many growing frustrations with rules coding in general and one of the things that has held me back from completing the Getting Started Tutorial. It’s like the English language; for every rule of thumb you’ll find a dozen exceptions. I can’t come up with a “Here’s how to write rules regardless of the language” followed by “and here is what’s specific to JavaScript.”

Hello, did you managed to calculate the delta? Could you please share us your code? Thank you.

Best regards.

I did not have to calculate the delta. As @rlkoshak suggested, I use the “isBefore()” function.

My rule now looks like this:

var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);
var NotificationAction = org.openhab.io.openhabcloud.NotificationAction;
var ZonedDateTime = Java.type("java.time.ZonedDateTime");

var currentZonedDateTime = ZonedDateTime.now();

//get the required item states
var lightSensorEastLastUpdated = itemRegistry.getItem('LichtsensorOsten_LastUpdated').getState();
var lightSensorSouthLastUpdated = itemRegistry.getItem('LichtsensorSuden_LastUpdated').getState();
var lightSensorWestLastUpdated = itemRegistry.getItem('LichtsensorWesten_LastUpdated').getState();
var waterLeakageSensorHeatingLastUpdated = itemRegistry.getItem('WassersensorHeizung_LastUpdated').getState();
var waterLeakageSensorWashingMachineLastUpdated = itemRegistry.getItem('WassersensorWaschmaschine_LastUpdated').getState();


if(lightSensorEastLastUpdated.getZonedDateTime().isBefore(currentZonedDateTime.minusDays(1)))
{
  var message = "Lichtsensor Osten sendet keine Updates mehr!";
  logger.warn(message);
  NotificationAction.sendBroadcastNotification(message);
}

if(lightSensorSouthLastUpdated.getZonedDateTime().isBefore(currentZonedDateTime.minusDays(1)))
{
  var message = "Lichtsensor SĂŒden sendet keine Updates mehr!";
  logger.warn(message);
  NotificationAction.sendBroadcastNotification(message);
}

if(lightSensorWestLastUpdated.getZonedDateTime().isBefore(currentZonedDateTime.minusDays(1)))
{
  var message = "Lichtsensor Westen sendet keine Updates mehr!";
  logger.warn(message);
  NotificationAction.sendBroadcastNotification(message);
}

if(waterLeakageSensorHeatingLastUpdated.getZonedDateTime().isBefore(currentZonedDateTime.minusDays(1)))
{
  var message = "Wassersensor Heizung sendet keine Updates mehr!";
  logger.warn(message);
  NotificationAction.sendBroadcastNotification(message);
}

if(waterLeakageSensorWashingMachineLastUpdated.getZonedDateTime().isBefore(currentZonedDateTime.minusDays(1)))
{
  var message = "Wassersensor Waschmaschine sendet keine Updates mehr!";
  logger.warn(message);
  NotificationAction.sendBroadcastNotification(message);
}

1 Like