Thank you again. This was super helpful. I made a few little tweaks going back and forth with chatgpt.
I wanted to show the age the person will turn rather than current age.
Also I had to change line 2 from p.fileClass to p.type for it to work for me.
This is what I ended up with
const pages = dv.pages('"People"')
.where(p => p.type == "people" && p.dates && p.dates.length > 0)
.filter(p => p.dates.some(date => date.includes("Birthday")));
const today = new Date();
const result = pages.map(p => {
const birthdays = p.dates
.filter(date => date.includes("Birthday"))
.map(date => new Date(date.split("|")[0].trim()));
const calculateDaysUntilNextBirthday = (birthday) => {
const nextBirthday = new Date(today.getFullYear(), birthday.getMonth(), birthday.getDate());
if (nextBirthday < today) {
nextBirthday.setFullYear(today.getFullYear() + 1);
}
return Math.ceil((nextBirthday - today) / (1000 * 60 * 60 * 24));
};
// Get valid birthdays and calculate days until next birthday
const validBirthdays = birthdays.map(birthday => {
const daysUntil = calculateDaysUntilNextBirthday(birthday);
return { birthday, daysUntil };
}).filter(b => b.daysUntil >= 0 && b.daysUntil <= 30); // Filter for today and upcoming birthdays
// Include birthdays that are today
const todayBirthdays = birthdays.filter(birthday => {
const birthdayDate = new Date(today.getFullYear(), birthday.getMonth(), birthday.getDate());
return birthdayDate.toDateString() === today.toDateString(); // Check if the birthday is today
});
// Combine today's birthdays with upcoming birthdays
const allValidBirthdays = validBirthdays.concat(todayBirthdays.map(b => ({
birthday: b,
daysUntil: 0 // Set days until to 0 for today
})));
if (allValidBirthdays.length === 0) return null; // Skip if no upcoming birthdays
// Find the closest upcoming birthday (including today)
const nextBirthday = allValidBirthdays.reduce((closest, b) => {
return b.daysUntil < closest.daysUntil ? b : closest;
});
const daysUntilNextBirthday = nextBirthday.daysUntil;
// Create a new Date object for the next birthday to get the correct weekday
const birthdayDate = new Date(today.getFullYear(), nextBirthday.birthday.getMonth(), nextBirthday.birthday.getDate());
if (birthdayDate < today) {
birthdayDate.setFullYear(today.getFullYear() + 1);
}
// Calculate the age the person will be on their next birthday
const originalBirthday = nextBirthday.birthday; // Use the original birthday for age calculation
let turns = today.getFullYear() - originalBirthday.getFullYear(); // Calculate base age
// Check if today is the birthday
if (today.getDate() === originalBirthday.getDate() && today.getMonth() === originalBirthday.getMonth()) {
// If today is the birthday, no need to add 1 to turns
turns = today.getFullYear() - originalBirthday.getFullYear(); // Correctly set to the current age
} else if (today >= new Date(today.getFullYear(), originalBirthday.getMonth(), originalBirthday.getDate())) {
// Increment the turns if the birthday has occurred this year
turns++;
}
// Format the birthday date to "ddd, D MMMM"
const formattedBirthday = birthdayDate.toLocaleDateString("en-US", {
weekday: 'short', // Short day name (e.g., "Mon")
day: 'numeric', // Numeric day (e.g., "1")
month: 'long', // Full month name (e.g., "January")
});
// Final output format
return {
name: "[[" + p.file.name + "]]",
birthday: formattedBirthday,
daysUntilNextBirthday: daysUntilNextBirthday,
turns: turns // Change to "Turns"
};
}).filter(p => p !== null); // Filter out null results
// Sort the results by daysUntilNextBirthday
const sortedResult = result.sort( a => a.daysUntilNextBirthday, 'asc')
const formattedResult = sortedResult.map(p => [
p.name,
p.birthday,
p.daysUntilNextBirthday,
p.turns // Change to "Turns"
]);
dv.table(["Name", "Birthday", "Days Until Next Birthday", "Turns"], formattedResult);