DateTime Conversion (openHAB 2.x)

There is a lot of confusion in that short little rule.

Today is an Item, not a DateTime. You can’t create a DateTime using an Item. You have to use either epoch or an ISO8601 formatted String.

Removing .millis doesn’t round epoch to the nearest second. .millis literally returns the epoch. By removing that you are not longer dealing with epoch.

To store the epoch value so you can use it in your visibility on the sitemap, Today_Epoch needs to be a Number Item. You can’t update a Number Item with a DateTimeType. Conversely, if it isn’t a Number Item than the Item can’t store epoch.

To put epoch for today at midnight (which is what you really need I think) into a Number Item Today_Epoch all you need is

    val midnight_today = now.withTimeAtStartOfDay()
    Today.postUpdate(midnight_today)
    Today_Epoch.postUpdate(midnight_today.millis)

Hi @rlkoshak Thanks for the clarification.

Yes, I do need a midnight time as one element, and would still need to convert the String from Partition1_AlarmMemory to EPOCH as well in order to use both in the visibility?
I am really new to coding at this level, so plenty of confusion.

I have changed rule to:

rule SetDay
when
    System started or
    Item Testing_Switch received command ON or
    Time is midnight
then
    val midnight_today = now.withTimeAtStartOfDay()

    Today.postUpdate(midnight_today)

    Today_Epoch.postUpdate(midnight_today.millis)  
end 

I now get the following error:

18:59:31.566 [INFO ] [del.core.internal.ModelRepositoryImpl] - Refreshing model 'time.rules'
18:59:36.635 [ERROR] [untime.internal.engine.RuleEngineImpl] - Error during the execution of startup rule 'SetDay': Could not invoke method: org.eclipse.smarthome.model.script.actions.BusEvent.postUpdate(org.eclipse.smarthome.core.items.Item,java.lang.String) on instance: null

Any ideas why that would be? And what I need to do to convert the STRING from the item that already exists?

Thanks
Mark

EDIT: Updated to:

Today.postUpdate(midnight_today.**toString**)

And works Thanks

Today_Epoch is a Number Item?

    val alarm_epoch = new DateTime(Partition1_AlarmMemory.state.toString).millis
    Partition1_AlarmMemory_Epoch.postUpdate(alarm_epoch) // you need to create this Item

What String from what item that already exists?

@rlkoshak
Yes, I have checked and Today_Epoch is a Number Item - with no dimension
Will try the code snip above as soon as I can get the error cleared from the Midnight_Today piece.

Partition1_AlarmMemory is a a channel from my Caddx binding. When this changes I log the Time to the Partition1_Last_Alarm String item (I think I was unclear in my reply above):

rule "Partition 1 Alarm Timestamp"
when
    Item Partition1_AlarmMemory changed to ON or
    Item Testing_Switch received command ON
then
        postUpdate(Partition1_Last_Alarm, new DateTimeType())
        logInfo("", "Partition 1 Alarm Timestamp " + Partition1_Last_Alarm.state )
end

I will be using the two items Today_Epoch and Partition1_AlarmMemory_Epoch in my visibilty condition.

EDIT: Tested the Partiton1_AlarmMemory_Epoch snippit - works great! Thanks

Mark

You don’t need a Rule for this. See the timestamp profiles. https://www.openhab.org/docs/configuration/items.html#profiles

Note that this should be a DateTime Item, not a String Item.

@rlkoshak
Great, thank you. Will take a detailed look. At first glance though this would timestamp each change (On and Off). I am only interested in On.

With your help though I now seem to have the two epoch items I need. So will see how far I get from here.

Working with DateTime is clearly way more complex that I expected.

You’re spending a lot of time on rules, but if the above is the purpose … what did you have in mind?
You cannot set set visibility along the lines of “if it is after six pm”.

I have now realized that you cannot compare two items in visibility - which presents a small challenge, but will work though that. Will just use the Epoch value to get an age of the information I want/don’t want to display.
The alarm system I am using sets flags for the zones which generated the last alarm. These do not update until they are cleared by the next alarm event, so once they are a certain age they become irrelevant, so want to hide them from view.

So thinking along the lines of only displaying the relevant groups of zones if the last alarm was within the last 24 hours (maybe allow a variable time period: 1 day, 2 days, 7 days).
That way there is only an option to see recent Zones which caused alarms on a Partition (Area) that has had an alarm in X time.

Hope I have explained clearly enough.

Always open to better more streamlined approaches though. Hoping to post my project to the Caddx Binding section as a sample at some stage when I have completed the basics.
Thanks again.

Think I’d use a dummy Item, maybe a switch. When update comes in, set switch on. Apply expire binding to switch off, if using fixed delay. If you want a variable delay, use a rules based timer. All this is just a variation of motion activated light.
Then sitemap visibility is simply about the switch on or off.

EDIT - following a different track

Alright, so to put it another way, you have captured alarm events in your static Item states. And you’d like them to go away after a time.
This is classic expire binding job, just apply expire to each Item.

Thank you for the great suggestion. That would be exactly what I wanted… Should have found this earlier - but know for future. The “problem” is the more you do, the more you want to try.

In his OH3 announcement, Kai said

The only change you’ll have to look our for in your rules is the fact that rules now use Java Time API instead of Jodatime, so some expressions need to be slightly adapted.

Could anyone explain what that means to the information in this thread ?
What do we need to change in our working rules ?
How much of Joda will there be left to be used in rules ?

1 Like

Before we change something.
Would it make sense to copy the content of this thread into a new one called DateTimeConversion (openHAB 3.x)?
I would then rename this original thread to DateTimeConversion (openHAB 2.x).
This would not lose any information for users who do not immediately switch to 3.x.

2 Likes

Yes rename it and open a new 3.X thread and link the two.
But only copy what’s relevant (and confirmed to work) to OH3. As of today that’s not clear at least to me it is not.

I’m particularly worried about replacing now, XXX.withTimeAtStartOfDay, XXX.plusMinutes(n) and so on and I think others will be interested, too.

I’ll have to go through all the cases in the OP. It’s on my list of todos. There shouldn’t be too many changes though. Most of the commonly used stuff is the same between the two.

Potentially nothing. There are a few little cases though where you might run into exceptions. I don’t have a list of all errors I would expect you’ll see at this time though.

None. Joda is totally gone and is completely replaced by native Java time classes. However, now is still there and has the plusSeconds et al functions so it should be mostly transparent for you.

plusMinutes should definitely work without change. I’m not 100% positive about withTimeAtStartOfDay. But

now.withHour(0).withMinute(0).withSecond(0)

should be the equivalent. Here is the full JavaDoc for the class.

1 Like

Thanks Rich.
A silly(?) question: how can I use the future Java code in OH2 today rather than Joda ?

now.withHour(0).withMinute(0).withSecond(0)

on current OH 2 (but running Java 11) gives me

2020-10-26 17:54:31.530 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'sage für den Rest des Tages erwartete Strommenge voraus': 'withHour' is not a member of 'org.joda.time.DateTime'; line 309, column 9, length 15

I think you need to do the following.

import java.time.ZonedDateTime

...

    // in a Rule
    val now = ZonedDateTime::now

Note, you can’t use a ZonedDateTime as the time in createTimer in OH 2. You still have to use Joda DateTime for that.

There is an easier way to do this. If you have a ZonedDateTime you can easily update the time using one of the LocalTime constants:

    ZonedDateTime.now().with(LocalTime.MAX)
    ZonedDateTime.now().with(LocalTime.MIDNIGHT)
    ZonedDateTime.now().with(LocalTime.MIN)
    ZonedDateTime.now().with(LocalTime.NOON)

You can already replace Joda-Time in your OH 2.5 rules today with java.time. That’s how I did it and have no issues with time when using the same rules in OH 3.

1 Like

Are you sure?

When I add this to a rule:

import java.time.ZonedDateTime

		//val startOfDay = now.withTimeAtStartOfDay
		val startOfDay = ZonedDateTime.now().with(LocalTime.MIDNIGHT)

… then it errors in VSCode with Type mismatch: cannot convert from LocalTime to TemporalAdjuster.

It might work better if you also:

import java.time.LocalTime

1 Like

I also could not get that one to work either.

Do you rather mean to import java.time ?

And mind we’re in rules DSL so I think I cannot do ZonedDateTime.now() that’s giving errors.
Need to use ZonedDateTime::now. Same likely for the MIDNIGHT literal but no matter what I try it doesn’t work.