95 Weekday - move methods into appropriate? scopes or classes

This commit is contained in:
Steve Bosman
2022-02-06 21:53:50 +00:00
parent a599e47e3d
commit 463351287e

View File

@@ -50,8 +50,10 @@ function tab(spaceCount) {
const MONTHS_PER_YEAR = 12; const MONTHS_PER_YEAR = 12;
const DAYS_PER_COMMON_YEAR = 365; const DAYS_PER_COMMON_YEAR = 365;
const DAYS_PER_IDEAL_MONTH = 30; const DAYS_PER_IDEALISED_MONTH = 30;
const MAXIMUM_DAYS_PER_MONTH = 31; const MAXIMUM_DAYS_PER_MONTH = 31;
// In a common (non-leap) year the day of the week for the first of each month moves by the following amounts.
const COMMON_YEAR_MONTH_OFFSET = [0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5];
/** /**
* Date representation. * Date representation.
@@ -105,6 +107,60 @@ class DateStruct {
return result; return result;
} }
/**
* The following performs a hash on the day parts which guarantees that
* 1. different days will return different numbers
* 2. the numbers returned are ordered.
* @returns {number}
*/
getNormalisedDay() {
return (this.year * MONTHS_PER_YEAR + this.month) * MAXIMUM_DAYS_PER_MONTH + this.day;
}
/**
* Determine the day of the week.
* This calculation returns a number between 1 and 7 where Sunday=1, Monday=2, ..., Saturday=7.
* @returns {number} Value between 1 and 7 representing Sunday to Saturday.
*/
getDayOfWeek() {
// Calculate an offset based on the century part of the year.
const centuriesSince1500 = Math.floor((this.year - 1500) / 100);
let centuryOffset = centuriesSince1500 * 5 + (centuriesSince1500 + 3) / 4;
centuryOffset = Math.floor(centuryOffset % 7);
// Calculate an offset based on the shortened two digit year.
// January 1st moves forward by approximately 1.25 days per year
const yearInCentury = this.year % 100;
const yearInCenturyOffsets = yearInCentury / 4 + yearInCentury;
// combine offsets with day and month
let dayOfWeek = centuryOffset + yearInCenturyOffsets + this.day + COMMON_YEAR_MONTH_OFFSET[this.month - 1];
dayOfWeek = Math.floor(dayOfWeek % 7) + 1;
if (this.month <= 2 && this.isLeapYear()) {
dayOfWeek--;
}
if (dayOfWeek === 0) {
dayOfWeek = 7;
}
return dayOfWeek;
}
/**
* Determine if the given year is a leap year.
* @returns {boolean}
*/
isLeapYear() {
if ((this.year % 4) !== 0) {
return false;
} else if ((this.year % 100) !== 0) {
return true;
} else if ((this.year % 400) !== 0) {
return false;
}
return true;
}
/** /**
* Returns a US formatted date, i.e. Month/Day/Year. * Returns a US formatted date, i.e. Month/Day/Year.
* @returns {string} * @returns {string}
@@ -169,7 +225,7 @@ class Duration {
*/ */
#fixRanges() { #fixRanges() {
if (this.#days < 0) { if (this.#days < 0) {
this.#days += DAYS_PER_IDEAL_MONTH; this.#days += DAYS_PER_IDEALISED_MONTH;
this.#months--; this.#months--;
} }
if (this.#months < 0) { if (this.#months < 0) {
@@ -178,10 +234,6 @@ class Duration {
} }
} }
toString() {
return this.#years + "/" + this.#months + "/" + this.#days;
}
/** /**
* Determine approximate Duration between two dates. * Determine approximate Duration between two dates.
* This is a naive calculation which assumes all months are 30 days. * This is a naive calculation which assumes all months are 30 days.
@@ -195,146 +247,90 @@ class Duration {
let days = date1.day - date2.day; let days = date1.day - date2.day;
return new Duration(years, months, days); return new Duration(years, months, days);
} }
}
// In a common (non-leap) year the day of the week for the first of each month moves by the following amounts. /**
const COMMON_YEAR_MONTH_OFFSET = [0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5]; * Calculate years, months and days as factor of days.
* This is a naive calculation which assumes all months are 30 days.
/** * @param dayCount Total day to convert to a duration
* Reads a date, and extracts the date information. * @param factor Factor to apply when calculating the duration
* This expects date parts to be comma separated, using US date ordering, * @returns {Duration}
* i.e. Month,Day,Year. */
* @returns {Promise<DateStruct>} static fromDays(dayCount, factor) {
*/ let totalDays = Math.floor(factor * dayCount);
async function readDateElements() { const years = Math.floor(totalDays / DAYS_PER_COMMON_YEAR);
let dateString = await input(); totalDays -= years * DAYS_PER_COMMON_YEAR;
const month = parseInt(dateString); const months = Math.floor(totalDays / DAYS_PER_IDEALISED_MONTH);
const day = parseInt(dateString.substr(dateString.indexOf(",") + 1)); const days = totalDays - (months * DAYS_PER_IDEALISED_MONTH);
const year = parseInt(dateString.substr(dateString.lastIndexOf(",") + 1)); return new Duration(years, months, days);
return new DateStruct(year, month, day);
}
/**
* Calculate years, months and days as factor of days.
* This is a naive calculation which assumes all months are 30 days.
* @param factor
* @param dayCount
* @returns {Duration}
*/
function time_spent(factor, dayCount) {
let totalDays = Math.floor(factor * dayCount);
const years = Math.floor(totalDays / DAYS_PER_COMMON_YEAR);
totalDays -= years * DAYS_PER_COMMON_YEAR;
const months = Math.floor(totalDays / DAYS_PER_IDEAL_MONTH);
const days = totalDays - (months * DAYS_PER_IDEAL_MONTH);
return new Duration(years, months, days);
}
/**
* Print the supplied duration.
* @param {Duration} duration
*/
function printTimeSpent(duration) {
print(duration.years + "\t" + duration.months + "\t" + duration.days + "\n");
}
/**
* Determine if the given year is a leap year.
* @param year
* @returns {boolean}
*/
function isLeapYear(year) {
if ((year % 4) !== 0) {
return false;
} else if ((year % 100) !== 0) {
return true;
} else if ((year % 400) !== 0) {
return false;
} }
return true;
}
/** toString() {
* Determine the day of the week. return this.#years + "/" + this.#months + "/" + this.#days;
* This calculation returns a number between 1 and 7 where Sunday=1, Monday=2, ..., Saturday=7.
* @param {DateStruct} date
* @returns {number} Value between 1 and 7 representing Sunday to Saturday.
*/
function getDayOfWeek(date) {
// Calculate an offset based on the century part of the year.
const centuriesSince1500 = Math.floor((date.year - 1500) / 100);
let centuryOffset = centuriesSince1500 * 5 + (centuriesSince1500 + 3) / 4;
centuryOffset = Math.floor(centuryOffset % 7);
// Calculate an offset based on the shortened two digit year.
// January 1st moves forward by approximately 1.25 days per year
const yearInCentury = date.year % 100;
const yearInCenturyOffsets = yearInCentury / 4 + yearInCentury;
// combine offsets with day and month
let dayOfWeek = centuryOffset + yearInCenturyOffsets + date.day + COMMON_YEAR_MONTH_OFFSET[date.month - 1];
dayOfWeek = Math.floor(dayOfWeek % 7) + 1;
if (date.month <= 2 && isLeapYear(date.year)) {
dayOfWeek--;
} }
if (dayOfWeek === 0) {
dayOfWeek = 7;
}
return dayOfWeek;
}
/**
* Obtain text for the day of the week.
* @param {DateStruct} date
* @returns {string}
*/
function getDayOfWeekText(date) {
const dayOfWeek = getDayOfWeek(date);
let dayOfWeekText = "";
switch (dayOfWeek) {
case 1:
dayOfWeekText = "SUNDAY.";
break;
case 2:
dayOfWeekText = "MONDAY.";
break;
case 3:
dayOfWeekText = "TUESDAY.";
break;
case 4:
dayOfWeekText = "WEDNESDAY.";
break;
case 5:
dayOfWeekText = "THURSDAY.";
break;
case 6:
if (date.day === 13) {
dayOfWeekText = "FRIDAY THE THIRTEENTH---BEWARE!";
} else {
dayOfWeekText = "FRIDAY.";
}
break;
case 7:
dayOfWeekText = "SATURDAY.";
break;
}
return dayOfWeekText;
}
/**
* The following performs a hash on the day parts which guarantees that
* 1. different days will return different numbers
* 2. the numbers returned are ordered.
* @param {DateStruct} date
* @returns {number}
*/
function getNormalisedDay(date) {
return (date.year * MONTHS_PER_YEAR + date.month) * MAXIMUM_DAYS_PER_MONTH + date.day;
} }
// Main control section // Main control section
async function main() { async function main() {
/**
* 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<DateStruct>}
*/
async function inputDate() {
let dateString = await input();
const month = parseInt(dateString);
const day = parseInt(dateString.substr(dateString.indexOf(",") + 1));
const year = parseInt(dateString.substr(dateString.lastIndexOf(",") + 1));
return new DateStruct(year, month, day);
}
/**
* Print the supplied duration.
* @param {Duration} duration
*/
function printTimeSpent(duration) {
print(duration.years + "\t" + duration.months + "\t" + duration.days + "\n");
}
/**
* Obtain text for the day of the week.
* @param {DateStruct} date
* @returns {string}
*/
function getDayOfWeekText(date) {
const dayOfWeek = date.getDayOfWeek();
let dayOfWeekText = "";
switch (dayOfWeek) {
case 1:
dayOfWeekText = "SUNDAY.";
break;
case 2:
dayOfWeekText = "MONDAY.";
break;
case 3:
dayOfWeekText = "TUESDAY.";
break;
case 4:
dayOfWeekText = "WEDNESDAY.";
break;
case 5:
dayOfWeekText = "THURSDAY.";
break;
case 6:
if (date.day === 13) {
dayOfWeekText = "FRIDAY THE THIRTEENTH---BEWARE!";
} else {
dayOfWeekText = "FRIDAY.";
}
break;
case 7:
dayOfWeekText = "SATURDAY.";
break;
}
return dayOfWeekText;
}
print(tab(32) + "WEEKDAY\n"); print(tab(32) + "WEEKDAY\n");
print(tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"); print(tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n");
print("\n"); print("\n");
@@ -344,18 +340,18 @@ async function main() {
print("GIVES FACTS ABOUT A DATE OF INTEREST TO YOU.\n"); print("GIVES FACTS ABOUT A DATE OF INTEREST TO YOU.\n");
print("\n"); print("\n");
print("ENTER TODAY'S DATE IN THE FORM: 3,24,1979 "); print("ENTER TODAY'S DATE IN THE FORM: 3,24,1979 ");
const today = await readDateElements(); const today = await inputDate();
// This program determines the day of the week // This program determines the day of the week
// for a date after 1582 // for a date after 1582
print("ENTER DAY OF BIRTH (OR OTHER DAY OF INTEREST)"); print("ENTER DAY OF BIRTH (OR OTHER DAY OF INTEREST)");
const dateOfBirth = await readDateElements(); const dateOfBirth = await inputDate();
print("\n"); print("\n");
// Test for date before current calendar. // Test for date before current calendar.
if (!dateOfBirth.isGregorianDate()) { if (!dateOfBirth.isGregorianDate()) {
print("NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO X.XV.MDLXXXII.\n"); print("NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO X.XV.MDLXXXII.\n");
} else { } else {
const normalisedToday = getNormalisedDay(today); const normalisedToday = today.getNormalisedDay();
const normalisedDob = getNormalisedDay(dateOfBirth); const normalisedDob = dateOfBirth.getNormalisedDay();
let dayOfWeekText = getDayOfWeekText(dateOfBirth); let dayOfWeekText = getDayOfWeekText(dateOfBirth);
if (normalisedToday < normalisedDob) { if (normalisedToday < normalisedDob) {
@@ -377,29 +373,29 @@ async function main() {
print(" \t-----\t------\t----\n"); print(" \t-----\t------\t----\n");
print("YOUR AGE (IF BIRTHDATE) \t"); print("YOUR AGE (IF BIRTHDATE) \t");
printTimeSpent(differenceBetweenDates); printTimeSpent(differenceBetweenDates);
const approximateDaysBetween = (differenceBetweenDates.years * DAYS_PER_COMMON_YEAR) + (differenceBetweenDates.months * DAYS_PER_IDEAL_MONTH) + differenceBetweenDates.days + Math.floor(differenceBetweenDates.months / 2); const approximateDaysBetween = (differenceBetweenDates.years * DAYS_PER_COMMON_YEAR) + (differenceBetweenDates.months * DAYS_PER_IDEALISED_MONTH) + differenceBetweenDates.days + Math.floor(differenceBetweenDates.months / 2);
// Create an object containing time unaccounted for // Create an object containing time unaccounted for
const unaccountedTime = differenceBetweenDates.clone(); const unaccountedTime = differenceBetweenDates.clone();
// Calculate time spent in the following functions. // Calculate time spent in the following functions.
print("YOU HAVE SLEPT \t\t\t"); print("YOU HAVE SLEPT \t\t\t");
const sleepTimeSpent = time_spent(0.35, approximateDaysBetween); const sleepTimeSpent = Duration.fromDays(approximateDaysBetween, 0.35);
printTimeSpent(sleepTimeSpent); printTimeSpent(sleepTimeSpent);
unaccountedTime.remove(sleepTimeSpent); unaccountedTime.remove(sleepTimeSpent);
print("YOU HAVE EATEN \t\t\t"); print("YOU HAVE EATEN \t\t\t");
const eatenTimeSpent = time_spent(0.17, approximateDaysBetween); const eatenTimeSpent = Duration.fromDays(approximateDaysBetween, 0.17);
printTimeSpent(eatenTimeSpent); printTimeSpent(eatenTimeSpent);
unaccountedTime.remove(eatenTimeSpent); unaccountedTime.remove(eatenTimeSpent);
if (unaccountedTime.years <= 3) { if (unaccountedTime.years <= 3) {
print("YOU HAVE PLAYED \t\t"); print("YOU HAVE PLAYED \t\t");
} else if (unaccountedTime.years <= 9) { } else if (unaccountedTime.years <= 9) {
print("YOU HAVE PLAYED/STUDIED \t\t"); print("YOU HAVE PLAYED/STUDIED \t");
} else { } else {
print("YOU HAVE WORKED/PLAYED \t\t"); print("YOU HAVE WORKED/PLAYED \t\t");
} }
const workPlayTimeSpent = time_spent(0.23, approximateDaysBetween); const workPlayTimeSpent = Duration.fromDays(approximateDaysBetween, 0.23);
printTimeSpent(workPlayTimeSpent); printTimeSpent(workPlayTimeSpent);
unaccountedTime.remove(workPlayTimeSpent); unaccountedTime.remove(workPlayTimeSpent);