iobroker.feiertage
Version:
282 lines (243 loc) • 10.6 kB
JavaScript
'use strict';
const utils = require('@iobroker/adapter-core');
const holidays = require('./admin/holidays').holidays; // Get common adapter utils
const adapterName = require('./package.json').name.split('.').pop();
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
class Feiertage extends utils.Adapter {
constructor(options) {
super({
...options,
name: adapterName,
useFormatDate: true,
});
this.lang = 'de';
this.on('ready', this.onReady.bind(this));
this.on('unload', this.onUnload.bind(this));
}
async onReady() {
const data = await this.getForeignObjectAsync('system.config');
if (data && data.common) {
this.lang = data.common.language;
this.log.debug(`Using language "${this.lang}" from system config`);
}
await this.checkHolidays();
this.stop();
}
// check the holidays
async checkHolidays() {
if (!this.readSettings()) {
this.log.error('No holiday is enabled');
return false;
}
const now = new Date();
let year = now.getFullYear();
let isLeap = this.getIsLeap(year);
// Easter sunday: day of the year
let easter = this.getEastern(year);
// Day of the year
const todayStart = new Date(now.setHours(0, 0, 0, 0));
const newYear = new Date(year, 0, 1);
const diffDays = (todayStart.getTime() - newYear.getTime()) / ONE_DAY_MS + 1;
let day = Math.ceil(diffDays);
const todayIs = Math.ceil(diffDays);
// 4th advent (sunday before first christmas day)
let advent4 = this.getAdvent4(year);
// today (day)
let hd = this.getHoliday(day, isLeap, easter, advent4, year);
this.setState('heute.Name', { ack: true, val: this.getHoliday(day, isLeap, easter, advent4, year, 'de') });
this.setState('heute.boolean', { ack: true, val: !!hd });
this.setState('today.name', { ack: true, val: hd });
this.setState('today.boolean', { ack: true, val: !!hd });
// tomorrow (tommo)
let tommo = day + 1;
let tommoYear = year;
let tommoIsLeap = isLeap;
let tommoEaster = easter;
let tommoAdvent4 = advent4;
if (tommo > 365 + isLeap) {
tommo = 1;
}
if (tommo < todayIs) {
tommoYear++;
tommoIsLeap = this.getIsLeap(tommoYear);
tommoEaster = this.getEastern(tommoYear);
tommoAdvent4 = this.getAdvent4(tommoYear);
}
hd = this.getHoliday(tommo, tommoIsLeap, tommoEaster, tommoAdvent4, tommoYear);
await this.setStateAsync('morgen.Name', {
ack: true,
val: this.getHoliday(tommo, tommoIsLeap, tommoEaster, tommoAdvent4, tommoYear, 'de'),
});
await this.setStateAsync('morgen.boolean', { ack: true, val: !!hd });
await this.setStateAsync('tomorrow.name', { ack: true, val: hd });
await this.setStateAsync('tomorrow.boolean', { ack: true, val: !!hd });
// the day after tomorrow (datommo)
let datommo = day + 2;
let datommoYear = year;
let datommoIsLeap = isLeap;
let datommoEaster = easter;
let datommoAdvent4 = advent4;
if (datommo > 365 + isLeap) {
datommo = 2;
}
if (datommo < todayIs) {
datommoYear++;
datommoIsLeap = this.getIsLeap(datommoYear);
datommoEaster = this.getEastern(datommoYear);
datommoAdvent4 = this.getAdvent4(datommoYear);
}
hd = this.getHoliday(datommo, datommoIsLeap, datommoEaster, datommoAdvent4, datommoYear);
await this.setStateAsync('uebermorgen.Name', {
ack: true,
val: this.getHoliday(datommo, datommoIsLeap, datommoEaster, datommoAdvent4, datommoYear, 'de'),
});
await this.setStateAsync('uebermorgen.boolean', { ack: true, val: !!hd });
await this.setStateAsync('aftertomorrow.name', { ack: true, val: hd });
await this.setStateAsync('aftertomorrow.boolean', { ack: true, val: !!hd });
// next holiday
let duration = 0;
do {
day++;
if (day > 365 + isLeap) {
day = 1;
}
duration = duration + 1;
hd = this.getHoliday(day, isLeap, easter, advent4, year);
if (hd) {
if (day < todayIs) {
year++;
isLeap = this.getIsLeap(year);
easter = this.getEastern(year);
advent4 = this.getAdvent4(year);
}
const date = this.getDateFromYearsDay(day, year);
await this.setStateAsync('naechster.Name', {
ack: true,
val: this.getHoliday(day, isLeap, easter, advent4, year, 'de'),
});
await this.setStateAsync('next.name', { ack: true, val: hd });
const nextHoliday = this.formatDate(date);
this.log.info(`Next holiday: ${hd} is in ${duration} days on ${nextHoliday}`);
await this.setStateAsync('naechster.Datum', nextHoliday, true);
await this.setStateAsync('next.date', nextHoliday, true);
await this.setStateAsync('naechster.Dauer', duration, true);
await this.setStateAsync('next.duration', duration, true);
break;
}
} while (!hd);
this.log.info('all objects written');
return true;
}
readSettings() {
let isOneEnabled = false;
for (const h in holidays) {
holidays[h].enabled =
this.config[`enable_${h}`] !== undefined
? this.config[`enable_${h}`] === true || this.config[`enable_${h}`] === 'true'
: holidays[h].enabled;
if (holidays[h].enabled) {
isOneEnabled = true;
}
}
return isOneEnabled;
}
// Get the name of holiday for the day of the year
getHoliday(day, isLeap, easter, advent4, year, _lang) {
_lang = _lang || this.lang;
for (const h in holidays) {
if (holidays[h].enabled) {
if (
holidays[h].offset !== 'undefined' &&
1 + holidays[h].offset + (holidays[h].offset >= 59 ? isLeap : 0) === day
) {
return (
holidays[h][_lang] +
(holidays[h][`comment_${_lang}`] ? ` ${holidays[h][`comment_${_lang}`]}` : '')
);
}
if (holidays[h].easterOffset !== 'undefined' && easter + holidays[h].easterOffset === day) {
return (
holidays[h][_lang] +
(holidays[h][`comment_${_lang}`] ? ` ${holidays[h][`comment_${_lang}`]}` : '')
);
}
if (holidays[h].advent4Offset !== 'undefined' && advent4 + holidays[h].advent4Offset === day) {
return (
holidays[h][_lang] +
(holidays[h][`comment_${_lang}`] ? ` ${holidays[h][`comment_${_lang}`]}` : '')
);
}
if (holidays[h].april30Offset !== 'undefined') {
const newYear = new Date(year, 0, 1);
const april30date = new Date(year, 3, 30, 0, 0, 0);
const april30num = Math.ceil((april30date.getTime() - newYear.getTime()) / ONE_DAY_MS + 1);
const mday = april30num - april30date.getDay() + holidays[h].april30Offset;
if (mday === day) {
return (
holidays[h][_lang] +
(holidays[h][`comment_${_lang}`] ? ` ${holidays[h][`comment_${_lang}`]}` : '')
);
}
}
if (holidays[h].michaelisOffset !== 'undefined') {
const newYear = new Date(year, 0, 1);
const michaelisDate = new Date(year, 8, 29, 0, 0, 0);
const michaelisNum = Math.ceil((michaelisDate.getTime() - newYear.getTime()) / ONE_DAY_MS + 1);
if (michaelisNum + (holidays[h].michaelisOffset - michaelisDate.getDay()) === day) {
return (
holidays[h][_lang] +
(holidays[h][`comment_${_lang}`] ? ` ${holidays[h][`comment_${_lang}`]}` : '')
);
}
}
}
}
return '';
}
getDateFromYearsDay(day, year) {
const dayMs = (day - 1) * ONE_DAY_MS; // Day of the year in ms from 01.01 00:00:00
const newYear = new Date(year, 0, 1, 0, 0, 0, 0); // This year 01.01 00:00:00
const newYearMs = newYear.getTime();
const date = new Date();
date.setTime(newYearMs + dayMs); // Add to current New year the ms
return date;
}
getIsLeap(year) {
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0 ? 1 : 0;
}
getEastern(year) {
// The modified Gauss-Formula to calculate catholic eastern, valid till 2048
const A = 120 + ((19 * (year % 19) + 24) % 30);
const B = (A + Math.floor((5 * year) / 4)) % 7;
// Easter sunday: day of the year
return A - B - 33 + this.getIsLeap(year);
}
getAdvent4(year) {
// 4th advent (sunday before first christmas day)
const newYear = new Date(year, 0, 1);
const christmas1 = new Date(year, 11, 25, 12, 0, 0);
const advent4date = new Date(
christmas1.getTime() - (!christmas1.getDay() ? 7 : christmas1.getDay()) * ONE_DAY_MS,
);
return Math.ceil((advent4date.setHours(0, 0, 0, 0) - newYear.getTime()) / ONE_DAY_MS + 1);
}
onUnload(callback) {
try {
this.log.debug('cleaned everything up...');
callback();
} catch {
callback();
}
}
}
// @ts-expect-error parent is a valid property on module
if (module.parent) {
// Export the constructor in compact mode
/**
* @param {Partial<utils.AdapterOptions>} [options] - The adapter options
*/
module.exports = options => new Feiertage(options);
} else {
// otherwise start the instance directly
new Feiertage();
}