1 /**
  2  * @fileOverview This file has functions related to getting the day of the week from a date string.
  3  * @author <a href="http://www.trevmex.com/">Trevor Menagh</a>
  4  * @version 1.0.0
  5  * Written on 7/5/2010 (Monday :D)
  6  */
  7 
  8 "use strict";
  9 
 10 /**
 11  * @description An algorithm to calculate the day of the week for any Julian or Gregorian calendar date.
 12  * @see <a href="http://en.wikipedia.org/wiki/Zeller%27s_congruence">Zeller's congruence</a>
 13  * @function
 14  * @param {Number} dayOfMonth The day of the month.
 15  * @param {Number} month The month.
 16  * @param {Number} year The year.
 17  * @param {Boolean} [iso] If true return the ISO week date Day-of-Week (1 = Monday to 7 = Sunday), default is false.
 18  * @param {String} [calendarType] "julian" or "gregorian", default is "gregorian".
 19  * @param {String[]} [i18nDayMapping] An array of strings mapping "Saturday" to "Friday" in a given language (default is English, ignored if iso is true).
 20  * @returns {String|Number} The day of the week ("Monday" to "Sunday"), or the ISO week date Day-of-Week if iso is true.
 21  * @throws {MissingParameters} If year, month, or dayOfMonth are not passed in.
 22  * @throws {InvalidParameters} If the day of the month or the month are not valid.
 23  * @throws {InvalidParameters} If the calendar type is supplied and is not valid.
 24  * @throws {InvalidParameters} If iso is supplied and is not valid.
 25  * @throws {InvalidParameters} If i18nDayMapping is supplied and is not valid.
 26  */
 27 function zeller(dayOfMonth, month, year, iso, calendarType, i18nDayMapping) {
 28     // Set the parameters for Zeller's congruence
 29     var q = dayOfMonth,
 30         m = month,
 31         Y = (m < 3) ? year - 1 : year,
 32         h,
 33         d,
 34         i;
 35 
 36     // Validations
 37     if (dayOfMonth === undefined || dayOfMonth === null) {
 38         throw "MissingParameters: The day of the month is required.\nFormat: zeller(dayOfMonth, month, year, [iso], [calendarType], [i18nDayMapping])";
 39     }
 40     if (month === undefined || month === null) {
 41         throw "MissingParameters: The month is required.\nFormat: zeller(dayOfMonth, month, year, [iso], [calendarType], [i18nDayMapping])";
 42     }
 43     if (year === undefined || year === null) {
 44         throw "MissingParameters: The year is required.\nFormat: zeller(dayOfMonth, month, year, [iso], [calendarType], [i18nDayMapping])";
 45     }
 46     if (month < 1 || month > 12) {
 47         throw "InvalidParameters: The month must be between 1 (January) and 12 (December). " + month + " is invalid.\nFormat: zeller(dayOfMonth, month, year, [iso], [calendarType], [i18nDayMapping])";
 48     }
 49     if (dayOfMonth < 1 || dayOfMonth > 31) {
 50         throw "InvalidParameters: The day of the month must be between 1 and 31. " + dayOfMonth + " is invalid.\nFormat: zeller(dayOfMonth, month, year, [iso], [calendarType], [i18nDayMapping])";
 51     }
 52     if (month === 4 || month === 6 || month === 9 || month === 11) {
 53         if (dayOfMonth > 30) {
 54             throw "InvalidParameters: Month " + month + " does not have day " + dayOfMonth + ".\nFormat: zeller(dayOfMonth, month, year, [iso], [calendarType], [i18nDayMapping])";
 55         }
 56     }
 57     if (year % 4 === 0 && year % 100 !== 0 || year % 400 === 0) {
 58         // This is a leap year
 59         if (month === 2 && dayOfMonth > 29) {
 60             throw "InvalidParameters: Month 2 (February) does not have day " + dayOfMonth + " this year (" + year + ").\nFormat: zeller(dayOfMonth, month, year, [iso], [calendarType], [i18nDayMapping])";
 61         }
 62     } else {
 63         // This is not a leap year
 64         if (month === 2 && dayOfMonth > 28) {
 65             throw "InvalidParameters: Month 2 (February) does not have day " + dayOfMonth + " this year (" + year + ").\nFormat: zeller(dayOfMonth, month, year, [iso], [calendarType], [i18nDayMapping])";
 66         }
 67     }
 68     if ((calendarType !== undefined && calendarType !== null) && !(calendarType.toLowerCase() === "gregorian" || calendarType.toLowerCase() === "julian")) {
 69         throw "InvalidParameters: Calendar type must be \"Gregorian\" or \"Julian\". " + calendarType + " is invalid.\nFormat: zeller(dayOfMonth, month, year, [iso], [calendarType], [i18nDayMapping])";
 70     }
 71     if ((iso !== undefined && iso !== null) && !(iso === true || iso === false)) {
 72         throw "InvalidParameters: ISO must be true or false. " + iso + " is invalid.\nFormat: zeller(dayOfMonth, month, year, [iso], [calendarType], [i18nDayMapping])";
 73     }
 74     if ((i18nDayMapping !== undefined && i18nDayMapping !== null)) {
 75         if (i18nDayMapping.length !== 7) {
 76             throw "InvalidParameters: Internationalized Day Mapping must be an array of 7 strings from Saturday to Friday. " + i18nDayMapping + " is invalid.\nFormat: zeller(dayOfMonth, month, year, [iso], [calendarType], [i18nDayMapping])";
 77         }
 78         for (i = i18nDayMapping.length - 1; i >= 0; i -= 1) {
 79             // Check to see if this is a native string
 80             if (typeof(i18nDayMapping[i]) !== "string") {
 81                 // Check to see if this is a String object
 82                 if (!(i18nDayMapping[i] instanceof String)) {
 83                     throw "InvalidParameters: Internationalized Day Mapping must be an array of 7 strings from Saturday to Friday. " + i18nDayMapping[i] + " at position " + i + " is invalid.\nFormat: zeller(dayOfMonth, month, year, [iso], [calendarType], [i18nDayMapping])";
 84                 }
 85             }
 86         }
 87     }
 88 
 89     // Set default values
 90     if (calendarType === undefined || calendarType === null) {
 91         calendarType = "gregorian";
 92     }
 93     if (iso === undefined || iso === null) {
 94         iso = false;
 95     }
 96     if (iso === false) {
 97         if (i18nDayMapping === undefined || i18nDayMapping === null) {
 98             i18nDayMapping = ["Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"];
 99         }
100     }
101 
102     if (calendarType.toLowerCase() === "gregorian") {
103         h = (Math.floor(q + (Math.floor((m + 1) * 26) / 10) + Y + Math.floor(Y / 4) + (6 * Math.floor(Y / 100)) + Math.floor(Y / 400))) % 7;
104     } else /* calendarType.toLowerCase() === "julian" */ {
105         h = (Math.floor(q + (Math.floor((m + 1) * 26) / 10) + Y + Math.floor(Y / 4) + 5)) % 7;
106     }
107 
108     if (iso) {
109         d = ((h + 5) % 7) + 1;
110     } else /* !iso */ {
111         d = i18nDayMapping[h];
112     }
113 
114     return d;
115 }
116 
117 /**
118  * @description Given a date and a date format, return which day of the week it is.
119  * @param {String} date A string containing today's date.
120  * @param {Boolean} [iso] If true return the ISO week date Day-of-Week (1 = Monday to 7 = Sunday), default is false.
121  * @param {String} [calendarType] "Julian" or "Gregorian", default is "Gregorian".
122  * @param {String[]} [i18nDayMapping] An array of strings mapping "Saturday" to "Friday" in a given language (default is English)
123  * @returns {String|Number} The day of the week ("Monday" to "Sunday"), or the ISO week date Day-of-Week if iso is true.
124  */
125 String.prototype.getDay = function (iso, calendarType, i18nDayMapping) {
126     var date = new Date(this);
127     
128     return zeller(date.getDate(), date.getMonth() + 1, date.getFullYear(), iso, calendarType, i18nDayMapping);
129 };