How do I display calculated dates for a school website (weeks until, week x of term)

Hey there. Thanks for sharing this!

You may or may not be able to help, but I’m doing a free website for a low socio-economic rural school and I want to have a dynamic text field on the home page to help parents to know where we are at in the school year.

IT IS WEEK {X} of TERM {X}. THERE ARE {X} WEEKS UNTIL THE {MONTH} SCHOOL HOLIDAYS

Any ideas how I could pull that off?

1 Like

Hi Hayden,

  • Put the terms in a CMS collection. Enter the start and end dates.
  • On your home page, put a collection list bound to terms, filtered to show only terms that started before today, and end after today. That’s the current term. Limit to 1, to be sure.
  • In that collection list, drop an HTML embed. have it emit your start and end dates from the term, e.g.
<data id="term-dates" start="(start date field)" end="(end date field)"></data>
  • Add a script that finds that data by ID, gets the fields, and converts them to Dates. now you’ve got the start and end date of the current term, and the school can manage the term dates themselves, and adjust them whenever needed.

The actual weeks-between-dates calc is just JS, you’ll find lots of functions online for this. moment.js is a good toolset to do date math too.

the momentJS is deprecated for few years now and is only maintained to be back compatible also has mutability issues.

https://momentjs.com/docs/#/-project-status/

You can use DayJS instead as it is easy to use and has only 2kb or use another momentJS alternatives

2 Likes

Hi @Hayden_Judd1 as this request is not possible to solve in writing here is a 20min video where I try to explain what issues you may face and how it can be solved.

here is the code I have used in the video

for WEBFLOW to create an array of objects from CMS

//  create WF collection eg: school terms
//  add title as text files
//  add start date as a date field
//  add end date as a date field

// in page add collection and in collection item add these 3 fields

const shoolYearTermsArray = [];

const terms = Array.from(document.querySelectorAll('.term')) as Array<HTMLElement>;

terms.forEach((term) => {
	const termName = term.querySelector('.term-name')?.textContent;
	const termStart = term.querySelector('.term-start')?.textContent;
	const termEnd = term.querySelector('.term-end')?.textContent;
	if (termName && termStart && termEnd) {
		shoolYearTermsArray.push({
			term: termName,
			start: termStart,
			end: termEnd
		});
	}
});

Rest of JS

// dayJS
import dayjs from 'dayjs';
import weekOfYear from 'dayjs/plugin/weekOfYear';
dayjs.extend(weekOfYear);

// fake db
const shoolYearTerms = [
	{
		name: 'February mid-term break',
		start: '2023-02-14',
		end: '2023-02-18'
	},
	{
		name: 'Easter',
		start: '2023-04-04',
		end: '2023-04-18'
	},
	{
		name: 'Autumn mid-name break',
		start: '2023-10-31',
		end: '2023-11-04'
	},
	{
		name: 'Christmas',
		start: '2023-12-20',
		end: '2024-01-04'
	}
];

// fake date
// const fakeDate = '2023-12-24';
// const currDate = dayjs(fakeDate).format('YYYY-MM-DD');

// dayJS  
const currDate = dayjs().format('YYYY-MM-DD');
const currYear = dayjs(currDate).year();
const weekNumber = dayjs().week();

// functions returns
const nextNearestTerm = followingTerm(shoolYearTerms, currDate); //?
const currrentTerm = findTerms(shoolYearTerms, currDate); //?
const daysToNextTerm = dayjs(nextNearestTerm.start).diff(currDate, 'day');

// find current school term
function findTerms(shoolYearTerms: Array<Record<string, string >>, currDate: string) {
	let currentSchoolTerm: Record<string, string> = {};
	for (const term of shoolYearTerms) {
		const termStartDay = dayjs(term.start).format('YYYY-MM-DD');
		const termEndsDay = dayjs(term.end).format(`YYYY-MM-DD`);

		if (dayjs(termStartDay).year() === currYear && dayjs(termEndsDay).year() === currYear) {
			if (termStartDay <= currDate && termEndsDay >= currDate) {
				currentSchoolTerm = term;
				break;
			}
		}

		if (dayjs(termStartDay).year() === currYear && dayjs(termEndsDay).year() === currYear + 1) {
			if (termStartDay <= currDate && termEndsDay >= currDate) {
				currentSchoolTerm = term;
				break;
			}
		}
	}

	return currentSchoolTerm;
}

// find following school term
function followingTerm(shoolYearTerms: Array<Record<string, string>>, currDate: string) {
	let nextClosestTerm: Record<string, string> = {};
	for (const [i, term] of shoolYearTerms.entries()) {
		const termStartDay = dayjs(term.start).format(`YYYY-MM-DD`);
		const termEndsDay = dayjs(term.end).format(`YYYY-MM-DD`);

		if (
			dayjs(termStartDay).year() === currYear &&
			dayjs(termEndsDay).year() === currYear &&
			i !== shoolYearTerms.length - 1
		) {
			if (termStartDay >= currDate && termEndsDay >= currDate) {
				nextClosestTerm = term;
				break;
			}
		}
		// Recurring part
		if (
			(dayjs(termStartDay).year() === currYear && dayjs(termEndsDay).year() !== currYear) ||
			i === shoolYearTerms.length - 1
		) {
			if (termStartDay >= currDate && currDate >= termEndsDay) {
				nextClosestTerm = term; //?
				break;
			}
		} else {
			// when term active increase next term year by 1 and reset is on current year when term ends
			shoolYearTerms[0].start = dayjs(shoolYearTerms[0].start).format(`${currYear + 1}-MM-DD`);
			shoolYearTerms[0].end = dayjs(shoolYearTerms[0].end).format(`${currYear + 1}-MM-DD`);
			nextClosestTerm = shoolYearTerms[0];
		}
	}

	return nextClosestTerm;
}

// message code example

function message(weekNumber: number, currrentTerm: any, daysToNextTerm: number) {
	return `Is week ${weekNumber} of the ${currYear}.${ifCurrntTermIsNotSet(
		currrentTerm
	)} and there  ${substr(daysToNextTerm)} to ${nextNearestTerm.name} `;
}
function ifCurrntTermIsNotSet(currrentTerm: any) {
	if (currrentTerm === null || undefined) {
		return 'There is no school term at the moment';
	}
	return ` We are currently in ${currrentTerm.name} term`;
}

function substr(days: number) {
	if (Number(days) > 1 && Number(days) <= 7) {
		return `are ${days} days`;
	}
	if (Number(days) > 7) {
		return `are ${Math.floor(days / 7)} weeks`;
	}

	return `is ${days} day`;
}

const msgToDisplay = message(weekNumber, currrentTerm, daysToNextTerm);
console.log(msgToDisplay);

as this is only the first raw code that works there is still space for refactoring :wink:

I have found a bug in the findNextTerm function I didn’t realize it when publishing it at 3:00 AM :crazy_face:. This function works in sequential order instead of returning the nearest term date related to the current date.

When I will have time I will fix it.

EDIT:

Hi @Hayden_Judd1 once you will come to this forum to look if someone trying to help. I have fixed and updated the code above. Now it should be recurring.

And here I am @Stan! Was delayed thanks to Cyclone Gabrielle!

Wow thanks for all the effort. Diving in now to give it a crack. Thanks so much!

Yep that was a fun one.
Midjourney agrees.