ECMAScript DateTime item convert to/from ZonedDateTime/LocalDateTime

Hello all,

I have an ECMAScript (Javascript) in which I want to process date time. For this I want to use an item in which the date and time are stored permanently. Unfortunately I can’t get it to work, also the search didn’t help me. In DateTime Conversion (openHAB 3.x) I don’t find an explanation for Javascript or I don’t understand it. Below the code how it should look like but I can’t get the conversion ZonedDateTime or LocalDateTime into a DateTime item and back.

I tried postUpdate for DateTime items from ECMAScript script.

But the item print out with

logger.info('NewItem2 = ' + itemRegistry.getItem('NewItem').getState());

is always NULL;

var scriptExecution = Java.type('org.openhab.core.model.script.actions.ScriptExecution');
var zonedDateTime = Java.type('java.time.ZonedDateTime'); 
var zonedDateTimeNow = Java.type('java.time.ZonedDateTime');
var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID); 

// Check if item is initialized
if ((itemRegistry.getItem("ControlStartLast").getState() == 'NULL') || (itemRegistry.getItem("ControlStartLast").getState() == 'UNDEF')) {
	events.postUpdate('ControlStartLast', zonedDateTime.now());
          logger.info('Init value');

} else {
  	   logger.info(' ControlStartLast is: ' + itemRegistry.getItem('ControlStartLast').getState());
        }

// Check if actual time is greater then ‚ControlStartLast’
zonedDateTimeNow =  zonedDateTime.now();
if ( zonedDateTime.now() > itemRegistry.getItem("ControlStartLast").getState()) {
  // Do something
  events.postUpdate("ControlStartLast", zonedDateTimeNow);
}

Regrads Holger

Which JavaScript are you using? ECMAScript 5.1 or ECMAScript 2021?

That means your NewItem Item has never been initialized. It’s not holding a DateTime so you need to address that first. You can’t convert or work with a DateTime that doesn’t exist.

If you go back to the DateTime. Conversion link, first of all realized that right here you are working a Java ZonedDateTime regardless of what language you are using (except in ECMAScript 2021 where the Java types are converted to JabaScript types). So what you see there applies.

With that go down to #4 Get Java Time from DateTimeType and you’ll have your answer.

val MyJavaTimeFromDateTimeItem = (MyDateTimeItem.state as DateTimeType).getZonedDateTime()

Now that’s Rules DSL so it takes a little bit of changes. But you’ve already demonstrated you know what to do. You have an Item.

itemRegistry.getItem('ControlStartLast')

You want the state of that Item (note, per the docs a DateTime Item’s state, when not NULL or UNDEF, is a DateTimeType).

itemRegistry.getItem('ControlStartLast').getState()

You want to compare that state to now which is a ZonedDateTime. How do we convert a DateTimeType to a ZonedDateTime? As shown at that link

itemRegistry.getItem('ControlStartLast').getState().getZonedDateTime()

But where does the > come from? You’ll not have seen that in any examples anywhere on this forum for comparing date times. You is isBefore() or isAfter().

if(zonedDateTime.now().isAfter(itemRegistry.getItem('ControlStartLast').getState().getZonedDateTime())){

Hello Rich,

Thanks for your fast response. I have ECMAScript 5.1.

I set the item value now during start up with the help of the Blockly Date and Time library.
grafik

I also learned from there how to set/get items values.

Thanks a lot.

1 Like

please be aware that if you use rrd4j for restoring values on startup, DateTime items are not supported (I found this in another post of @rlkoshak which I can’t find right now…). I had the same issue and resolved it easily by creating a Number item instead of the DateTime item which is stored and restored properly. Instead of setting the date I’m setting the ms from the timestamp via “items.getItem(‘xx’).postUpdate(new Date().getTime());”. If you want to compare the value with the current date you can easily do it by checking if the item state is < new Date().getTime() again.

If you want to show the value in a sitemap, you can add a JS transformation:

function pad2(tobepadded) {
    if (tobepadded < 10) {
        return '0' + tobepadded;
    } else {
        return tobepadded;
    }
}

(function (i) {
    if (i === '0') {
        return '';
    }
    var date = new Date(parseInt(i));
    var dateString =
        pad2(date.getDay()) +
        '.' +
        pad2((date.getMonth() + 1)) +
        '.' +
        date.getFullYear() +
        ' ' +
        pad2(date.getHours()) +
        ':' +
        pad2(date.getMinutes());
    return dateString;
})(input)

(I didn’t get padStart to work and transformations don’t throw errors, so I implemented it the brute force way :slight_smile: )

I think as of 3.1 rrd4j now supports DateTime Items. I remember seeing a PR saying such scroll by. I never tested it though. I use MapDB for restoreOnStartup which supports all Item types.

at least in OH 3.2 it was not working (until yesterday). I checked the persistence folder and couldn’t find a file for the DateTime items. Now as I changed them to Number they are available.

I’m just wondering if using MapDB + rrd4j has an impact on the performance of the system as for each update there have to be executed two DB writes?

Well, you don’t have to write everything to both databases Those are just default settings to get you started. As your system grows you really should be thinking tailoring anyway.

Having said that, mapdb is very low overhead in any case.

1 Like

Here is the solution that works for me.

Init of the values in a rule thats is triggerd during startup.
grafik

Javascript code in the rule in which my control is worked out.

var zonedDateTime = Java.type('java.time.ZonedDateTime'); 
var startOfToday = Java.type('java.time.ZonedDateTime');
var startOfLastDay = Java.type('java.time.ZonedDateTime');
var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID); 

// Note: Init of time values is done in rule 'Initialization'


logger.info('Rule started');

// Get start of today
startOfToday = zonedDateTime.now();
startOfToday = startOfToday.minusHours(startOfToday.getHour());
startOfToday = startOfToday.minusMinutes(startOfToday.getMinute());
startOfToday = startOfToday.minusSeconds(startOfToday.getSecond());
startOfToday = startOfToday.minusNanos(startOfToday.getNano());

// Get start of last day
startOfLastDay = itemRegistry.getItem('RollerShutterControlStartLast').getState().getZonedDateTime();
startOfLastDay = startOfLastDay.minusHours(startOfLastDay.getHour());
startOfLastDay = startOfLastDay.minusMinutes(startOfLastDay.getMinute());
startOfLastDay = startOfLastDay.minusSeconds(startOfLastDay.getSecond());
startOfLastDay = startOfLastDay.minusNanos(startOfLastDay.getNano());

if (itemRegistry.getItem('ControlAutoHand').getState() == 'ON') {
  if (!startOfToday.isEqual(startOfLastDay)) {
    // Do something
	events.sendCommand('RollerShutterControlStartLast', new dateTimeType(startOfToday));
  }
}