Formatting a date/time string to use for comparison in a rule

Im really struggling with date/times in Openhab and would love some help. Im using v2.5 on a PI 4

I have an item that is an update string that includes a date in the following format:

“December 7, 2020 at 02:22PM”

What I want to do is only execute a command in a rule if this date/time is later than a previous saved date/time

I can’t see how to turn this string into a useable date time item to allow a comparison to be made.

Any ideas. Sorry if Im being stupid!

Thanks in advance.

What is generating this string? Why is iit string instead of DateTimeType?

It’s coming from an external source updating an item via the rest api. The date time is part of a longer text string that is received and I extract it from the string. I have no control over the input to change its format.

Ah… that makes sense. To go from a formatted string to a DateTimeType, the easiest thing will be to convert from your string to a LocalDateTime using a DateTimeFormatter. Then convert it to a ZonedDateTime by adding timezone information.

// add imports to the top of the rule file
import java.time.format.DateTimeFormatter
import java.time.LocalDateTime
import java.time.ZoneId
...
// in your rule
val initial_time = "December 7, 2020 at 02:22PM"
val zdt = LocalDateTime.parse(initial_time, DateTimeFormatter.ofPattern("MMMM d, yyyy 'at' hh:mma")).atZone(ZoneId.systemDefault())
My_Item.postUpdate(new DateTimeType(zdt).toString())

Thanks, Scott

I’ve tried to use what you suggested but can’t get it to work.

The goal here is to read the latest date time and if it is later than the previous date time that was sent, then update it, otherwise ignore it.

Here’s my rule:

rule "test"
when
    Item test_toggle changed
then
   
    val extract_date_time = google_wifi_Glenn.state.toString.substring(8,google_wifi_Glenn.state.toString.length) // this extracts the date time from the string ie (Home at December 7, 2020 at 02:22PM)
    val extract_date_time_formatted = LocalDateTime.parse(extract_date_time, DateTimeFormatter.ofPattern("MMMM d, yyyy 'at' hh:mma")).atZone(ZoneId.systemDefault())
    val new_time_of_event = new DateTimeType(extract_date_time_formatted).toString()
    

    if(new_time_of_event > google_wifi_Glenn_date_time ) 
    {
        logInfo("Glenn Wifi", "GREATER" ) 
        postUpdate(google_wifi_Glenn_date_time, new_time_of_event) //save the new date time
    }
    else 
    {
        logInfo("Glenn Wifi", "LESS")  //ignore
    }
    
end

But I get en error in the logos

2020-12-08 14:53:32.667 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'test': org.eclipse.smarthome.core.library.items.DateTimeItem cannot be cast to java.lang.String

If I just log the values of the two times im comparing I get this:

new_time_of_event = 2020-12-08T12:57:00.000+0000
google_wifi_Glenn_date_time = (Type=DateTimeItem, State=2020-12-07T11:32:00.000+0000, Label=Glenn last change at, Category=null)

I’ve tried the changing the if statement to add the “state” of the “google_wifi_Glenn_date_time” like this:

if(new_time_of_event > google_wifi_Glenn_date_time.state ).....

But that gives the same error

What am I getting wrong?

Thanks

There were a few things not quite right… try this one…

rule "test"
when
    Item test_toggle changed
then
    val extract_date_time = google_wifi_Glenn.state.toString.substring(8,google_wifi_Glenn.state.toString.length) // this extracts the date time from the string ie (Home at December 7, 2020 at 02:22PM)
    val extract_date_time_formatted = LocalDateTime.parse(extract_date_time, DateTimeFormatter.ofPattern("MMMM d, yyyy 'at' hh:mma")).atZone(ZoneId.systemDefault())
    val new_time_of_event = new DateTimeType(extract_date_time_formatted).toString()
    
    if (extract_date_time_formatted.isAfter(google_wifi_Glenn_date_time.getStateAs(DateTimeType).zonedDateTime)) {
        logInfo("Glenn Wifi", "GREATER") 
        google_wifi_Glenn_date_time.postUpdate(new_time_of_event) //save the new date time
    } else {
        logInfo("Glenn Wifi", "LESS")  //ignore
    }
end

[edit: added missing closing parenthesis]

Thanks a lot, that’s done the job (with the addition of a missing ‘)’ at the end of the if statement)

Thanks for you help, dates are confusing for a novice!

rule "test"
when
    Item test_toggle changed
then
    val extract_date_time = google_wifi_Glenn.state.toString.substring(8,google_wifi_Glenn.state.toString.length) // this extracts the date time from the string ie (Home at December 7, 2020 at 02:22PM)
    val extract_date_time_formatted = LocalDateTime.parse(extract_date_time, DateTimeFormatter.ofPattern("MMMM d, yyyy 'at' hh:mma")).atZone(ZoneId.systemDefault())
    val new_time_of_event = new DateTimeType(extract_date_time_formatted).toString()
    
    if (extract_date_time_formatted.isAfter(google_wifi_Glenn_date_time.getStateAs(DateTimeType).zonedDateTime)) 
    {
        logInfo("Glenn Wifi", "GREATER" ) 
        google_wifi_Glenn_date_time.postUpdate(new_time_of_event) //save the new date time
    } 
    else 
    {
        logInfo("Glenn Wifi", "LESS")  //ignore
    }
end

You are welcome!

Hi again Scott,
One thing I didn’t think of was if the date/times are the same, and this rule will move that to ignore, but I’d actually want that to process it. Is there something to use rather than …isAfter( ) that is equivalent to isAfter or isEqual?

Take a look at the methods available for ZonedDateTime. compareTo looks to do what you want.

Thanks again.