-
-
Save jterrace/f412fdfac90687719cf3016ff968cc0b to your computer and use it in GitHub Desktop.
// Formats the given Date and returns map with format string parts. | |
const makeTimeFormatMap = function(date) { | |
const tz = Intl.DateTimeFormat().resolvedOptions().locale; | |
const dateTimeFormat = new Intl.DateTimeFormat(tz, { | |
month: 'short', | |
day: 'numeric', | |
weekday: 'short', | |
hour: 'numeric', | |
minute: 'numeric', | |
hour12: true, | |
}); | |
const partsMap = {}; | |
dateTimeFormat.formatToParts(date).map(({type, value}) => { | |
partsMap[type] = value | |
}) | |
partsMap.dayPeriod = partsMap.dayPeriod[0].toLowerCase(); | |
return partsMap; | |
}; | |
// Makes a Date from a date/time string. | |
const makeDate = function(dateString) { | |
if (dateString.includes("T")) { | |
return new Date(dateString); | |
} | |
// All day events just show up as "YYYY-MM-DD" with no | |
// time zone, so parse manually to make sure it's in "local" | |
// time zone. | |
var b = dateString.split(/\D/); | |
return new Date(b[0], b[1]-1, b[2]); | |
}; | |
// Returns an array of dates between the two time strings. | |
const getDaysArray = function (start, end) { | |
const days = []; | |
for (var dt = makeDate(start); dt <= makeDate(end); dt.setDate(dt.getDate() + 1)) { | |
days.push(new Date(dt)); | |
} | |
return days; | |
}; | |
const addEvent = function(events_by_date, date, dateStr, eventValue) { | |
events_by_date[date] = events_by_date[date] || {dateStr: dateStr, events: []}; | |
if (eventValue === null) return; | |
events_by_date[date].events.push(eventValue); | |
}; | |
const today = new Date(new Date().toDateString()); | |
const todayParts = makeTimeFormatMap(today); | |
const todayStr = `${todayParts.weekday} ${todayParts.month} ${todayParts.day}`; | |
const by_date = {}; | |
addEvent(by_date, today, todayStr, null); | |
for (const [calname, cal] of Object.entries(msg.payload)) { | |
for (const event of cal.events) { | |
const days = getDaysArray(event.start, event.end); | |
node.warn(days); | |
if (days.length == 1) { | |
const ts = days[0]; | |
const formatParts = makeTimeFormatMap(ts); | |
const dateStr = `${formatParts.weekday} ${formatParts.month} ${formatParts.day}`; | |
const timeStr = `${formatParts.hour}:${formatParts.minute}${formatParts.dayPeriod}`; | |
const dayDate = new Date(ts.toDateString()); | |
addEvent(by_date, dayDate, dateStr, timeStr + ' ' + event.summary); | |
continue; | |
} | |
// Multi day events end at midnight the day after, lop it off. | |
days.pop(); | |
for (const day of days) { | |
const dayDate = new Date(day.toDateString()); | |
if (dayDate < today) continue; | |
const formatParts = makeTimeFormatMap(day); | |
const dateStr = `${formatParts.weekday} ${formatParts.month} ${formatParts.day}`; | |
addEvent(by_date, dayDate, dateStr, event.summary); | |
} | |
} | |
} | |
node.warn(by_date); | |
const drawPayloads = []; | |
var largeSize = 30; | |
const sortedByDate = [...Object.keys(by_date)].sort(function (a, b) { | |
const x = new Date(a); | |
const y = new Date(b); | |
return x < y ? -1 : x > y ? 1 : 0; | |
}); | |
for (const dt of sortedByDate) { | |
drawPayloads.push( | |
{ | |
type: "text", | |
value: by_date[dt].dateStr, | |
font: "ppb.ttf", | |
x: 5, | |
size: largeSize, | |
color: "red" | |
}); | |
largeSize = 25; | |
if (by_date[dt].events.length > 0) { | |
drawPayloads.push( | |
{ | |
type: "multiline", | |
value: by_date[dt].events.join('|'), | |
delimiter: '|', | |
font: "rbm.ttf", | |
offset_y: 30, | |
x: 10, | |
size: 20, | |
y_padding: 5, | |
color: "black", | |
anchor: "la" | |
}); | |
} | |
} | |
node.warn(drawPayloads); | |
return {payload: drawPayloads }; |
and an other question is, if i can impement a second calender
Just updated the script with a few changes I've made that weren't posted. You can add multiple entities to fetch with the calendar.get_events. Here you can see I have both my family calendar and holidays. And yes, you have to add the msg.payload output property now:
For 24 hour time, change hour12: true
to hour12: false
.
As for the language/locale, I'm not sure how node red pulls that information into the nodejs context, so I don't think I can help there.
Dear Jeff. Thanks a lot for the new skript...the both (or more?) calender words great. I spend now a lot of time in changing the 12h to 24h and the language...after a few hours trying (I´m not a programmer - only a user) I aked chatgpt...and this gave me a simple answer... and now it works perfekt: The only change that is nessesary is in row 3: change the value of "const tz":
here the example (see also the comments for the 12h to 24h-Change):
// Formats the given Date and returns map with format string parts.
const makeTimeFormatMap = function (date) {
const tz = "de-DE"; // Set locale to German
const dateTimeFormat = new Intl.DateTimeFormat(tz, {
month: 'short',
day: 'numeric',
weekday: 'short',
hour: 'numeric',
minute: 'numeric',
hour12: false, // For AM/PM format (can be removed if 24h format is preferred)
});
const partsMap = {};
dateTimeFormat.formatToParts(date).map(({ type, value }) => {
partsMap[type] = value;
});
partsMap.dayPeriod = partsMap.dayPeriod ? partsMap.dayPeriod[0].toLowerCase() : ''; // Adjust for AM/PM
return partsMap;
};
Later I had to adjust the writing: in Germany we do the day first, then the month...
I also had to adjust the size (thats what most people have to do to make it fit to their display) of the text an spaces between the lines because i only use a 1,54" display - i want to mount it into a electric-Socket in the bathroom...
Thanks a lot...
i´m not so keen in witing programms - i could only use and change some things...
So the flow works great, but i wan´t to change some things to make it more fit for me:
The day are giben in english words: is there a possibility to wirte this in german? The same for 12h and 24h...you comment something in row 25 to 27 about the "local" thinks, but i did not understand what i could change...