Feeling rusty... compare two times?

Shame on me, but I need to refresh my rule ability… let’s say I have something like this
How do compare two times so I know how many seconds is between those?
Do I need convert DateTime states to something to be able to substract them? cos this is not working :wink:

Things

DateTime myTime_on
DateTime myTime_off
Text myPeriod

Rule

rule "compare times"
when
  myItem received update
then
  val lastON  = myTime_on.state
  val lastOFF = myTime_off.state

  val diff = lastOFF - lastON

  postUpdate(myPeriod, diff)
end

Thanks, my brain is not working … :frowning:

Yes. You need to get epoch (milliseconds since 1970-01-01T00:00:00.000). https://www.openhab.org/docs/configuration/rules-dsl.html#datetime-item has a good reference for working with DateTimeTypes in Rules.

    val lastOn = (myTime_on.state as DateTimeType).zonedDateTime.timeInMillis
    val lastOff = (myTime_off.state as DateTimeType).zonedDateTime.timeInMillis

    val diff = (lastOff - lastOn) / 1000

as always, thank you @rlkoshak you are lifesaver :wink:

edit:

The method or field timeInMillis is undefined for the type ZonedDateTime(org.eclipse.xtext.diagnostics.Diagnostic.Linking

Is there a need to include something at the begining of the rules?

Z should be lower case? zonedDateTime

it is

 val lastOn = (myTime_on.state as DateTimeType).zonedDateTime.timeInMillis
 val lastOff = (myTime_off.state as DateTimeType).zonedDateTime.timeInMillis

Maybe this from this post

val lastOn = (myTime_on.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli

that worked, thanks :wink:

Hmmm, it would appear the docs are wrong. I copied and pasted from those.

It depends on what you’ve written your rule in. With scripted automation, Jython and the helper libraries, you can use the core.date.seconds_between function…

from core.log import logging, LOG_PREFIX#, log_traceback
from core.date import seconds_between

LOG = logging.getLogger("{}.TEST".format(LOG_PREFIX))

LOG.warn(seconds_between(items["Virtual_DateTime_1"], items["Virtual_DateTime_2"]))

However, java.time.temporal.ChonoUnit provides something similar…

from java.time.temporal.ChronoUnit import SECONDS
from core.log import logging, LOG_PREFIX#, log_traceback

LOG = logging.getLogger("{}.TEST".format(LOG_PREFIX))

LOG.warn(SECONDS.between(items["Virtual_DateTime_1"].zonedDateTime, items["Virtual_DateTime_2"].zonedDateTime))

This can also be used in the rules DSL…

import java.time.temporal.ChronoUnit

rule "Test DSL rule"
when
    System started
then
    logWarn("Rules", "Test: Start")

    logWarn("Rules", "{}", ChronoUnit.SECONDS.between((Virtual_DateTime_1.state as DateTimeType).zonedDateTime, (Virtual_DateTime_2.state as DateTimeType).zonedDateTime))

    logWarn("Rules", "Test: End")
end

well this is getting quite interesting :wink:

2020-01-23 21:56:47.882 [INFO ] [lipse.smarthome.model.script.->> one] - -25
2020-01-23 21:56:47.883 [INFO ] [lipse.smarthome.model.script.->> two] - -53
val lastOn = (ItemON.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli
    val lastOff = (itemOFF.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli

    val diff = (lastOff - lastOn) / 1000

    logInfo("->> one", diff.toString)
    
    logInfo("->> two", "{}", ChronoUnit.SECONDS.between((itemOFF.state as DateTimeType).zonedDateTime, (itemON.state as DateTimeType).zonedDateTime))

and physical device console

21:55:55 MQT: home/test/sensor/PIR = ON
21:56:48 MQT: home/test/sensor/PIR = OFF

so, If I did not missed math in school that’s exactly 53s. That means second approach calculates it correctly, but first is somehow calculating only 25s?

few moments later I’ve got this

22:01:45 MQT: home/test/sensor/PIR = ON
22:02:39 MQT: home/test/sensor/PIR = OFF

which is 56s

but log

2020-01-23 22:02:37.972 [INFO ] [lipse.smarthome.model.script.->> one] - -296
2020-01-23 22:02:37.973 [INFO ] [lipse.smarthome.model.script.->> two] - 296

Am I overlooking something?

You probably want to log out the timestamps the rule is working with.

Guessing you are triggering the rule from something that is only vaguely linked to those getting updated, you might be looking at a race condition.

nope, it’s inside one rule so everything is triggered at same time
at least for point of view of code.

A great resource for understanding this better is the awesome time conversion thread by rud @anfaenger found here

thanks, solving similar things it seems :wink:

anyway looks like OH is having difficulties to work with changed times inside single rule.
Splitted into two and seems to be behaving better.

Both your failing and successful rules are secret, this makes it difficult to comment constructively.

In the skeleton example at the top, the rule is triggered by one Item updating, but the timestamps are derived from other Items which we have no way of knowing how or when they get updated.

In the later snippet you posted with two methods, each method fetches its ‘data’ independently from Items. There is no guarantee that these Items do not changed inbetween. It’s not a fair test.