DateTime Conversion (openHAB 3.x)

I believe you want to determine the holiday, so you also need stAdvent. I’ am not really sure if it is in the best way, but it works for me

var LocalDate easterSunday =  ZonedDateTime.parse(year + "-" + month +"-" + day + "T00:00:00.000Z").toLocalDate()
var LocalDate stAdvent = ZonedDateTime.parse(year + "-12-25T00:00:00.000Z").minusDays(ZonedDateTime.parse(year + "-12-25T00:00:00.000Z").getDayOfWeek.getValue + 21).toLocalDate()

Thanks for the quick answer, I’ll test it and then mess it up

unfortunately I get an error at stAdvent
The value of the local variable stAdvent is not used (org.eclipse.xtext.xbase.validation.IssueCodes.unused_local_variable)

That’s typically no error but a warning. You declared a variable (stAdvent) but did never use it. You can either just ignore it or use the variable in your rule. If you don’t use it, you can also delete it, since it makes no sense declaring a variable that is never used.

Thank you, ok

Here is the bit of the rule I think you are interested in…converts a time stamp string to Epoch to enable time calculations. Does not use the formatter but uses brute force to get timestamp into ISO8601 format.

rule "Heat pump return sensor 1 time stamp check"
when
    Item MobileAlertsHeatPumpReturnSensorTimestamp received update
then
    val String timestamp_str = MobileAlertsHeatPumpReturnSensorTimestamp.state.toString //from http cache and REGEX transform

    val Number string_length =  timestamp_str.length
    if (string_length < 30) {

        //Format string to ISO8601 stanard to for conversion to Epoch milliseconds
        //logInfo("Mobile Alerts" , "<<<<<<< timestamp_str >>>>>>> = " + timestamp_str)

        val timestamp_divided = timestamp_str.split(" ")
        val date_str = timestamp_divided.get(0)
        val time_str = timestamp_divided.get(1)
        val meridiem_str = timestamp_divided.get(2)

        val date_divided = date_str.split("\\/")
        var daydate_str = date_divided.get(1) //Can be eg 1 or 11
        val daydate_length =  daydate_str.length
        var month_str = date_divided.get(0) //Can be eg 1 or 11
        val month_length =  month_str.length
        val year_str = date_divided.get(2)

        val time_divided = time_str.split(":")
        var hour_str = time_divided.get(0) //Can be eg 1 or 11
        var Number hour_number = Integer::parseInt(hour_str) //Convert hour String to Number
        val minutes_str = time_divided.get(1)
        val seconds_str = time_divided.get(2)
        
        //logInfo("Mobile Alerts" , "1 Split time: " + hour_str + " Hours " + minutes_str + " Minutes "  + seconds_str + " Seconds " + meridiem_str + " Meridien" )

        //Convert Meridien time to 24hr format
        if (meridiem_str == "PM" && hour_number != 12) {
            hour_number = hour_number + 12
        }

        //Add leading zeros if necessary
        //Hour
        if (hour_number < 10) {
            hour_str = "0" + hour_number
        }
        else {
            hour_str = hour_number.toString
        }
        //Day
        if (daydate_length == 1) {
            daydate_str = "0" + daydate_str
        }
        //Month
        if (month_length == 1) {
            month_str = "0" + month_str
        }

        //Re-assemble date and time to ISO 8601 formatted String
        val timestamp_iso8601 = new String(year_str + "-" + month_str + "-" + daydate_str + "T" + hour_str + ":" + minutes_str + ":" + seconds_str + ".000+01:00")
        logInfo("Mobile Alerts" , "1 ISO formatted timestamp = " + timestamp_iso8601)

        //https://community.openhab.org/t/datetime-conversion-openhab-3-x/107197  

        //Convert String to to datetime type. Method #01
        val DateTimeType DateTimeTypeFromString = DateTimeType.valueOf(timestamp_iso8601)
        //logInfo("Mobile Alerts" , "DateTime from String = " + DateTimeTypeFromString)

        //Convert Datetime type to Epoch millis. Method #08 variant A
        val Number timestamp_epoch = (DateTimeTypeFromString).zonedDateTime.toInstant.toEpochMilli 
        //logInfo("Mobile Alerts" , "Epoch from DateTime variant A = " + timestamp_epoch)

        //Calulculate elapsed time since timestamp
        val Number currenttime = now.toInstant().toEpochMilli()
        val Number elapsedtime_minutes = (currenttime - timestamp_epoch)/60000 //minutes
        //logInfo("Mobile Alerts" , "Elapsed time mins = " + elapsedtime_minutes)
        val Number elapsedtime_hours = elapsedtime_minutes/60 //hours

        logInfo("Mobile Alerts" , "1 Heat pump return sensor last seen " + String::format("%.1f", elapsedtime_hours) + " hrs ago")

Perfect thx a lot. now my rule is working again, great

Would someone be able to tell me what I’m doing wrong. Have been stuck on this for ages. I’m trying to parse an almost ISO format string into a DateTime item but get the error Text ‘2021-01-16 20:05:10 +0000’ could not be parsed at index 20 in …

var String str = "2021-01-16 20:05:10 +0000"
var formatter = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z");
postUpdate( ApcDate, ZonedDateTime.parse( str, formatter ) )

Thanks

I managed to get it working. It’s a bit messy with some string replaces to make it an ISO date. I had hoped to use the DateTimeFormatter, but oh well it works.

var String str = "2021-01-16 20:05:10 +0000"
str = str.replace(" +0000","+00:00").replace(" ","T")
postUpdate( str )

I am having troubles getting my head around these DateTime conversions.
Really want to migrate from 2 to 3 and have one remaining rule to convert.

now.plusMinutes(30).isBefore((ASTRO_SUNRISE_TIME.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)

I tried various attempts but keep getting errors :frowning:

Well you could use:

var sunrise = (Sunrise_Time.state as DateTimeType).getZonedDateTime()
sunrise.isBefore(now.minusMinutes(240))

or you convert (not tested):

now.plusMinutes(30).isBefore(sunrise.toInstant.toEpochMilli)

hth

1 Like

I had the same problem converting from 2.5 to 3.

This worked for me:

val sunset = (LocalSun_Set_EndTime.state as DateTimeType).getZonedDateTime()
        val sunrise = (LocalSun_Rise_StartTime.state as DateTimeType).getZonedDateTime()
        if (now.plusMinutes(30).isAfter(sunset) || now.isBefore(sunrise)) {
        

Or in one line:

if (now.plusMinutes(30).isAfter(new sunset (LocalSun_Set_EndTime.state as DateTimeType).getZonedDateTime()) || now.isBefore(new sunset (LocalSun_Rise_StartTime.state as DateTimeType).getZonedDateTime())) {```

Hello to all and good afternoon,

Yesterday migrated to OH3 and I am loving it. I stumbled across some things regarding ZonedDateTime. I elaborated a simle rule in jython just as an example to whta I want to do that is do a simple postUpdate to a DateTime item like this:

from core.rules import rule
from core.triggers import when
from java.time import ZonedDateTime as DateTime

@rule("JythonLightControlTestRule", description="Jython Light Control Test Rule", tags=["admin"])
@when("Item SwitchLightsControlShortJython changed")
def jython_light_control_test_rule(event):
    now = DateTime.now()
    timeout = 10
    if event.itemState == ON:
        events.postUpdate(ir.getItem("DateTimeLightsControlLampJythonTimeoutControlLastUpdate"), str(now.plusSeconds(timeout)))

The issue is that the now.plusSeconds(timeout), if I print it out to the log it get’s printed with the timezone like this:

2021-01-30 15:51:26.017 [INFO ] [23.jython.JythonLightControlTestRule] - 2021-01-30T15:51:36.006681Z[Europe/Lisbon]

Afterwards I get an error:

IllegalArgumentException: java.lang.IllegalArgumentException: The argument 'state' must not be null.

This is for sure some simple conversion necessary, but from all the atemps I read I did not get there yet.

Could someone be so kind and give ma hand on this, please?

Thank you very much in advanced.

Hello again,

I found a way that work, do not know if it is the most correct one but it works, By adding .toLocalDateTime() in postUpdate it works now:

from core.rules import rule
from core.triggers import when
from java.time import ZonedDateTime as DateTime

@rule("JythonLightControlTestRule", description="Jython Light Control Test Rule", tags=["admin"])
@when("Item SwitchLightsControlShortJython changed")
def jython_light_control_test_rule(event):
    now = DateTime.now()
    timeout = 10
    if event.itemState == ON:
        events.postUpdate(ir.getItem("DateTimeLightsControlLampJythonTimeoutControlLastUpdate"), str(now.plusSeconds(timeout).toLocalDateTime()))

Thanks.

My rule looks like this:

from core.rules import rule
from core.triggers import when
from core.actions import ScriptExecution
from java.time import ZonedDateTime as DateTime

@rule("Turn on ZWaveNode089FGS222DoubleRelaySwitch2X15KWSwitchBinary1 after motion sensor is triggered", description="Turn on Flood light after motion is detected", tags=["Tag 1", "Tag 2"])
@when("Item ZWaveNode104SP816SP816MotionSensorAlarmMotion changed")
def ZWaveNode104SP816SP816MotionSensorAlarmMotion(event):
    if items["Naplemente_Kapcsolo"] == ON and items["Overwind"] == OFF:
        if items["ZWaveNode104SP816SP816MotionSensorAlarmMotion"] == ON:
            events.sendCommand("ZWaveNode089FGS222DoubleRelaySwitch2X15KWSwitchBinary1", "ON")
            ScriptExecution.createTimer(DateTime.now().plusSeconds(120), lambda:(ZWaveNode104SP816SP816MotionSensorAlarmMotion_2(OFF)))

def ZWaveNode104SP816SP816MotionSensorAlarmMotion_2(event):
    if items["ZWaveNode104SP816SP816MotionSensorAlarmMotion"] == OFF:
        events.sendCommand("ZWaveNode089FGS222DoubleRelaySwitch2X15KWSwitchBinary1", "OFF")
    else: ZWaveNode104SP816SP816MotionSensorAlarmMotion(ON)

Hello @kovacsi2899 ,

Thanks for your input and for sharing your rule.

Best regards.

Hello, I am currently migrating from OpenHAB 2.5 to 3.0. I really like the semantic model but I am struggling with migrating from Jodatime to Java Time API. I am not a programmer and guess there is a trivial solution. How do I translate these few lines?

var Number hour = now.getHourOfDay
var Number day = now.getDayOfWeek
var Number month = now.getMonthOfYear

Thanks so much!

Hello,

Take a look at this post:

I think it will help with what you are looking for.

Best regards

Thanks, it works for

now.getMonthValue
now.getHour

what I am missing is the day of the week either as a number or name.

Take a look at this thread:

I think it can help you.

Best regards.