diff --git a/Conversions/DateToDay.js b/Conversions/DateToDay.js index 8683bdec4b..a22f75ca3f 100644 --- a/Conversions/DateToDay.js +++ b/Conversions/DateToDay.js @@ -9,35 +9,11 @@ algorithm shown below gives us the number of the day and finally converts it to the name of the day. - Algorithm & Explanation : https://cs.uwaterloo.ca/~alopez-o/math-faq/node73.html + Algorithm & Explanation : https://en.wikipedia.org/wiki/Zeller%27s_congruence */ -// March is taken as the first month of the year. -const calcMonthList = { - 1: 11, - 2: 12, - 3: 1, - 4: 2, - 5: 3, - 6: 4, - 7: 5, - 8: 6, - 9: 7, - 10: 8, - 11: 9, - 12: 10 -} - -// show the week day in a number : Sunday - Saturday => 0 - 6 -const daysNameList = { // weeks-day - 0: 'Sunday', - 1: 'Monday', - 2: 'Tuesday', - 3: 'Wednesday', - 4: 'Thursday', - 5: 'Friday', - 6: 'Saturday' -} +// Array holding name of the day: Saturday - Sunday - Friday => 0 - 1 - 6 +const daysNameArr = ['Saturday', 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'] const DateToDay = (date) => { // firstly, check that input is a string or not. @@ -45,18 +21,40 @@ const DateToDay = (date) => { return new TypeError('Argument is not a string.') } // extract the date - const [day, month, year] = date.split('/').map((x) => Number(x)) + let [day, month, year] = date.split('/').map((x) => Number(x)) // check the data are valid or not. - if (day < 0 || day > 31 || month > 12 || month < 0) { + if (day < 1 || day > 31 || month > 12 || month < 1) { return new TypeError('Date is not valid.') } - // divide year to century and yearDigit value. - const yearDigit = (year % 100) + + // In case of Jan and Feb: + // Year: we consider it as previous year + // e.g., 1/1/1987 here year is 1986 (-1) + // Month: we consider value as 13 & 14 respectively + if (month < 3) { + year-- + month += 12 + } + + // divide year into century and the last two digits of the century + const yearDigits = year % 100 const century = Math.floor(year / 100) - // Apply the algorithm shown above - const weekDay = Math.abs((day + Math.floor((2.6 * calcMonthList[month]) - 0.2) - (2 * century) + yearDigit + Math.floor(yearDigit / 4) + Math.floor(century / 4)) % 7) - // return the weekDay name. - return daysNameList[weekDay] + + /* + In mathematics, remainders of divisions are usually defined to always be positive; + As an example, -2 mod 7 = 5. + Many programming languages including JavaScript implement the remainder of `n % m` as `sign(n) * (abs(n) % m)`. + This means the result has the same sign as the numerator. Here, `-2 % 7 = -1 * (2 % 7) = -2`. + + To ensure a positive numerator, the formula is adapted: `- 2 * century` is replaced with `+ 5 * century` + which does not alter the resulting numbers mod 7 since `7 - 2 = 5` + + The following example shows the issue with modulo division: + Without the adaption, the formula yields `weekDay = -6` for the date 2/3/2014; + With the adaption, it yields the positive result `weekDay = 7 - 6 = 1` (Sunday), which is what we need to index the array + */ + const weekDay = (day + Math.floor((month + 1) * 2.6) + yearDigits + Math.floor(yearDigits / 4) + Math.floor(century / 4) + 5 * century) % 7 + return daysNameArr[weekDay] // name of the weekday } // Example : DateToDay("18/12/2020") => Friday diff --git a/Conversions/test/DateToDay.test.js b/Conversions/test/DateToDay.test.js index a932dff08c..f0809821db 100644 --- a/Conversions/test/DateToDay.test.js +++ b/Conversions/test/DateToDay.test.js @@ -1,8 +1,8 @@ import { DateToDay } from '../DateToDay' -test('The date 18/02/2001 is Monday', () => { +test('The date 18/02/2001 is Sunday', () => { const res = DateToDay('18/02/2001') - expect(res).toBe('Monday') + expect(res).toBe('Sunday') }) test('The date 18/12/2020 is Friday', () => { @@ -14,7 +14,22 @@ test('The date 12/12/2012 is Wednesday', () => { const res = DateToDay('12/12/2012') expect(res).toBe('Wednesday') }) -test('The date 01/01/2001 is Friday', () => { +test('The date 01/01/2001 is Monday', () => { const res = DateToDay('01/01/2001') - expect(res).toBe('Friday') + expect(res).toBe('Monday') +}) + +test('The date 1/1/2020 is Wednesday', () => { + const res = DateToDay('1/1/2020') + expect(res).toBe('Wednesday') +}) + +test('The date 2/3/2014 is Sunday', () => { + const res = DateToDay('2/3/2014') + expect(res).toBe('Sunday') +}) + +test('The date 28/2/2017 is Tuesday', () => { + const res = DateToDay('28/2/2017') + expect(res).toBe('Tuesday') })