[jsr223] How to get now in UTC timezone using JavaScript

Tags: #<Tag:0x00007f6173250568> #<Tag:0x00007f61732cbcb8>

Hello,

I get a DateTime object for the current point in time using DateTime.now(). What I need is this time in time zone UTC. According to the Jodatime API, this can be done using
DateTime.now().withZone(DateTimeZone.UTC). However, the DateTimeZone class is not available in jsr233 / JavaScript.

I tried var DateTimeZone = Java.type("org.joda.time.DateTimeZone") but this is throwing an exception the class can’t be found.

Thanks for any hint!

  • Harry

You are probably better off using Java’s ZonedDateTime in this context. https://docs.oracle.com/javase/8/docs/api/java/time/ZonedDateTime.html. I don’t know if it is imported by default in JavaScript but if not you can import it and ZoneId.

This works for me in Jython…

from org.joda.time import DateTime, DateTimeZone
from core.log import logging, LOG_PREFIX#, log_traceback

LOG = logging.getLogger("{}.TEST".format(LOG_PREFIX))
LOG.warn(DateTime.now().withZone(DateTimeZone.UTC))

And this works in JS…

'use strict';
var OPENHAB_CONF = Java.type("java.lang.System").getenv("OPENHAB_CONF");
load(OPENHAB_CONF + "/automation/lib/javascript/core/actions.js");
var DateTime = Java.type("org.joda.time.DateTime");
var DateTimeZone = Java.type("org.joda.time.DateTimeZone");

LogAction.logWarn("Rules", DateTime.now().withZone(DateTimeZone.UTC));

Using ZonedDateTime…

from java.time import ZoneId
LOG.warn("here [{}], UTC [{}]".format(DateTimeType().zonedDateTime, DateTimeType().zonedDateTime.withZoneSameInstant(ZoneId.of("UTC"))))

… and…

var ZoneId = Java.type("java.time.ZoneId");

LogAction.logWarn("Rules", "here [{}], UTC [{}]", new DateTimeType().zonedDateTime, new DateTimeType().zonedDateTime.withZoneSameInstant(ZoneId.of("UTC")));

Thanks for looking into this!

Yes, I tried the var DateTimeZone = Java.type("org.joda.time.DateTimeZone"); assignment before, but for my installation it bombs with a java.lang.ClassNotFoundException exception.

I’m on the latest openHABian and latest stable openHAB2 release. I’ll try the ZonedDateTime class in a minute.

2020-01-15 10:42:00.594 [DEBUG] [e.automation.internal.RuleEngineImpl] - 

java.lang.RuntimeException: Fail to execute action: 1

at org.openhab.core.automation.internal.RuleEngineImpl.executeActions(RuleEngineImpl.java:1197) ~[bundleFile:?]

at org.openhab.core.automation.internal.RuleEngineImpl.runRule(RuleEngineImpl.java:993) [bundleFile:?]

at org.openhab.core.automation.internal.TriggerHandlerCallbackImpl$TriggerData.run(TriggerHandlerCallbackImpl.java:91) [bundleFile:?]

at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_222]

at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_222]

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_222]

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_222]

at java.lang.Thread.run(Thread.java:748) [?:1.8.0_222]

Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: org.joda.time.DateTimeZone

at org.openhab.core.automation.module.script.rulesupport.shared.simple.SimpleRule$$NashornJavaAdapter.execute(Unknown Source) ~[?:?]

at org.openhab.core.automation.module.script.rulesupport.shared.simple.SimpleRuleActionHandlerDelegate.execute(SimpleRuleActionHandlerDelegate.java:34) ~[?:?]

at org.openhab.core.automation.module.script.rulesupport.internal.delegates.SimpleActionHandlerDelegate.execute(SimpleActionHandlerDelegate.java:59) ~[?:?]

at org.openhab.core.automation.internal.RuleEngineImpl.executeActions(RuleEngineImpl.java:1189) ~[bundleFile:?]

... 7 more

Caused by: java.lang.ClassNotFoundException: org.joda.time.DateTimeZone

at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[?:1.8.0_222]

at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_222]

at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349) ~[?:1.8.0_222]

at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_222]

at org.eclipse.osgi.internal.framework.ContextFinder.loadClass(ContextFinder.java:132) ~[org.eclipse.osgi-3.12.100.jar:?]

at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_222]

at java.lang.Class.forName0(Native Method) ~[?:1.8.0_222]

at java.lang.Class.forName(Class.java:348) ~[?:1.8.0_222]

at jdk.nashorn.internal.runtime.Context.findClass(Context.java:1051) ~[nashorn.jar:?]

at jdk.nashorn.internal.objects.NativeJava.simpleType(NativeJava.java:498) ~[nashorn.jar:?]

at jdk.nashorn.internal.objects.NativeJava.type(NativeJava.java:322) ~[nashorn.jar:?]

at jdk.nashorn.internal.objects.NativeJava.type(NativeJava.java:314) ~[nashorn.jar:?]

at jdk.nashorn.internal.objects.NativeJava.type(NativeJava.java:310) ~[nashorn.jar:?]

at jdk.nashorn.internal.scripts.Script$Recompilation$236$9972A$\^eval\_.datetime_utc2(<eval>:337) ~[?:?]

at jdk.nashorn.internal.scripts.Script$Recompilation$234$10329AA$\^eval\_.execute(<eval>:352) ~[?:?]

at org.openhab.core.automation.module.script.rulesupport.shared.simple.SimpleRule$$NashornJavaAdapter.execute(Unknown Source) ~[?:?]

at org.openhab.core.automation.module.script.rulesupport.shared.simple.SimpleRuleActionHandlerDelegate.execute(SimpleRuleActionHandlerDelegate.java:34) ~[?:?]

at org.openhab.core.automation.module.script.rulesupport.internal.delegates.SimpleActionHandlerDelegate.execute(SimpleActionHandlerDelegate.java:59) ~[?:?]

at org.openhab.core.automation.internal.RuleEngineImpl.executeActions(RuleEngineImpl.java:1189) ~[bundleFile:?]

... 7 more

So this is occurring when the rule is triggered. I only tested using it through the script, not in a rule. Could you post your rule, or better the simplest rule that causes the error?

This works for me on 2.5.1-2…

'use strict';
var OPENHAB_CONF = Java.type("java.lang.System").getenv("OPENHAB_CONF");
load(OPENHAB_CONF + '/automation/lib/javascript/core/rules.js');
load(OPENHAB_CONF + '/automation/lib/javascript/core/actions.js');

var DateTime = Java.type("org.joda.time.DateTime");
var DateTimeZone = Java.type("org.joda.time.DateTimeZone");

JSRule({
    name: "Test JavaScript rule",
    description: "This rule is for testing JavaScript",
    triggers: [
        CommandEventTrigger("Virtual_Switch_1", null, "Test_Trigger_Name")
    ],
    execute: function (module, input) {
        // LogAction.logWarn("Rules", "Test {}", input['event'].itemCommand)
        LogAction.logWarn("Rules", DateTime.now().withZone(DateTimeZone.UTC));
    }
});

I have placed both the DateTimeZone and ZoneID versions in Javascript functions:

var datetime_utc2 = function (t /*DateTime*/)
{
	//var DateTime = Java.type("org.joda.time.DateTime"); // doesn't bomb, but not required
	var DateTimeZone = Java.type("org.joda.time.DateTimeZone"); // bombs
	var t_utc = t.withZone(DateTimeZone.UTC);
	
	logInfo("datetime_utc2(): "+t_utc);
	
	return t_utc;
}

var datetime_utc3 = function (t /*ZonedDateTime*/)
{
	var ZoneId = Java.type("java.time.ZoneId");
	var t_utc = t.withZoneSameInstant(ZoneId.of("UTC"));

	logInfo("datetime_utc3 (): "+t_utc);
	
	return t_utc;
}

The minimal rule is this one, uncommenting the datetime_utc2 call throws the exception. In case this is working for you, I have either different Java configuration or it is related to 2.5.0-1 vs. 2.5.1-2 openHAB releases.

JSRule({
	name: me+" L"+__LINE__,
	description: "Rule_Sun_TotalRadiation",
	triggers: [ 
        TimerTrigger("0 * * * * ?")
	],
	execute: function( module, input) {
		
		//datetime_utc2(DateTime.now());
		datetime_utc3(new DateTimeType().zonedDateTime);
	}
});

Your minimal rule gave me errors due to unknown variable ‘me’. I took that out and it ran without errors using utc2.

This works for me…

'use strict';

var OPENHAB_CONF = Java.type("java.lang.System").getenv("OPENHAB_CONF");
load(OPENHAB_CONF + '/automation/lib/javascript/core/rules.js');
load(OPENHAB_CONF + '/automation/lib/javascript/core/actions.js');

var datetime_utc2 = function (t /*DateTime*/)
{
	//var DateTime = Java.type("org.joda.time.DateTime"); // doesn't bomb, but not required
	var DateTimeZone = Java.type("org.joda.time.DateTimeZone"); // bombs
	var t_utc = t.withZone(DateTimeZone.UTC);
	logInfo("datetime_utc2(): "+t_utc);
	return t_utc;
}

datetime_utc2(DateTime.now());
var me = "test"
JSRule({
	name: "Test rule",
	description: "Rule_Sun_TotalRadiation",
	triggers: [ 
        TimerTrigger("0 * * * * ?")
	],
	execute: function(module, input) {
		datetime_utc2(DateTime.now());
		//datetime_utc3(new DateTimeType().zonedDateTime);
	}
});

There were no changes in openHAB core between these releases and there won’t be any in the 2.5.x releases. Are you using the JavaScript helper libraries from here? If so, when was the last time you updated them? Also, which OS and version of Java are you using?

“me” has been the name of the .js file as used in the samples. Not relevant for the test.

I’m using the helper libs linked, actually I installed them yesterday (which is the day I started to migrate from XTend to jsr223). The Java version is the standard installed with openHABian:

[13:13:41] openhabian@openhab:~$ java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment (Zulu8.40.0.178-CA-linux_aarch32hf) (build 1.8.0_222-b178)
OpenJDK Client VM (Zulu8.40.0.178-CA-linux_aarch32hf) (build 25.222-b178, mixed mode, Evaluation)

The interesting thing is that
var DateTime = Java.type("org.joda.time.DateTime");
is working while
var DateTimeZone = Java.type("org.joda.time.DateTimeZone");
bombs… Both should be in the same package.

A appreciate the time you take looking into this. And I’d rather have it working using DateTimeZone instead of having a reference to the deprecated DateTimeType in my code… But for now I can live with the ZonedDateTime solution - better that adding the timezone shift manually. :wink:

Somebody needs to keep an eye on automation :wink:!

Do you get the error straight from the script (no rule)? I’m curious if you get the error in Jython.

DateTimeType is not deprecated, but Joda is and has been removed from OH 3.0.

No idea about Jython - I have removed that part during installation.

Java.type(“org.joda.time.DateTimeZone”) crashes when called from within a rule (as discussed) but doesn’t when ran on script top level (i.e. when executed when the script is loaded). :frowning: