Trying to compare dates in rule (javascript)

Hi,

i am trying to compare dates in items and just can’t work out how to do it. I know this is a common topic and i did a lot of research, but somehow i can’t get the example to work or they don’t apply to my case (found alot for DSL, but sadly can’t transition that to javascript).

I am doing this on Openhab 3.2.0, ECMAScript Edition 11. I edit a rule via the GUI and want to add a script as action in the “then” section.
My goal is to check if year, month and day of the two items (DateTime, Point) is the same.

I am retrieving my items as followed, but don’t know how to proceed for the comparison of the dates (year, month and day).

const date1= items.getItem('date1_item');
const date2= items.getItem('date2_item');

I can access the content of date1 and date2 (e.g. date1.state) and it was correctly retrieved. I can’t compare them directly as they contain hours, minutes, seconds, … and will never be the same.
I tried “getMonth”, but i get a type error saying that getMonth is not a function. I tried casting it, but got an error as well, so i obv did something wrong.

i did something like this …

var month = (date1.state as DateTimeType).getMonth();

and got “Expected ) but found as” in my log.

I honestly don’t know if i just make some stupid syntax error, missing an import or trying to apply the wrong concept here.

Kind regards, P

Three things.

  1. The helper (the thing that provides items.getItem()) almost never gives you the original Java Objects that come from openHAB.

  2. DateTimeType is an openHAB Java class, not JavaScript.

  3. In JavaScript it is very rare that you’d need to ever cast something to another type. It’s really good at handling that sort of thing for you.

So you almost never will be in a position to cast something you got from the helper library to something that is a Java class.

So what do you get back from items.getItem('date1_item')? Looking at the docs we find

  • .getItem(name, nullIfMissing) ⇒ Item

OK, so what’s Item? Again, looking at the docs a little further down we see Item. There we see that Item.state returns

  • .state ⇒ String

So date1.state is a String, not a DateTimeType nor anything that can be converted to any sort of date time by casting. Most of the time that doesn’t matter because even if you have a number, you can do math with the String representation of that number without worry (see 3). But DateTime Items are different. You really do want the original DateTimeType. Looking at the docs some more we find rawState

  • .rawState ⇒ HostState

This is the original Java Item’s state. But there is no getMonth() method on the openHAB Java DateTimeType (see DateTimeType (openHAB Core 4.2.0-SNAPSHOT API)). In no language supported by openHAB could you ever have cast an Item’s state to DateTimeType and call .getMonth() on it. You need to get the raw ZonedDateTime from it. And you’ll see a getZonedDateTime() method on the DateTimeType. From there you can access anything supported by ZonedDateTime (Java SE 11 & JDK 11 ).

So you need

const date1 = items.getItem(‘date1_item’).rawState.getZonedDateTime();

Then you can get the month

var month = date1.getMonth();
2 Likes

Thanks a TON for this very detailed description!

Not only solves this my current problem, but also helps me alot understanding how things are implemented and how they work together! Thanks for devoting your time explaining it in that level of detail!

How would one go about setting a DateTime-item to the ZonedDateTime?
I tried:

  • var zdt = time.ZonedDateTime.now(); items.getItem("myItem").postUpdate(zdt);
  • var zdt = time.ZonedDateTime.now().toISOString(); items.getItem("myItem").postUpdate(zdt);
  • var zdt = time.ZonedDateTime.now().toString; items.getItem("myItem").postUpdate(zdt);

But all came back with errors. I did also try:
var dt = new Date().toISOString(); items.getItem("myItem").postUpdate(dt); and that gave me 2022-05-30T00:49:41.760+0000 in my item. However, I did expect 2022-05-30T02:49:41.760+0200
I read about toLocalTime() or something similar but this is not the same. For the rule I am designing at the moment it is not a problem but there is something going on with DST in combination with Local Time.

What errors? What version of OH?

OH 3.2, scripttype is ECMA 11 (2021).
Item = DateTime type

rule:

var zdt = time.ZonedDateTime.now();
items.getItem("ducoBox_1_expire").sendCommand(zdt);

Log:

2022-06-01 00:57:30.065 [WARN ] [ab.core.internal.events.EventHandler] - Creation of event failed, because one of the registered event factories has thrown an exception: Error getting class for simple name: '$ProxType' using package name 'org.openhab.core.library.types.'.
java.lang.IllegalArgumentException: Error getting class for simple name: '$ProxType' using package name 'org.openhab.core.library.types.'.
        at org.openhab.core.items.events.ItemEventFactory.parseSimpleClassName(ItemEventFactory.java:183) ~[?:?]
        at org.openhab.core.items.events.ItemEventFactory.parseType(ItemEventFactory.java:158) ~[?:?]
        at org.openhab.core.items.events.ItemEventFactory.createCommandEvent(ItemEventFactory.java:109) ~[?:?]
        at org.openhab.core.items.events.ItemEventFactory.createEventByType(ItemEventFactory.java:78) ~[?:?]
        at org.openhab.core.events.AbstractEventFactory.createEvent(AbstractEventFactory.java:53) ~[?:?]
        at org.openhab.core.internal.events.EventHandler.createEvent(EventHandler.java:131) ~[?:?]
        at org.openhab.core.internal.events.EventHandler.handleEvent(EventHandler.java:106) ~[?:?]
        at org.openhab.core.internal.events.EventHandler.handleEvent(EventHandler.java:84) ~[?:?]
        at org.openhab.core.internal.events.ThreadedEventHandler.lambda$0(ThreadedEventHandler.java:67) ~[?:?]
        at java.lang.Thread.run(Thread.java:829) [?:?]
Caused by: java.lang.ClassNotFoundException: org.openhab.core.library.types.$ProxType cannot be found by org.openhab.core_3.2.0
        at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:519) ~[org.eclipse.osgi-3.16.300.jar:?]
        at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:170) ~[org.eclipse.osgi-3.16.300.jar:?]
        at java.lang.ClassLoader.loadClass(ClassLoader.java:522) ~[?:?]
        at java.lang.Class.forName0(Native Method) ~[?:?]
        at java.lang.Class.forName(Class.java:315) ~[?:?]
        at org.openhab.core.items.events.ItemEventFactory.parseSimpleClassName(ItemEventFactory.java:179) ~[?:?]
        ... 9 more

If I change the rule to:

var zdt = time.ZonedDateTime.now();
var regex = new RegExp(/.*(?=\[SYSTEM\])/gm);
var part = regex.exec(zdt);
part = part[0];
console.log(zdt + " " + part);
items.getItem("ducoBox_1_expire").sendCommand(part);

The item is updated correctly and I get in the log:

2022-06-01 01:16:46.583 [INFO ] [org.openhab.automation.script       ] - 2022-06-01T01:16:46.569+02:00[SYSTEM] 2022-06-01T01:16:46.569+02:00

OK, postUpdate and sendCommand always requires a String. So you’d never be able to just send a ZoneDateTime as a command.

It’s supposed to be able to parse the default toString() of the ZonedDateTime but that doesn’t seem to be working due to how the timezone is being represented. But it does appear to work with a LocalDateTime.

items.getItem('TestToZDTDateTime').postUpdate(time.toZDT().toLocalDateTime().toString());**strong text**

I indeed found that time.ZonedDateTime.now().toString() is indeed not working.

I’ll give your suggestion a go. Thanks

Hi,
this is really complicated :thinking:

I want to check in a rule, if a DateTime-item is older than xx seconds compared to now. How would I do that in OH3-Javascript?

if (time.ZonedDateTime.now() - items.getItem(‘date_item’).rawState.getZonedDateTime() > 60) {
}

Thank you.

hi,
in order to get the java ZonedDateTime.now(), this is working for me.

const ZonedDateTime   = Java.type("java.time.ZonedDateTime");

you have to import the java type in order to use methods like now() or getHour(),

i was then able to use

const nowTime = ZonedDateTime.now();

you can then compare the values in the standard java way (ChronoZonedDateTime (Java Platform SE 8 ))

if(item.rawState.getZonedDateTime().plusSeconds(60).isAfter(nowTime)) {
...
}

Thank you!

1 Like