import { utcToZonedTime, zonedTimeToUtc } from "date-fns-tz"; export const TERMS = ["winter", "spring", "fall"] as const; export type Term = typeof TERMS[number]; export const DATE_FORMAT = "MMMM dd yyyy HH:mm"; // https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates export function isTerm(x: string): x is Term { return TERMS.some((term) => x === term); } export function capitalize(str: string) { return str.slice(0, 1).toUpperCase() + str.slice(1); } // Converts a date to local time export function getLocalDateFromEST(date: Date): Date { return utcToZonedTime( // The date parameter is in EST zonedTimeToUtc(date, "America/Toronto"), Intl.DateTimeFormat().resolvedOptions().timeZone ); } export interface TermYear { term: Term; year: number; } export interface GetTermYearOptions { goBackwards?: boolean; skipCurrent?: boolean; } export function* getTermYear( start?: number | TermYear, { goBackwards = false, skipCurrent = false }: GetTermYearOptions = {} ) { const allTerms = [...TERMS]; if (goBackwards) { allTerms.reverse(); } const today = new Date(); const todayYear = today.getFullYear(); const todayTerm = TERMS[Math.trunc(today.getMonth() / 4)]; start ??= { term: todayTerm, year: todayYear }; if (typeof start === "number") { start = { term: allTerms[0], year: start }; } let currentYear = start.year; while (0 <= currentYear && currentYear <= Number.MAX_SAFE_INTEGER) { for (const currentTerm of allTerms) { if ( currentYear === start.year && allTerms.indexOf(currentTerm) < allTerms.indexOf(start.term) ) { continue; } if ( skipCurrent && currentYear === start.year && currentTerm === start.term ) { continue; } yield { term: currentTerm, year: currentYear }; } currentYear = currentYear + (goBackwards ? -1 : 1); } } export function getCurrentTermYear() { const result = getTermYear().next(); if (result.done === true) { throw new Error("Cannot get current term. Iterator is done."); } return result.value; }