diff --git a/95_Weekday/javascript/weekday.js b/95_Weekday/javascript/weekday.js index caf45990..dd1d82d5 100644 --- a/95_Weekday/javascript/weekday.js +++ b/95_Weekday/javascript/weekday.js @@ -46,7 +46,33 @@ function fnb(arg) { return Math.floor(arg / 7); } -const t = [, 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5]; +// in a non-leap year the day of the week for the first of each month moves by the following amounts. +const MONTHLY_DAY_OF_WEEK_OFFSETS = [0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5]; + +/** + * Reads a date, and extracts the date information. + * This expects date parts to be comma separated, using US date ordering, + * i.e. Month,Day,Year. + * @returns {Promise<[number,number,number]>} [year, month, dayOfMonth] + */ +async function readDateElements() { + let dateString = await input(); + const month = parseInt(dateString); + const dayOfMonth = parseInt(dateString.substr(dateString.indexOf(",") + 1)); + const year = parseInt(dateString.substr(dateString.lastIndexOf(",") + 1)); + return [year, month, dayOfMonth]; +} + +/** + * Returns a US formatted date, i.e. Month/Day/Year. + * @param year + * @param month + * @param dayOfMonth + * @returns {string} + */ +function getFormattedDate(year, month, dayOfMonth) { + return month + "/" + dayOfMonth + "/" + year; +} let k5; let k6; @@ -73,6 +99,46 @@ function time_spent(f, a8) print(i5 + "\t" + i6 + "\t" + i7 + "\n"); } +function getDayOfWeek(dobYear, dobMonth, dobDayOfMonth) { + const i1 = Math.floor((dobYear - 1500) / 100); + let a = i1 * 5 + (i1 + 3) / 4; + const i2 = Math.floor(a - fnb(a) * 7); + const y2 = Math.floor(dobYear / 100); + const y3 = Math.floor(dobYear - y2 * 100); + a = y3 / 4 + y3 + dobDayOfMonth + MONTHLY_DAY_OF_WEEK_OFFSETS[dobMonth-1] + i2; + let dayOfWeek = Math.floor(a - fnb(a) * 7) + 1; + if (dobMonth <= 2) { + if (y3 !== 0) { + t1 = Math.floor(dobYear - fna(dobYear) * 4); + } else { + a = i1 - 1; + t1 = Math.floor(a - fna(a) * 4); + } + if (t1 === 0) { + if (dayOfWeek === 0) { + dayOfWeek = 6; + } + dayOfWeek--; + } + } + if (dayOfWeek === 0) { + dayOfWeek = 7; + } + return dayOfWeek; +} + +/** + * The following performs a special hash on the day parts which guarantees + * that different days will return different numbers, and the numbers returned are in ordered. + * @param todayYear + * @param todayMonth + * @param todayDayOfMonth + * @returns {*} + */ +function getNormalisedDay(todayYear, todayMonth, todayDayOfMonth) { + return (todayYear * 12 + todayMonth) * 31 + todayDayOfMonth; +} + // Main control section async function main() { @@ -85,59 +151,38 @@ async function main() print("GIVES FACTS ABOUT A DATE OF INTEREST TO YOU.\n"); print("\n"); print("ENTER TODAY'S DATE IN THE FORM: 3,24,1979 "); - let str = await input(); - const m1 = parseInt(str); - const d1 = parseInt(str.substr(str.indexOf(",") + 1)); - const y1 = parseInt(str.substr(str.lastIndexOf(",") + 1)); + const [todayYear, todayMonth, todayDayOfMonth] = await readDateElements(); // This program determines the day of the week // for a date after 1582 print("ENTER DAY OF BIRTH (OR OTHER DAY OF INTEREST)"); - str = await input(); - const m = parseInt(str); - const d = parseInt(str.substr(str.indexOf(",") + 1)); - const y = parseInt(str.substr(str.lastIndexOf(",") + 1)); + const [dobYear, dobMonth, dobDayOfMonth] = await readDateElements(); print("\n"); - const i1 = Math.floor((y - 1500) / 100); // Test for date before current calendar. - if (y - 1582 < 0) { + // Note: this test is unreliable - the Gregorian calendar was introduced on Friday 15 October 1582 + // and the weekday algorithm fails for dates prior to that + if (dobYear - 1582 < 0) { print("NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO MDLXXXII.\n"); } else { - let a = i1 * 5 + (i1 + 3) / 4; - const i2 = Math.floor(a - fnb(a) * 7); - const y2 = Math.floor(y / 100); - const y3 = Math.floor(y - y2 * 100); - a = y3 / 4 + y3 + d + t[m] + i2; - let b = Math.floor(a - fnb(a) * 7) + 1; - if (m <= 2) { - if (y3 !== 0) { - t1 = Math.floor(y - fna(y) * 4); - } else { - a = i1 - 1; - t1 = Math.floor(a - fna(a) * 4); - } - if (t1 === 0) { - if (b === 0) - b = 6; - b--; - } - } - if (b === 0) - b = 7; - if ((y1 * 12 + m1) * 31 + d1 < (y * 12 + m) * 31 + d) { - print(m + "/" + d + "/" + y + " WILL BE A "); - } else if ((y1 * 12 + m1) * 31 + d1 === (y * 12 + m) * 31 + d) { - print(m + "/" + d + "/" + y + " IS A "); + const dayOfWeek = getDayOfWeek(dobYear, dobMonth, dobDayOfMonth); + + const normalisedToday = getNormalisedDay(todayYear, todayMonth, todayDayOfMonth); + const normalisedDob = getNormalisedDay(dobYear, dobMonth, dobDayOfMonth); + + if (normalisedToday < normalisedDob) { + print(getFormattedDate(dobYear, dobMonth, dobDayOfMonth) + " WILL BE A "); + } else if (normalisedToday === normalisedDob) { + print(getFormattedDate(dobYear, dobMonth, dobDayOfMonth) + " IS A "); } else { - print(m + "/" + d + "/" + y + " WAS A "); + print(getFormattedDate(dobYear, dobMonth, dobDayOfMonth) + " WAS A "); } - switch (b) { + switch (dayOfWeek) { case 1: print("SUNDAY.\n"); break; case 2: print("MONDAY.\n"); break; case 3: print("TUESDAY.\n"); break; case 4: print("WEDNESDAY.\n"); break; case 5: print("THURSDAY.\n"); break; case 6: - if (d === 13) { + if (dobDayOfMonth === 13) { print("FRIDAY THE THIRTEENTH---BEWARE!\n"); } else { print("FRIDAY.\n"); @@ -145,31 +190,32 @@ async function main() break; case 7: print("SATURDAY.\n"); break; } - if ((y1 * 12 + m1) * 31 + d1 !== (y * 12 + m) * 31 + d) { - let i5 = y1 - y; + if (normalisedToday !== normalisedDob) { + let yearsBetweenDates = todayYear - dobYear; print("\n"); - let i6 = m1 - m; - let i7 = d1 - d; - if (i7 < 0) { - i6--; - i7 += 30; + let monthsBetweenDates = todayMonth - dobMonth; + let daysBetweenDates = todayDayOfMonth - dobDayOfMonth; + if (daysBetweenDates < 0) { + monthsBetweenDates--; + daysBetweenDates += 30; } - if (i6 < 0) { - i5--; - i6 += 12; + if (monthsBetweenDates < 0) { + yearsBetweenDates--; + monthsBetweenDates += 12; } - if (i5 >= 0) { - if (i7 === 0 && i6 === 0) + if (yearsBetweenDates >= 0) { + if (daysBetweenDates === 0 && monthsBetweenDates === 0) { print("***HAPPY BIRTHDAY***\n"); + } print(" \tYEARS\tMONTHS\tDAYS\n"); print(" \t-----\t------\t----\n"); - print("YOUR AGE (IF BIRTHDATE) \t" + i5 + "\t" + i6 + "\t" + i7 + "\n"); - const a8 = (i5 * 365) + (i6 * 30) + i7 + Math.floor(i6 / 2); - k5 = i5; - k6 = i6; - k7 = i7; + print("YOUR AGE (IF BIRTHDATE) \t" + yearsBetweenDates + "\t" + monthsBetweenDates + "\t" + daysBetweenDates + "\n"); + const a8 = (yearsBetweenDates * 365) + (monthsBetweenDates * 30) + daysBetweenDates + Math.floor(monthsBetweenDates / 2); + k5 = yearsBetweenDates; + k6 = monthsBetweenDates; + k7 = daysBetweenDates; // Calculate retirement date. - const e = y + 65; + const e = dobYear + 65; // Calculate time spent in the following functions. print("YOU HAVE SLEPT \t\t\t"); time_spent(0.35, a8);