DateTime Conversion after Migration to OH3

Hi all,

after migration from 2.5 to 3.4 I am struggling with updating my rules to new DateTime syntax. I read the Tutorial but still need some help.

I have made some changes to my rule regarding astro information but it is still not running.
Any help appreciated.

val sunsetend = ((Sunset_End.state as DateTimeType).getZonedDateTime().toInstant.toEpochMilli)
val daylstart = ((Daylight_Start.state as DateTimeType).getZonedDateTime.toInstant.toEpochMilli)
if (now.isBefore(ZonedDateTime.now().with(LocalTime.MIDNIGHT).plusHours(12))) {
Midnight_Start.postUpdate(ZonedDateTime.now().with(LocalTime.MIDNIGHT).toString)
Sunset_End_Rule.postUpdate(sunsetend.minusDays(1).toString)
Daylight_Start_Rule.postUpdate(daylstart.toString)
}
// wenn nach 12 Uhr nimm aktuelle Zeiten
if (now.isAfter(ZoneDateTime.now().with(LocalTime.MIDNIGHT).plusHours(12))) {
Midnight_Start.postUpdate(ZoneDateTime.now().with(LocalTime.MIDNIGHT).plusDays(1).toString)
Sunset_End_Rule.postUpdate(sunsetend.toString)
Daylight_Start_Rule.postUpdate(daylstart.plusDays(1).toString)
}

Two things. Please use code fences, not quotes, when posting code.

```
code goes here
```

Second, we are not computers. What’s the error?

Sorry Rich!

The error message is about the if clauses:

2022-12-29 21:51:01.789 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID ‘midnight-1’ failed: The name ‘ZoneDateTime’ cannot be resolved to an item or type; line 26, column 17, length 12 in midnight

val sunsetend = ((Sunset_End.state as DateTimeType).getZonedDateTime().toInstant.toEpochMilli)
val daylstart = ((Daylight_Start.state as DateTimeType).getZonedDateTime.toInstant.toEpochMilli)
if (now.isBefore(ZonedDateTime.now().with(LocalTime.MIDNIGHT).plusHours(12))) {
Midnight_Start.postUpdate(ZonedDateTime.now().with(LocalTime.MIDNIGHT).toString)
Sunset_End_Rule.postUpdate(sunsetend.minusDays(1).toString)
Daylight_Start_Rule.postUpdate(daylstart.toString)
}
// wenn nach 12 Uhr nimm aktuelle Zeiten
if (now.isAfter(ZoneDateTime.now().with(LocalTime.MIDNIGHT).plusHours(12))) {
Midnight_Start.postUpdate(ZoneDateTime.now().with(LocalTime.MIDNIGHT).plusDays(1).toString)
Sunset_End_Rule.postUpdate(sunsetend.toString)
Daylight_Start_Rule.postUpdate(daylstart.plusDays(1).toString)
}

This line is correct.

This line is incorrect. Can you spot the difference? You’re missing a “d”. Zoned not Zone.

Thanks! Sometimes it is so obvious but you don’t see it.

Now there’s another error coming up:

2022-12-29 22:19:02.121 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID ‘midnight-1’ failed: ‘plusDays’ is not a member of ‘long’; line 29, column 32, length 21 in midnight

It is the last line.

Well, for some unknown reason, you’ve initialized sunsetend and daylstart to epoch. That’s just a number counting the number of milliseconds since midnight 1970-1-1. It’s just a number so of course it doesn’t have a plusDays.

If you want to use milliseconds epoch, then do that, but you will just be working with raw numbers. If you want code that’s readable and easy to understand, drop the epoch and stick to ZonedDateTime.

Hmm, strange that it worked with these variables at OH2.5.

I deleted it and now the rule works but doesn’t change the item Midnight_Start which is a DateTime item:

2022-12-29 22:42:01.529 [WARN ] [b.core.model.script.actions.BusEvent] - Cannot convert ‘2022-12-30T00:00+01:00[Europe/Berlin]’ to a state type which item ‘Midnight_Start’ accepts: [DateTimeType, UnDefType].

Because it is a DateTime item I don’t understand what’s wrong now.

I guarantee you that this code, as written, never worked in OH 2.5. You can’t call plusDays() on a long. That’s never been possible. Either you’ve added the calls to toInstant.toEpochMilli or you added the call to plusDays(1) since converting (or this code never ran in 2.5 in the first place).

Add some logging to work backwards to see why it might be failing.

Elsewhere you use now by itself but here you use ZonedDateTime.now(), why the inconsistency?

You probably don’t need the toString. Assuming this is Rules DSL (you never said) you can pass a ZonedDateTime, no need to use a String and force OH to reparse it.

I read about this as a working solution in another thread.

Without „.toString“ the rule is throwing an error again:

2022-12-29 23:06:01.505 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID ‘midnight-1’ failed: An error occurred during the script execution: Could not invoke method: org.openhab.core.model.script.actions.BusEvent.postUpdate(org.openhab.core.items.Item,org.openhab.core.types.State) on instance: null in midnight

I will do the logging tomorrow and come back to you.

Thank you Rich for your patience and support so far!

You don’t show your imports. Are you using the right ZonedDateTime? I can’t imagine how you couldn’t be but this is not behaving normally.

I found the solution: I had to use LocalDateTime for updating the item Midnight_Start.

I still have to migrate some other DateTime related rules.
I hope you don’t mind if I come back to you when I am struggling with these too :pensive:

Note that a recent update (in the last day in fact) to the openhab-js library fixes the need to convert to LocalDateTime.

And here I am with another problem.

I want to update the DateTime item with the actual DateTime (=> now)
but I don’t get it running.

EG_Kinderzimmer_Motion_Time.postUpdate(LocalDateTime.now().toString)

While this one is working:

Midnight_Start.postUpdate(LocalDateTime.now().with(LocalTime.MIDNIGHT).toString)

I see no reason why one would work and the other not work. What’s the error?

I found a solution - this one works

EG_Kinderzimmer_Motion_Time.postUpdate(now.toLocalDateTime().toString())

Maybe at the above one the „()“ was missing at toString?

In Rules DSL the () is optional for calls to functions that don’t take an argument.

I have another question regarding a rule I don’t get running.

val sunsetendWZ = ((Sunset_End.state as DateTimeType).getZonedDateTime())

is used in an if clause this way

now.isAfter(sunsetendWZ.plusMinutes(10))

This if clause doesn’t work anymore in 3.4. but I don’t know why.

Maybe it’s better to send the complete code

The if clause should fire when it’s dark outside.
But it always is firing the else if.

val sunsetendKZ = ((Sunset_End.state as DateTimeType).getZonedDateTime())
val daylstartKZ = ((Daylight_Start.state as DateTimeType).getZonedDateTime())
var String melder_log_msg = "echo " + now.toLocalDateTime().toString + " Kinderzimmer >> /var/log/openhab/bewegung.log 2>&1"
executeCommandLine(Duration.ofSeconds(5),"/bin/bash","-c",melder_log_msg)
EG_Kinderzimmer_Motion.sendCommand(ON)
EG_Kinderzimmer_Motion_Time.postUpdate(now.toLocalDateTime().toString())
logInfo("INFO", "Bewegung Kinderzimmer erfasst")
//  if (Kinderzimmer_timer === null && now.isAfter(sunsetendKZ.plusMinutes(10)) && now.isBefore(daylstartKZ.minusMinutes(30))) {
if (Kinderzimmer_timer === null && sunsetendKZ.isBefore(now.minusMinutes(10)) && daylstartKZ.isAfter(now.plusMinutes(30))) {
    EG_Kinderzimmer_Switch.sendCommand(ON)
    logInfo("INFO", "Bewegung - Licht Kinderzimmer an")
//  Kinderzimmer_timer = createTimer(now.plusMinutes(5), [ | EG_Kinderzimmer_Switch.sendCommand(OFF) EG_Kinderzimmer_Motion.sendCommand(OFF) EG_Kinderzimmer_Motion_Tamper.sendCommand(OFF) Kinderzimmer_timer = null ])
    Kinderzimmer_timer = createTimer(now.plusMinutes(5), [ | EG_Kinderzimmer_Motion.sendCommand(OFF) EG_Kinderzimmer_Motion_Tamper.sendCommand(OFF) Kinderzimmer_timer = null ])
}
else if (Kinderzimmer_timer === null) {
    Kinderzimmer_timer = createTimer(now.plusMinutes(5), [ | EG_Kinderzimmer_Motion.sendCommand(OFF) EG_Kinderzimmer_Motion_Tamper.sendCommand(OFF) Kinderzimmer_timer = null ])
}

The „// if“ line is the old one from 2.5. I tried another one as you can see but it doesn’t work too.

Errors in the log?

There is nothing obviously wrong with that line of code.

If there are no error logs and it just isn’t running when expected, it means Sunset_End doesn’t have the state you expect here. So log it out. Log out now too and even log out the result of the isAfter.

Thanks it was a good hint!
One of the dates was not set correctly