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.
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 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):