# Extract hours, mins from Duration (?)

**URL:** <https://community.openhab.org/t/extract-hours-mins-from-duration/129511>\
**Category:** Scripts & Rules\
**Created:** [December 2, 2021, 8:14pm UTC](https://community.openhab.org/t/extract-hours-mins-from-duration/129511 "2021-12-02T20:14:49Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![norbert\_jordan](https://community.openhab.org/user_avatar/community.openhab.org/norbert_jordan/32/34295_2.png) [@norbert\_jordan](https://community.openhab.org/u/norbert_jordan)\
**Post date:** [December 2, 2021, 8:14pm UTC](https://community.openhab.org/t/extract-hours-mins-from-duration/129511/1 "2021-12-02T20:14:49Z")

</div>

I have a rule that stores the duration of the overall heating process of my central heater…from Start to Stop. Normally it takes a few hours. What i’m already able to see is the following output stored in Delta:

```auto

PT4H6M59.673275S

```

which I guess is 4hours and 6minutes.

IS there a way to extract it into two sepearte variables mins and hours as numbers?

here is the rule simplified to the core, i’m on latest v3 Milestone 4 version of Openhab.

```auto
rule "ETA SH20_Start/Stop Logger"
when
    Item EtaKesselState received update
then
    if (EtaKesselState.state=="Heizen" && EtaState_Switch.state==OFF) {
       EtaStart = now
    else
    if (EtaKesselState.state=="Bereit" && EtaState_Switch.state==ON){
       var EtaDelta = Duration.between(EtaStart, now)
   }
end

```

Thanks a lot for your review,  
Norbert

---

<div class="post-metadata">

**Author:** ![rossko57](https://community.openhab.org/user_avatar/community.openhab.org/rossko57/32/70263_2.png) [@rossko57](https://community.openhab.org/u/rossko57)\
**Post date:** [December 2, 2021, 8:29pm UTC](https://community.openhab.org/t/extract-hours-mins-from-duration/129511/2 "2021-12-02T20:29:13Z")

</div>

Might help

```auto
var myDurationInHours = EtaDelta.toHours // e.g. 136.78
var myDurationJustTheMinutes = EtaDelta.toMinutesPart // e.g. 45
var myDurationString = EtaDelta.format(DateTimeFormatter.ofPattern("HH:mm")

```

---

<div class="post-metadata">

**Author:** ![norbert\_jordan](https://community.openhab.org/user_avatar/community.openhab.org/norbert_jordan/32/34295_2.png) [@norbert\_jordan](https://community.openhab.org/u/norbert_jordan)\
**Post date:** [December 2, 2021, 10:17pm UTC](https://community.openhab.org/t/extract-hours-mins-from-duration/129511/3 "2021-12-02T22:17:25Z")

</div>

Thanks a lot! Norbert

---

<div class="post-metadata">

**Author:** ![norbert\_jordan](https://community.openhab.org/user_avatar/community.openhab.org/norbert_jordan/32/34295_2.png) [@norbert\_jordan](https://community.openhab.org/u/norbert_jordan)\
**Post date:** [December 6, 2021, 9:38pm UTC](https://community.openhab.org/t/extract-hours-mins-from-duration/129511/4 "2021-12-06T21:38:24Z")

</div>

Sorry to bother again, did adapt the rule accordingly…first received an error. After short search i found out quick that i missed a required libraray: import java.time.format.DateTimeFormatter

I thought this was it, but after todays heatup i again receive error messages:  
`Script execution of rule with UID 'eta-1' failed: 'format' is not a member of 'java.time.Duration'; line 24, column 32, length 53 in eta`

The rule simplfied looks like:

```auto
import java.time.Duration
import java.time.format.DateTimeFormatter
var ZonedDateTime EtaStart = null

// ***************************************************************************************************
// ***************************************************************************************************
rule "ETA SH20_Start/Stop Logger"
when
    Item EtaKesselState received update
then
    if (EtaKesselState.state=="Heizen" && EtaState_Switch.state==OFF) {
       EtaStart = now }
    else
    if (EtaKesselState.state=="Bereit" && EtaState_Switch.state==ON){
       var EtaDelta = Duration.between(EtaStart, now)
       var EtaDurationString = EtaDelta.format(DateTimeFormatter.ofPattern("HH:mm"))
       val mailActions = getActions("mail","mail:smtp:gmailsmtp")
       mailActions.sendMail("xxxxxxxxxxxxxxx", "ETA SH20 | Finished " + PufferState.state + "%", "Run-Time: " + EtaDurationString)
    }

```

end

---

<div class="post-metadata">

**Author:** ![rossko57](https://community.openhab.org/user_avatar/community.openhab.org/rossko57/32/70263_2.png) [@rossko57](https://community.openhab.org/u/rossko57)\
**Post date:** [December 6, 2021, 11:11pm UTC](https://community.openhab.org/t/extract-hours-mins-from-duration/129511/5 "2021-12-06T23:11:46Z")

</div>

> [@norbert\_jordan](#):
>
> ‘format’ is not a member of ‘java.time.Duration’;

Yeh, that looks like duff info I found. Good for times but not duration.  
Don’t use that, then.

```auto
// crude
var EtaDurationString = EtaDelta.toHours.toString + ":" + EtaDelta.toMinutesPart.toString

```

Fancier methods here

> <https://stackoverflow.com/questions/266825/how-to-format-a-duration-e-g-format-hmmss/44343699#44343699>

Beware that many suggestions mess up with duration \> 24 hours

---

<div class="post-metadata">

**Author:** ![norbert\_jordan](https://community.openhab.org/user_avatar/community.openhab.org/norbert_jordan/32/34295_2.png) [@norbert\_jordan](https://community.openhab.org/u/norbert_jordan)\
**Post date:** [December 7, 2021, 11:28pm UTC](https://community.openhab.org/t/extract-hours-mins-from-duration/129511/6 "2021-12-07T23:28:24Z")

</div>

hm, I now used the more elegant way you linked above…but still there is a strange error message that does not help me a lot. Any idea what still is not the way it should be…

```auto
2021-12-08 00:22:47.674 [INFO] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model 'eta.rules', using it anyway:
This expression is not allowed in this context, since it doesn't cause any side effects.

2021-12-08 00:23:04.463 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'eta-1' failed: null in eta

```

```auto
rule "ETA SH20_Start/Stop Logger"
when
    Item EtaKesselState received update
then
    if (EtaKesselState.state=="Heizen" && EtaState_Switch.state==OFF) {
       EtaStart = now }
    else
    if (EtaKesselState.state=="Bereit" && EtaState_Switch.state==ON){
       var EtaDelta = Duration.between(EtaStart, now)
       String hms = String.format("%d:%02d:%02d",
                                EtaDelta.toHours(),
                                EtaDelta.toMinutesPart(),
                                EtaDelta.toSecondsPart());
       val mailActions = getActions("mail","mail:smtp:gmailsmtp")
       mailActions.sendMail("xxxxxxxxxxxxxxx", "ETA SH20 | Finished " + PufferState.state + "%", "Run-Time: " + hms)
    }
end

```

---

<div class="post-metadata">

**Author:** ![rossko57](https://community.openhab.org/user_avatar/community.openhab.org/rossko57/32/70263_2.png) [@rossko57](https://community.openhab.org/u/rossko57)\
**Post date:** [December 8, 2021, 1:11am UTC](https://community.openhab.org/t/extract-hours-mins-from-duration/129511/7 "2021-12-08T01:11:17Z")

</div>

> [@norbert\_jordan](#):
>
> `String.format(`

That’s usually written `String::format(` in DSL, I don’t know if that is your problem.

You’ll need to declare `hms` with var or val, too

---

<div class="post-metadata">

**Author:** ![norbert\_jordan](https://community.openhab.org/user_avatar/community.openhab.org/norbert_jordan/32/34295_2.png) [@norbert\_jordan](https://community.openhab.org/u/norbert_jordan)\
**Post date:** [December 8, 2021, 9:41pm UTC](https://community.openhab.org/t/extract-hours-mins-from-duration/129511/8 "2021-12-08T21:41:17Z")

</div>

Thanks. did play arround and struggling with the following error message.

`2021-12-08 22:38:03.644 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'eta-1' failed: null in eta`

even if I remove all new code based on your help its still there…and that is strange

```auto
import java.time.Duration
//import java.time.format.DateTimeFormatter
var ZonedDateTime EtaStart = null

// ***************************************************************************************************
// ***************************************************************************************************
rule "ETA SH20_Start/Stop Logger"
when
    Item EtaKesselState received update
then
    if (EtaKesselState.state=="Heizen" && EtaState_Switch.state==OFF) {
       EtaStart = now
    }
    else
    if (EtaKesselState.state=="Bereit" && EtaState_Switch.state==ON){
       var EtaDelta = Duration.between(EtaStart, now)
// var String hms = String.format("%d:%02d:%02d",
// EtaDelta.toHours(),
// EtaDelta.toMinutesPart(),
// EtaDelta.toSecondsPart());
       val actions = getActions("pushover", "pushover:pushover-account:account")
       actions.sendMessage("Finished in " + EtaDelta +" | " + PufferState.state + "% | " + "["+PUtopTemp.state+"/"+PUobenTemp.state+"/"+PUuntenTemp.state+"]°C", "ETA SH20 | Heating")
       val mailActions = getActions("mail","mail:smtp:gmailsmtp")
       mailActions.sendMail("xxxxxxx", "ETA SH20 | Finished " + PufferState.state + "%", "Run-Time: " + EtaDelta)
    }

```

end

---

<div class="post-metadata">

**Author:** ![rossko57](https://community.openhab.org/user_avatar/community.openhab.org/rossko57/32/70263_2.png) [@rossko57](https://community.openhab.org/u/rossko57)\
**Post date:** [December 8, 2021, 10:16pm UTC](https://community.openhab.org/t/extract-hours-mins-from-duration/129511/9 "2021-12-08T22:16:52Z")

</div>

Use logInfo() to follow progress through your rule, important values, and help identify where it breaks. Finding out beats staring at code.

This looks interesting though -

```auto
var ZonedDateTime EtaStart = null

rule "ETA SH20_Start/Stop Logger"
...
var EtaDelta = Duration.between(EtaStart, now)

```

I can’t see anything stopping you arriving there with EtaStart still `null`.

---

<div class="post-metadata">

**Author:** ![norbert\_jordan](https://community.openhab.org/user_avatar/community.openhab.org/norbert_jordan/32/34295_2.png) [@norbert\_jordan](https://community.openhab.org/u/norbert_jordan)\
**Post date:** [December 9, 2021, 10:33pm UTC](https://community.openhab.org/t/extract-hours-mins-from-duration/129511/10 "2021-12-09T22:33:08Z")

</div>

thanks, will do a better debugging/testing approach.

Only short question, what do you mean by “arriving still null”.  
The rule overall works in a way that first (when heating starts) it will take for sure the IF part and remember a timestamp in EtaStart. Only once as the State\_Switch would lock up so its not going another time in there. As soon as heating is finished it would start the “else if” part and do the duration calculations…

Do you already see an obvious issue i’m having?

Kind REgards Norbert

---

<div class="post-metadata">

**Author:** ![rossko57](https://community.openhab.org/user_avatar/community.openhab.org/rossko57/32/70263_2.png) [@rossko57](https://community.openhab.org/u/rossko57)\
**Post date:** [December 9, 2021, 10:37pm UTC](https://community.openhab.org/t/extract-hours-mins-from-duration/129511/11 "2021-12-09T22:37:15Z")

</div>

> [@norbert\_jordan](#):
>
> it will take for sure the IF part

Well, let’s find out.  
Nothing in the rule as it is written stops it triggering from an update (not a change) of EtaKesselState to “Bereit”, while EtaStart still = null.  
You might have other reasons to think that cannot happen.

---

<div class="post-metadata">

**Author:** ![norbert\_jordan](https://community.openhab.org/user_avatar/community.openhab.org/norbert_jordan/32/34295_2.png) [@norbert\_jordan](https://community.openhab.org/u/norbert_jordan)\
**Post date:** [December 9, 2021, 10:53pm UTC](https://community.openhab.org/t/extract-hours-mins-from-duration/129511/12 "2021-12-09T22:53:03Z")

</div>

OK, sure the rule will be triggered every time EtaKesselState is updated…even if the value does not change…but still the if will not allow any change if conditions are not met.

what i missed and this for sure makes it not easy to follow for you is the fact that inside the if and the else if there will be changed this LOCK\_variable "EtaState\_Switch vice-versa…  
I tried to remove all parts not important but did remove this locking mechanism. Not sure if there is a much better way to handle such behaviour.

```auto
import java.time.Duration
var ZonedDateTime EtaStart = null

rule "ETA SH20_Start/Stop Logger"
when
    Item EtaKesselState received update
then
    if (EtaKesselState.state=="Heizen" && EtaState_Switch.state==OFF) {
       EtaStart = now
       EtaState_Switch.sendCommand(ON) }
    else
    if (EtaKesselState.state=="Bereit" && EtaState_Switch.state==ON){
       var EtaDelta = Duration.between(EtaStart, now)
       EtaState_Switch.sendCommand(OFF)
       val mailActions = getActions("mail","mail:smtp:gmailsmtp")
       mailActions.sendMail("asdfasdfn@live.com", "ETA SH20 | Finished " + PufferState.state + "%", "Run-Time: " + EtaDelta)
    }
end

```

---

<div class="post-metadata">

**Author:** ![norbert\_jordan](https://community.openhab.org/user_avatar/community.openhab.org/norbert_jordan/32/34295_2.png) [@norbert\_jordan](https://community.openhab.org/u/norbert_jordan)\
**Post date:** [December 11, 2021, 10:40pm UTC](https://community.openhab.org/t/extract-hours-mins-from-duration/129511/13 "2021-12-11T22:40:16Z")

</div>

@rossko57 I now did analyze the rule and found out that most of the time it works as it should. nicely.  
Only few times it does not start correctly in the IF part so it never switches ON and so it never stops the ELSE IF part. But as soon as this faulty scenario is done, it again works.

`Script execution of rule with UID 'eta-1' failed: An error occurred during the script execution: Cannot assign a value in null context. in eta`

Without good knowledge about variables being reset (e.g. when rules are changed and their files stored) my assumltion is that this error log messages comes into play…so for whatever reason a NULL issue shows up.Only i do not see any problem, as the IF part does not use EtaStart reading…so its NULL state is irrelevant and set anyway to “NOW”.

Or does this error mean that if the “else if” part would be considerred with NULL there would happen a problem. But in reality this is not going to happen.

Any idea - if this is the issue - how i could overcome this error message in the logs.

Kind Regards  
Norbert

---

<div class="post-metadata">

**Author:** ![rossko57](https://community.openhab.org/user_avatar/community.openhab.org/rossko57/32/70263_2.png) [@rossko57](https://community.openhab.org/u/rossko57)\
**Post date:** [December 12, 2021, 1:20am UTC](https://community.openhab.org/t/extract-hours-mins-from-duration/129511/14 "2021-12-12T01:20:25Z")

</div>

> [@norbert\_jordan](#):
>
> An error occurred during the script execution: Cannot assign a value in null context. in eta

These messages are horrid; you don’t know what’s behind it and must find out. Use the available tools to find out.

> [@norbert\_jordan](#):
>
> Without good knowledge about variables being reset

If you edit the rules file, EtaStart will be null. You told it make it null at the top of your rule file.  
If you edit the rules file, that won’t change any pre-existing Item states.  
Let’s find out.

> [@norbert\_jordan](#):
>
> a NULL issue shows up.

Careful here. A valid Item with a NULL state has little to do with `null` variables. You can of course trip over a null if you do things like trying to get the decimal value of NULL, but that doesn’t look likely here. Let’s find out.

```auto
then
    logInfo("test", "My rule is triggered")
    logInfo("test", "These look important -")
    logInfo("test", "EtaKesselState state -" + EtaKesselState.state.toString)
    logInfo("test", "EtaState_Switch state -" + EtaState_Switch.state.toString)
    logInfo("test", "PufferState state -" + PufferState.state.toString)
    if (EtaStart === null {
        logInfo("test", "EtaStart is null")
    } else {
        logInfo("test", "EtaStart is " + EtaStart.toString)
    }

    if (EtaKesselState.state=="Heizen" && EtaState_Switch.state==OFF) {
       logInfo("test", "Satisfied the first if()")
       EtaStart = now
       EtaState_Switch.sendCommand(ON) }
    else
    if (EtaKesselState.state=="Bereit" && EtaState_Switch.state==ON){
       logInfo("test", "Satisfied the second if()")
       var EtaDelta = Duration.between(EtaStart, now)
       EtaState_Switch.sendCommand(OFF)
       val mailActions = getActions("mail","mail:smtp:gmailsmtp")
       if (mailActions === null {
            logInfo("test", "Failed to get mailActions")
       }
       mailActions.sendMail("asdfasdfn@live.com", "ETA SH20 | Finished " + PufferState.state + "%", "Run-Time: " + EtaDelta)
    } else (
       logInfo("test", "Neither if() satisfied")
    )
end

```
