Ephemeris vs. iCal for Birthday counter?

  • Platform information:
    • openHAB version: 4.1.1

as far as I can see there is no year tag inside:

<tns:Fixed month="MARCH" day="27" descriptionPropertiesKey="Son's Birthday" />

And code also has only

Ephemeris.getDaysUntil(alias, test.xml)

I am searching something like Ephemeris.getDaysSince / getYearsSince :wink:
Goal is to add the exact age on every Birthday-Reminder.

PS: unfortunately even Calender dont save the year so that binding is also “no solution”.

Might it be a PR worth for Ephemeris or any other Binding?


The way that Ephemeris works, or to be more specific the way that the JollyDay library it’s built upon, it’s designed to keep track of recurring holidays or recurring types of days that occur every week. It doesn’t really make any sense to add a year to a holiday. Given that the XML file is “owned” by the JollyDay library I don’t see a year being added but you never know. You could file a feature request issue and see what they say. Note that OH 4.2 will bring in a new version of JollyDay.

I thought you could add data to the calendar entry that the iCal binding could parse out and update an Item with. If not, you could put the year in the calendar entry perhaps.

I think your best bet will be to store the actual birthday somewhere: calendar entry name, separate Item, Item metadata, etc. Then it’s a simple calculation to get the number of years.

In JS Scripting, assuming it’s a separate Item, it could look something like this:

var holidayName = actions.Ephemeris.getBankHolidayName(0, '/etc/openhab/ephemeris/birthdays.xml');
if(holidayName !== null) {
  // Assuming the label of the Item storing the actual date matches the descriptionPropertiesKey in the XML
  const dtItem = items.getItems().filter( item => item.label == holidayName)[0];
  const delta = time.Duration.between(time.toZDT(dtItem), time.toZDT());
  const numYears = delta.get(time.ChronoUnit.YEARS);

Ok, simply played…

var marie, date, d, y, cleanedM, cleanedD, M;

// Get in informative String build out of datetime.
function age(date) {
  d = (time.ChronoUnit.DAYS.between(date,(time.ZonedDateTime.now())));
  y = (time.ChronoUnit.YEARS.between(date,(time.ZonedDateTime.now())));
  M = (time.ChronoUnit.MONTHS.between(date,(time.ZonedDateTime.now())));
  cleanedM = (time.ChronoUnit.MONTHS.between(date,time.ZonedDateTime.now().minusYears(y)));
  cleanedD = (time.ChronoUnit.DAYS.between(date,time.ZonedDateTime.now().minusMonths(M)));
  return [y,' Jahre ',cleanedM,' Monate ',cleanedD,' Tage.','\r\n','Oder auch:',d,' Tage.','\r\n','Dieses Jahr wird es ein ',date.plusYears(y + 1).format(time.DateTimeFormatter.ofPattern('E'))].join('');

marie = (time.toZDT(items.getItem('birthday_marie')));

But what might wront with the formater?


PolyglotException: p: Pattern using (localized) text not implemented, use @js-joda/locale plugin!

Found this: How to use DateTimeFormatter.ofPattern in ECMA 2021 openhab rules

Just call this line (and restart OH):

npm i @js-joda/locale_de

Does not fix the problem. Any Suggestions?

There is a challenge with joda-js, the underlying library that implements everything you find under time. To include all the locale stuff would be many megabytes of additional data, most of which is not used for most users. So the Helper Library doesn’t ship with every locale.

You’ll also need to import it into your rule too using a require.

var Locale = require('@joda-js/locale_de').Locale.GERMANY;

Then if time.DateTimeFormatter doesn’t recognize the locale automatically you’ll want to use the LocaleDatetimeFormatter.

var Locale = require('@js-joda/locale_de').Locale.GERMANY;

Cannot load CommonJS module: ‘@js-joda/locale_de’

Maybee you have another hint for me :upside_down_face:

According to the example here, maybe you need to instantiate the Locale.

I’ve never had to directly fight with these locale options so all I really know I’m pulling from the docs.