DateTime calculations/formatting in a rule

Hey chaps & chapettes,
I’m having a hard time transforming DateTime into something I can work with.
What I’m trying to do:
Send a push notification at 6pm in case the garbage will be picked up the next day. I have “garbage collection” as a datetime object in OH (MuellTime0 ). So I’ve started to code the following rule:

import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import org.joda.time.*
import java.util.Date
import java.lang.Double
import org.openhab.core.types.Command
import java.lang.Math
import java.util.Date
import java.util.Calendar
import java.util.GregorianCalendar

rule "Bring garbage outside"
Time cron "00 00 18 ? * *"
var DateTime alarm = now.plusHours(7) as DateTime
logInfo(“Muell Erinnnerung”, "MuellTime0 : " + MuellCalTime0.state)
logInfo(“Muell Erinnnerung”, "Now : " + now)
logInfo(“Muell Erinnnerung”, "Now +7h : " + alarm)
if (alarm.isAfter(MuellCalTime0.state)) {
logInfo(“Muell Erinnnerung”, “Muelltonne muss raus”)
} else {
logInfo(“Muell Erinnnerung”, “Muelltonne kann stehen bleiben”)

Logfile sais:

2016-04-28 13:52:00.267 [INFO ] [model.script.Muell Erinnnerung] - MuellTime0 : 2016-04-28T00:00:00
2016-04-28 13:52:00.327 [INFO ] [model.script.Muell Erinnnerung] - Now : 2016-04-28T13:52:00.327+02:00
2016-04-28 13:52:00.380 [INFO ] [model.script.Muell Erinnnerung] - Now +7h : 2016-04-28T20:52:00.114+02:00
2016-04-28 13:52:00.439 [ERROR] [.o.m.r.i.engine.ExecuteRuleJob] - Error during the execution of rule Bring garbage outside
java.lang.IllegalStateException: Could not invoke method: org.joda.time.base.AbstractInstant.isAfter(long) on instance: 2016-04-28T20:52:00.114+02:00
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation( ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._featureCallOperation( ~[na:na]
at sun.reflect.GeneratedMethodAccessor50.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke( ~[na:1.8.0_77]
at java.lang.reflect.Method.invoke( ~[na:1.8.0_77]
at org.eclipse.xtext.util.PolymorphicDispatcher.invoke( ~[na:na]
at org.openhab.model.script.interpreter.ScriptInterpreter.internalFeatureCallDispatch( ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._evaluateMemberFeatureCall( ~[na:na]
at sun.reflect.GeneratedMethodAccessor51.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke( ~[na:1.8.0_77]
at java.lang.reflect.Method.invoke( ~[na:1.8.0_77]
at org.eclipse.xtext.util.PolymorphicDispatcher.invoke( ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate( ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._evaluateIfExpression( ~[na:na]
at sun.reflect.GeneratedMethodAccessor91.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke( ~[na:1.8.0_77]
at java.lang.reflect.Method.invoke( ~[na:1.8.0_77]
at org.eclipse.xtext.util.PolymorphicDispatcher.invoke( ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate( ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._evaluateBlockExpression( ~[na:na]
at sun.reflect.GeneratedMethodAccessor59.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke( ~[na:1.8.0_77]
at java.lang.reflect.Method.invoke( ~[na:1.8.0_77]
at org.eclipse.xtext.util.PolymorphicDispatcher.invoke( ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate( ~[na:na]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate( ~[na:na]
at org.openhab.model.script.internal.engine.ScriptImpl.execute( ~[na:na]
at org.openhab.model.rule.internal.engine.ExecuteRuleJob.execute( ~[na:na]
at [quartz-all-2.1.7.jar:na]
at org.quartz.simpl.SimpleThreadPool$ [quartz-all-2.1.7.jar:na]
Caused by: java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_77]
at sun.reflect.NativeMethodAccessorImpl.invoke( ~[na:1.8.0_77]
at sun.reflect.DelegatingMethodAccessorImpl.invoke( ~[na:1.8.0_77]
at java.lang.reflect.Method.invoke( ~[na:1.8.0_77]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation( ~[na:na]
… 29 common frames omitted

As you can see my variables/timestamps are filled ok but the if comparrison does not work. Can anyone give me a hint how to make it work?
Thanks much!

Have a look at my rule for determining time of day:

rule "Get time period for right now"
System started
val morning = now.withTimeAtStartOfDay.plusHours(MorningStart).millis
val night = now.withTimeAtStartOfDay.plusHours(NightStart).millis
val sunrise = new DateTime(getAstroSunriseStart(now.toDate, lat, lon))
val evening = new DateTime(getAstroSunsetStart(now.toDate, lat, lon))
val twilight= evening.minusMinutes(TwilightStart)

// Set the time variables (once), and their events OFF
var DateTime morningtime=now.withTimeAtStartOfDay.plusHours(MorningStart)
if(now.getHourOfDay>MorningStart) {
	// morning has passed add 24 hours
var DateTime nighttime=now.withTimeAtStartOfDay.plusHours(NightStart)
postUpdate(Morning_Time, new DateTimeType(morningtime.toCalendar(null)))
postUpdate(Night_Time, new DateTimeType(nighttime.toCalendar(null)))

// Determine TimeOfDay state
if(now.isAfter(morning) && now.isBefore(sunrise)) {     
} else if(now.isAfter(sunrise) && now.isBefore(twilight)) {
} else if(now.isAfter(twilight) && now.isBefore(evening)) { 
} else if(now.isAfter(evening) && now.isBefore(night))  {  
} else if(now.isAfter(night)) {                                                 

// Create the necessary timers
if(TimeOfDay.state=="night") {
	// Create timer for in the morning
	if(tMorning!=null) {
		logInfo("TOD","Cancelling morning timer")
	tMorning = createTimer(morningtime) [|
		logInfo("TOD","Timer tMorning executed")
	logInfo("TOD","Morning timer created")
} else {
	// Create timer for the night
	if(tNight!=null) {
		logInfo("TOD","Cancelling night timer")
	tNight = createTimer(nighttime) [|
		logInfo("TOD","Timer tNight executed")
	logInfo("TOD","Night timer created")


This works like a charm.

Hey Gerhard,
thanks for your reply. Not sure if I got your example correctly. You’re suggesting to convert both DateTime’s into millis to do proper “greater than” comparrison?
For my alarm var thats easy, but how do I put the DateTime object into such millis?

Or did I get your idea completly wrong?
Thanks for your help.

As you can see from your log MuellCalTime0.state is casted to 2016-04-28T00:00:00 which is a formatted datetime and you cant do calculations with that. Am not that experienced with java and jodatime, but maybe you can give the following a go:
add var Muell = new DateTime(MuellCalTime0.state) and then change your alarm.isafter to this variable. This is similar to my sunrise and evening variables.

One small point: A DateTime item in openHAB is not at all the same thing as a DateTime object from org.joda.time. They unfortunately share the same name, but they aren’t actually related.

A DateTime item in openHAB usually has a state of class DateTimeType. When you have a DateTimeType, you can reference its java.util.Calendar member using .calendar in a rule. Then you can access this calendar’s properties, such as .timeInMillis. Then you can use that returned long to create or modify org.joda.time.base.AbstractInstant instances. For example:

import org.joda.time.*
import org.openhab.core.library.types.DateTimeType

rule MyRule
  Item BinMenArrive changed
  val DateTime binMenArrive = new DateTime((BinMenArrive.state as DateTimeType).calendar.currentTimeMills)
  if (now.isBefore(binMenArrive)) {
    logInfo("MyRule", "put the bins out!")
  } else {
    logWarn("MyRule", "too late; have to wait a week.")

Hey guys,
many thanks for your help. I have the following rule in place now which works ok.

rule "Bring garbage outside"
Time cron “00 00 18 ? * *”
//Time cron "00 * * ? * *"
//The time from NOW until alarm
val alarm = now.plusHours(7).millis
//The time from NOW until garbage event happens
var MuellTime0Millis = (MuellCalTime0.state as DateTimeType).calendar.timeInMillis
//logInfo(“Muell Termin”, "MuellTime0 : " + MuellCalTime0.state)
//logInfo(“Muell Termin”, "MuellTime0.Millis : " + MuellTime0Millis)
//logInfo(“Muell Termin”, "Now +7h : " + now.plusHours(7))
//logInfo(“Muell Termin”, “Now +7h.Millis : " + alarm)
if (alarm > MuellTime0Millis) {
logInfo(“Muell Termin”, “Muelltonne muss raus: " + MuellCalName0.state.toString )
sendBroadcastNotification(“Morgen (”+MuellCalTime0.state+”) wird die “” + MuellCalName0.state.toString + “” Tonne geleert”)
} else {
logInfo(“Muell Termin”, “Muelltonne kann stehen bleiben”)

Only thing I have to fiddle now is that my events are 24h events and I get a message in case the bins have been collected the same morning already. But that should be fairly easy with now.getDayofweek.millis I guess.
Again, thanks for your help!