[SOLVED] Another JavaTime conversion Thread... DateTime

Hi Folks,

I just changed to Openhab 3 Stable

Now after getting almost everithing working I run into conversion problems…
I’m using my timeofday pattern to switch daytimes but this isn’t functioning anymore

I read the threads about DateTime Conversion (openHAB 3.x) and Design Pattern: Time Of Day but I don’t get it.

I guess I’m trying to convert from JavaTime to DateTime but not sure if this is right…
There are many different guesses and I’m a little bit overwhelmed what to choose.
I tried some different approaches but all I get in the logs are warnings and errors.

If I try this:

val morning = ZonedDateTime.now().with(LocalTime.MIDNIGHT.plusDays(1).minusHours(16).minusMinutes(0))

log says:

[ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'timeofday-1' failed: 'plusDays' is not a member of 'java.time.LocalTime'

If I try this code instead:

val morning = now.withHour(8).withMinute(0).withSecond(0)

the logs are saying that this line is not working because valueOf is not a member of JavaTime:

Morning_Time.postUpdate(morning.valueOf(morning.toLocalDateTime().toString()))

see here:

[ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'timeofday-1' failed: 'valueOf' is not a member of 'java.time.ZonedDateTime'

and if I try this instead:

Morning_Time.postUpdate(morning.toString)

I get:

[WARN] [b.core.model.script.actions.BusEvent] - Cannot convert '2021-01-03T08:00:00.924228+01:00[Europe/Berlin]' to a state type which item 'Morning_Time' accepts: [DateTimeType, UnDefType].

So I’m stuck at trial & error - any hints appreciated :wink:

Do I have to change the ItemType to anything else?? Or is it a syntax error??
To prevent my head from exploding I’m writing this thread and hope for clearification and help…

thanks in advance

Dan

I have tested that with ECMA Script ,changed the first part a bit and i think it should work like shown below.

This should initialize the date with current time, set the localtime to midnight and perform the c aalculation you want after that.

var ZonedDateTime   = Java.type("java.time.ZonedDateTime")
var LocalTime       = Java.type("java.time.LocalTime")

var morning = ZonedDateTime
.now()
.with(LocalTime.MIDNIGHT)
.plusDays(1)
.minusHours(16)
.minusMinutes(0)

The plus and minus methods are part of ZonedDateTime and not of LocalTime.
Therefore you have to do the LocalTime change first and then apply the other methods.

I added the 2 definitions on top of my rules so that they’re recognized globally…

and I changed “morning” to

val morning = ZonedDateTime.now().with(LocalTime.MIDNIGHT).plusDays(1).minusHours(16).minusMinutes(0)

but this doesn’t seem to work, log says:

[ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'timeofday-1' failed: 'now' is not a member of 'Object'

maybe I got something wrong?

this is the whole rule:

var ZonedDateTime   = Java.type("java.time.ZonedDateTime")
var LocalTime       = Java.type("java.time.LocalTime")

rule "TimeOfDay - Calculate State" 
when
	System started or 
	Channel 'astro:sun:home:civilDawn#event'  triggered START or
	Channel 'astro:sun:home:set#event'  triggered START or
	Time cron "0 1 0 * * ? *" or
	Time cron "0 0 1 * * ? *" or
	Time cron "0 0 8 * * ? *" or
	Time cron "0 0 10 * * ? *" or
	Time cron "0 0 12 * * ? *" or
	Time cron "0 0 15 * * ? *" or
	Time cron "0 0 18 * * ? *"
then
	logInfo("TimeOfDay", "Calculating time of day...")
	// get values for calculation from astrodata
	val dawnstart = (Dawnstart_Time.state as DateTimeType).getZonedDateTime()
	val sunsetstart = (Sunsetstart_Time.state as DateTimeType).getZonedDateTime()

	// set hardcoded values for calculation
	val morning = ZonedDateTime.now().with(LocalTime.MIDNIGHT).plusDays(1).minusHours(16).minusMinutes(0)
	val forenoon = ZonedDateTime.now().with(LocalTime.MIDNIGHT).plusDays(1).minusHours(14).minusMinutes(0)
	val noone = ZonedDateTime.now().with(LocalTime.MIDNIGHT).plusDays(1).minusHours(12).minusMinutes(0)
	val afternoon = ZonedDateTime.now().with(LocalTime.MIDNIGHT).plusDays(1).minusHours(9).minusMinutes(0)
	val evening = ZonedDateTime.now().with(LocalTime.MIDNIGHT).plusDays(1).minusHours(6).minusMinutes(0)
	val dayend = ZonedDateTime.now().with(LocalTime.MIDNIGHT).plusDays(1).minusSeconds(1)
	val daystart = ZonedDateTime.now().with(LocalTime.MIDNIGHT).plusDays(1).minusHours(24).minusMinutes(0)
	val bedtime = ZonedDateTime.now().with(LocalTime.MIDNIGHT).plusDays(1).minusHours(23).minusMinutes(0)

	// send values to Items
	Morning_Time.postUpdate(morning.toString)
	logInfo("TimeOfDay", "morning: "+morning.toString)
	Forenoon_Time.postUpdate(forenoon.valueOf(now.toLocalDateTime().toString()))
	logInfo("TimeOfDay", "forenoon: "+forenoon.toString)
	Noon_Time.postUpdate(noone.valueOf(now.toLocalDateTime().toString()))
	logInfo("TimeOfDay", "noone: "+noone.toString)
	Afternoon_Time.postUpdate(afternoon.valueOf(afternoon.toLocalDateTime().toString()))
	logInfo("TimeOfDay", "afternoon: "+afternoon.toString)
	Evening_Time.postUpdate(evening.valueOf(evening.toLocalDateTime().toString()))
	logInfo("TimeOfDay", "evening: "+evening.toString)
	Dayend_Time.postUpdate(dayend.valueOf(dayend.toLocalDateTime().toString()))
	logInfo("TimeOfDay", "dayend: "+dayend.toString)
	Daystart_Time.postUpdate(daystart.valueOf(daystart.toLocalDateTime().toString()))
	logInfo("TimeOfDay", "daystart: "+daystart.toString)
	Bedtime_Time.postUpdate(bedtime.valueOf(bedtime.toLocalDateTime().toString()))
	logInfo("TimeOfDay", "bedtime: "+bedtime.toString)

	// Calculate the current time of day
	var curr = "UNKNOWN"
	var last = TimeOfDay.previousState(true).state.toString

	switch true {
		case 	now.isAfter(bedtime) 		&& now.isBefore(dawnstart)									: curr =    "BEDTIME"
		case 	now.isAfter(dawnstart) 		&& now.isBefore(morning) 		&& now.isBefore(forenoon)   : curr =    "DAWN"
		case 	now.isAfter(dawnstart) 		&& now.isAfter(morning) 		&& now.isBefore(forenoon)   : curr =    "DAWN"
		case 	now.isAfter(morning) 		&& now.isAfter(dawnstart)   	&& now.isBefore(forenoon) 	: curr =    "MORNING" 
		case 	now.isAfter(morning) 		&& now.isBefore(dawnstart)  	&& now.isBefore(forenoon) 	: curr =    "MORNING"      
		case 	now.isAfter(forenoon) 		&& now.isBefore(noone)       								: curr =    "FORENOON"
		case 	now.isAfter(noone) 			&& now.isBefore(afternoon)      							: curr =    "NOON"
		case 	now.isAfter(afternoon) 		&& now.isBefore(evening)    								: curr =    "AFTERNOON"
		case 	now.isAfter(evening)		&& now.isBefore(sunsetstart) 	&& now.isBefore(dayend)		: curr =    "EVENING"
		case 	now.isAfter(evening)		&& now.isAfter(sunsetstart) 	&& now.isBefore(dayend)		: curr =    "EVENING"
		case 	now.isAfter(sunsetstart)	&& now.isAfter(evening)			&& now.isBefore(dayend)		: curr =    "SUNSET"
		case 	now.isAfter(sunsetstart)	&& now.isBefore(evening) 		&& now.isBefore(dayend)		: curr =    "SUNSET"
		case 	now.isAfter(daystart) 		&& now.isBefore(bedtime)									: curr =	"NIGHT"
		case 	now.isAfter(dayend) 		&& now.isBefore(daystart)									: curr =	"EVENING"	
	}

	// Publish the current state
	if ( TimeOfDay.state.toString != curr ) {
		TimeOfDay.sendCommand(curr)
		PreviousTimeOfDay.sendCommand(last)
		logInfo("TimeOfDay", "It's "+curr.toString+" now")
		logInfo("PreviousTimeOfDay", "It's "+last.toString+" now")
	}
end

ignore different syntax - I’m still trying what works…

I am not sure if and how ZonedDateTime has to be declared in DSL Rules.
As said i have done them in ECMA Script, because i use that for all of my rules.

Did you test my minimum example too and did the same error occur there?

I only tested it in my rule… but I think this doesn’t make a difference, the log errors on the first line with your syntax…

You need not to define the two headers for ZonedDateTime in the DSL rule.
The only item that you need to change is the closing ) after MIDNIGTH as proposed and you already did.

another approach would be to use this syntax:

	// set hardcoded values for calculation
	val morning = now.withHour(8).withMinute(0).withSecond(0)
	val forenoon = now.withHour(10).withMinute(0).withSecond(0)
	val noone = now.withHour(12).withMinute(0).withSecond(0)
	val afternoon = now.withHour(15).withMinute(0).withSecond(0)
	val evening = now.withHour(18).withMinute(0).withSecond(0)
	val dayend = now.withHour(23).withMinute(59).withSecond(59)
	val daystart = now.withHour(0).withMinute(0).withSecond(0)
	val bedtime = now.withHour(1).withMinute(0).withSecond(0)

and concentrate on this error:

[ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'timeofday-1' failed: 'valueOf' is not a member of 'java.time.ZonedDateTime'

caused by this syntax

Morning_Time.postUpdate(morning.valueOf(morning.toLocalDateTime().toString()))

I think ‘now.withHour(8).withMinute(0).withSecond(0)’ is working… but the writing to the Item fails due to conversion problems. But I don’t know the right syntax for that…

Ok I’ll give it a try… give me a minute

I changed the syntax to:

	// set hardcoded values for calculation
	val morning = ZonedDateTime.now().with(LocalTime.MIDNIGHT.plusDays(1).minusHours(16).minusMinutes(0))
	val forenoon = ZonedDateTime.now().with(LocalTime.MIDNIGHT.plusDays(1).minusHours(14).minusMinutes(0))
	val noone = ZonedDateTime.now().with(LocalTime.MIDNIGHT.plusDays(1).minusHours(12).minusMinutes(0))
	val afternoon = ZonedDateTime.now().with(LocalTime.MIDNIGHT.plusDays(1).minusHours(9).minusMinutes(0))
	val evening = ZonedDateTime.now().with(LocalTime.MIDNIGHT.plusDays(1).minusHours(6).minusMinutes(0))
	val dayend = ZonedDateTime.now().with(LocalTime.MIDNIGHT.plusDays(1).minusSeconds(1))
	val daystart = ZonedDateTime.now().with(LocalTime.MIDNIGHT.plusDays(1).minusHours(24).minusMinutes(0))
	val bedtime = ZonedDateTime.now().with(LocalTime.MIDNIGHT.plusDays(1).minusHours(23).minusMinutes(0))

but the error remains:

[ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'timeofday-1' failed: 'now' is not a member of 'Object'

what about my other suggestion to concentrate on converting the data while writing to the Item?? e.g. change these lines (both not working):

Morning_Time.postUpdate(morning.toString)
Morning_Time.postUpdate(morning.valueOf(morning.toLocalDateTime().toString()))

to anything else…

OK I figured it out by myself:

as I suggested i had to change the above mentioned line to:

Morning_Time.postUpdate(morning.toLocalDateTime().toString())

and left this line as it was before…

val morning = now.withHour(8).withMinute(0).withSecond(0)

e.g.

only replace

.toString

with

.toLocalDateTime().toString()

now everything is running fine again :slight_smile:

I Also got this error while bugfixing, it’s another way of thinking was my experience. But i’m pretty sure i configured Openhab with timezone Europe/Amsterdam. Something I’m missing? I think Berlin is your timezone?

You’re right thats my timezone… if I get you right you installed with Europe/Amsterdam and getting errors/warnings for Europe/Berlin in your logs??

Correct, not sure what I’ve could have done wrong actually or where I can configure it else then in the UI. I never chose Berlin, so I think it’s the default for some reason.

weird… but maybe you’re right - hope you will find my solution helpful…

i think you should use

Morning_Time.postUpdate(morning.toLocalDateTime().toString())

to prevent this error

you have to change the lowercase ‘morning’ to your corresponding val name!

1 Like

Great solution with localtime!

I don’t use the method for my part of day determination. In my setup, morning, afternoon, evening and night at dynamical determined. Morning when we are downstairs, evening when it’s dark, night when nobody is downstairs and no movement for a while,etc.

So Val doesn’t work in my situation. Anyway thanks for sharing!