DateTime Conversion (openHAB 3.x)

It seems I’ve just solved the issue with the script above (@Malti1812 )

if you have a specific date (eg. Christmas is 12/25) you can use:

(dayOfYear==LocalDate.of(year, 12, 25).getDayOfYear)

If you need do some maths around Eastern Sunday, something like this should do the trick:

...
    var int year = now.getYear()
    var int a = year % 19
    var int b = year / 100
    var int c = year % 100
    var int d = b / 4;
    var int e = b % 4;
    var int f = (b + 8) / 25;
    var int g = (b - f + 1) / 3;
    var int h = (19 * a + b - d - g + 15) % 30;
    var int i = c / 4;
    var int k = c % 4;
    var int L = (32 + 2 * e + 2 * i - h - k) % 7;
    var int m = (a + 11 * h + 22 * L) / 451;
    var int month = (h + L - 7 * m + 114) / 31;
    var int day = ((h + L - 7 * m + 114) % 31) + 1
...
var easterSunday = LocalDate.of(year, month, day)
var int dayOfYear = now.getDayOfYear()
...
(dayOfYear==easterSunday.getDayOfYear-2)

this is for Good Friday.

Hope this helps
Andrea

It’s worth noting that most of this sort of thing can be handled by Ephemeris. If the default configuration for your country and region doesn’t use the right calculation (e.g. you live in the US but follow the Eastern calculation for Easter) you can create a custom config that uses the right calculation.

Then in a rule you can just use the Ephemeris Actions.

    // If today is Christmas
    if(getBankHolidayName == "CHRISTMAS")

    // How many days until Easter?
    logInfo("Easter", "Easter is " + getDaysUntil("EASTER") + " days away.")

    // Is today a holiday?
    if(isBankHoliday)

    // Is today the weekend?
    if(isWeekend)

Most of the Christian (latin, eastern, even Ethiopian Orthodox), Islamic, and Jewish holidays are supported. There are a couple of Hindu holidays that are not on fixed days of the solar year also supported.

These can also be used in But only if… conditions and rule triggers in UI Rules so certain rules only run on holidays and others never run on holidays. You can even provide offsets, such as only running a rule if tomorrow is a holiday and the like. You’ll have to use a Script Condition though if you want to test for specific holidays.

Also note it supports daysets so instead of needing to test whether today is between 1-5 you can just test for isWeekend.

2 Likes
  1. As your rule is triggering only at 5 pm or 8 pm, your first if condition will never be true. (maybe you changed something?)
  2. I’m not sure about DateTime as var (I’m pretty sure you want to use it as a DateTime Item Type, which could work, but I’m not sure about the key word)
  3. return has to have a ; at the end - because otherwise the next word will be used as the return value, which can’t be delivered… the meaning of return; is: “make a break and no return value at all”
  4. as the var nachricht will never be empty, the last if condition will always be true.
  5. I’m not sure about the double {} either. Maybe better to use () instead of the outer {} in log Command.
  6. You should NOT use logError at all, as the messages aren’t Error Messages. Please be aware that frontail has a filter function, this is much better then misusing the color codes :wink:
  7. you should consider to change the Item names. Then it’s possible to write a much shorter rule by using a group item.

If defining the Item names like this:

Group events
String event_name_tomorrow_1 (events)
String event_name_tomorrow_2 (events)
String event_name_tomorrow_3 (events)
String event_name_today_1 (events)
String event_name_today_2 (events)
String event_name_today_3 (events)

this rule should do the job:

val telegramAction = getActions("telegram","telegram:telegramBot:FS6")

rule "Abfallkalender"
when
    Time cron "0 1 17 ? * MON-SAT" or
    Time cron "0 0 20 ? * MON-SAT"
then
    val String nachricht = "Heute "
	if (ZonedDateTime.now.getHour > 17) {
		nachricht = "Morgen "
	}
	nachricht += "wird folgender Müll geholt: "
    events.members.filter[j|j.name.contains(if(ZonedDateTime.now.getHour > 17) "tomorrow" else "today")].sortBy[name].forEach[i|
        if(i.name.split("_").get(3) == "1" && i.state == UNDEV) {
			logInfo("waste", "Kalender rules: Event1 UNDEV; Heute kein Müll ({})", i.state)
			return;
		}
		val titel = i.state.toString
		if(titel.length>=3 && titel.startsWith("EB ")){
			nachricht = nachricht + if(i.name.split("_").get(3) == "1") "" else ", " + titel.substring(3, titel.length)
	]
	logInfo("waste", "Kalender rules: {}", nachricht)
	telegramAction.sendTelegram(nachricht)
	say(nachricht, "picotts:deDE", "sonos:One:Wohnzimmer")
end
2 Likes

The Class names are basically the Item type with “Item” appended. So you’d have DateTimeItem, SwitchItem, RollershutterItem, and so on.

This is the first time I ever thought about why the ; is required. That makes perfect sense! I learned something today. :smiley:

1 Like

Wow. That’s a star in my calender and I rose an inch (I swear!) :wink:

I have tried to use this method to convert a string such as 2021-03-18T17:50:21.364Z extracted from a JSON response using this rule [extract]

logWarn("rules.Oculus", " Timestamp: "+timestamp)
var Number epoch = new DateTime(timestamp).millis       // Convert to number

and I get:

2021-03-27 11:21:01.979 [WARN ] [enhab.core.model.script.rules.Oculus] -  Timestamp: 2021-03-18T17:50:21.364Z
2021-03-27 11:21:01.982 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'oculus-1' failed: An error occurred during the script execution: null in oculus

I have searched across the forum and I can’t see a solution. I don’t think I need to import anything for this to work?

1 Like

I need to ask again since I still struggle with time Zoned epoch time:

I need the current epoch in seconds for the current time and not the UTC time.
When I use this:

var newDate = new DateTimeType().getZonedDateTime().toInstant.toEpochMilli / 1000

I get the epoche time but for UTC time even though my computer is set to the correct time date etc:

[08:43:03] root@openhab:~# timedatectl
                      Local time: Sun 2021-03-28 08:43:04 CEST
                  Universal time: Sun 2021-03-28 06:43:04 UTC
                        RTC time: n/a
                       Time zone: Europe/Berlin (CEST, +0200)
       System clock synchronized: yes
systemd-timesyncd.service active: yes
                 RTC in local TZ: no

So how do I get the epoch time in seconds for the correct time zone?

Andy

That’s what epoch means,it’s always UTC in this context.
You could adjust it yourself with an offset, add 2 hours worth of seconds.

hmm ok but since we have Daylight saving time how do I know if I need to add +2 or just +1 hour?

I think you can ask your original ZonedDateTime using .getOffset()

great thx a lot now its working!

I am reading an xml URL where I read an Epoch value 1617982380
Type string : start_1 [stateTransformation=“XPath:/e2eventlist/e2event[2]/e2eventstart/text()”]
is it possible to convert this epoch directly to datetime or something similar? Or is it necessary to create an epoch Item as well linked to this channel and a datetime Item which needs to be updated by a rule?

Who can say. Which binding is involved, which OH version?
OH3 HTTP binding allows for chained transformations. That would allow to use a JS to convert an epoch into a readable date-time for a OH DateTime Item.

Yes, it is the HTTP Binding with OH3. So how is it possible to change it directly?

Well, if you look at the binding docs you will see that you can chain one transformation after another, using a magic “∩”.character.
So you could use XPATH to extract the epoch, which could be passed to a JS javascript, that then parsed the epoch and converted to ISO text.

But, um, you do know you can post an epoch value directly to a DateTime type Item?

1 Like

Thank you. It is working directly.
In my thing it is now a number:

     Type number :   start_1          [ stateTransformation="XPath:/e2eventlist/e2event[2]/e2eventstart/text()"]

And my item is a DateTime
DateTime EPGStart1 “String channel” {channel=“http:url:EPG:start_1”}

But I recognized that it is GMT. Is there also a possibility to change it directly to a specific timezone?

You started with an epoch. Epoch simply have no zone and are always UTC, so that’s how the DateTime interprets it.
What’s your objective, display in local time or actually force a faked zone into the Item state?

I would like to have a faked zone in the item state, so the item itself is having the same time like my openhab. So the item state is the one i my local timezone.

I know I can display my local time with Startzeit [%1$tH:%1$tM], but unfortunatly this is not sufficiant for me.

Have you investigated what happens when you do that? So far as I know, openHAB willconvert stored DateTimes to your local zone before formatting for display.

Unfortunately it is not storing in the local zone:
image

image

image
Only the UI is showing the local time