DateTime operations

  • Platform information:
  • Release = Raspbian GNU/Linux 12 (bookworm)
  • Kernel = Linux 6.6.31+rpt-rpi-v8
  • Platform = BCM43455 37.4MHz Raspberry Pi 3±0190
  • OH openHAB 4.2.2 - Release Build
  • Java Runtime Environment: openjdk version “17.0.12” 2024-07-16
  • Issue of the topic: DateTime - duration between

Gentlemen, can you tell me how to handle the time calculation rule between two dates (in minutes, seconds, DD:HH:MM - it doesn’t matter)?

I’ve looked through almost the entire OH forum. Most of the solutions are from years ago and probably don’t work because of changes and progress.
One of the latest examples almost worked (Difference between 2 timestamps - #3 by rlkoshak ), i.e. it calculates some difference but only between two dates of the type
2024-12-11T16:39:30.154360295+01:00[Europe/Berlin]

In the meantime, basically all DateTime items that I have and would like to subtract from each other are in the format:
2024-12-11T16:47:04.322854811+0100

VisualStudioCode suggests in the written rule that:

Type mismatch: cannot convert from DateTimeItem to Temporal(org.eclipse.xtext.xbase.validation.IssueCodes.incompatible_types)

and attempting to subtract these two different formats from each other returns an error in frontail:

2024-12-11 16:58:05.583 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID '_atest-1' failed: An error occurred during the script execution: Could not invoke method: java.time.Duration.between(java.time.temporal.Temporal,java.time.temporal.Temporal) on instance: null in _atest

Here it is rule code I`m trying to make working:

import java.time.Duration

var ZonedDateTime lastOffTime = null

rule "Rele1"
when
    Item TestJinks14 changed
then
    if(newState == OFF) {
        lastOffTime = now
        var sunset = LocalSun_Z
        
        
        logInfo("testsr", now.toString() )
		var diff = Duration.between(lastOffTime, sunset)
        logInfo("sweet", "Duration is: " + diff.toString() )
		
    }
end

Those are just String formating of a DateTime. If you have a ZonedDateTime already, the String formatting is irrelevant.

If I assume that LocalSun_Z is a DateTime Item then you just need to get the ZonedDateTime from the Item’s state.

import java.time.Duration

var ZonedDateTime lastOffTime = null

rule "Rele1"
when
    Item TestJinks14 changed
then
    if(newState == OFF) {
        lastOffTime = now
        var sunset = (LocalSun_Z.state as DateTimeType).zonedDateTime
        
        
        logInfo("testsr", now.toString() )
		var diff = Duration.between(lastOffTime, sunset)
        logInfo("sweet", "Duration is: " + diff.toString() )
		
    }
end

Note the “toString” method of Duration returns an ISO8601 duration String. For example, 1 day, 2 hours, 3 minutes, 4 seconds would be “P1DT2H3M4S”). If you want HH:MM:SS you’ll have to build that string yourself using the methods of the Duration.

Thanks for the incredibly fast response. It works beautifully, I can handle formatting to DD:HH:MM somehow (I saw it in some forum thread) :grinning:

I was puzzled to see this, as it seemed like this would try to access the private member zonedDateTime in DateTimeType - which doesn’t exist anymore in 4.3. But after testing, it seems like some sort of alias for getZonedDateTime?

Please note that getZonedDateTime() is deprecated in OH 4.3. However, this will now work:

var sunset = (LocalSun_Z.state as DateTimeType).getZonedDateTime(ZoneId.systemDefault)`

For reference: DateTimeType (openHAB Core 4.3.0-SNAPSHOT API)

See also The method getZonedDateTime() from the type DateTimeType is deprecated

1 Like

Rules DSL let’s you reference getters as if they were properties. So if there is a getZonedDateTime() method you can call it using zonedDateTime.

And that deprecation is possibly a mistake. The PR that changed it was not supposed to impact Rules DSL.

For anyone following this thread, the mentioned PR is this one:

You are right that I didn’t anticipate that Rules DSL would log deprecation notices when loading rules. Unfortunately there is strong coupling between Rules DSL and core types.

I’m not sure if the deprecation itself is a mistake though, but I am somewhat divided. The issue is that previously you would get back the time-zone that was provided when creating the DateTimeType. If the item was updated by a binding, this might be the configured time-zone in openHAB - or system time-zone or UTC, depending on the binding.

Now, you will get system time-zone, because that’s the only time-zone which is possible to obtain within the DateTimeType instance. Therefore the functionality had to change, and IMHO this ambiguity is a good reason for deprecating the method, and instead promote getZonedDateTime(ZoneId) in order to have consistent and predictable results. Especially for addons, this should lead to refactoring so that the desired time-zone is always explicitly provided. I already prepared a PR for that, so that we’ll no longer be using the deprecated methods:

On the other hand, it might be desirable to be less strict for Rules DSL since this is user-provided rules, and for most users the system time-zone will be the same as the time-zone configured in openHAB. However, fundamentally the problem is the same in rules as in addons, so in the long run, I still think it would be better to avoid relying implicitly on the time-zone, as it could lead to some unexpected behavior.

Unfortunately, because of the tight coupling, there is no way of deprecating the method for core/addons Java development, but not for Rules DSL. So I think not deprecating it now will just postpone the problem. And all DSL rules will still continue to work, even with the deprecation notices logged.

For completeness, this deprecation shouldn’t affect any other rule languages. It has been verified at least that JavaScript doesn’t log anything, and it will only require a small change in the beginning of the 5.0 development cycle to stop using the deprecated method, and instead use the time-zone configured in openHAB. This will lead to a more consistent behavior than prior to 4.3 (the “breaking change” label is misleading, it won’t be breaking):

1 Like