1 /* 2 * HebrewRataDie.js - Represent an RD date in the Hebrew calendar 3 * 4 * Copyright © 2012-2015, 2018, JEDLSoft 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20 var HebrewCal = require("./HebrewCal.js"); 21 var MathUtils = require("./MathUtils.js"); 22 var RataDie = require("./RataDie.js"); 23 24 /** 25 * @class 26 * Construct a new Hebrew RD date number object. The constructor parameters can 27 * contain any of the following properties: 28 * 29 * <ul> 30 * <li><i>unixtime<i> - sets the time of this instance according to the given 31 * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970. 32 * 33 * <li><i>julianday</i> - sets the time of this instance according to the given 34 * Julian Day instance or the Julian Day given as a float 35 * 36 * <li><i>year</i> - any integer, including 0 37 * 38 * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc. 39 * 40 * <li><i>day</i> - 1 to 31 41 * 42 * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 43 * is always done with an unambiguous 24 hour representation 44 * 45 * <li><i>parts</i> - 0 to 1079. Specify the halaqim parts of an hour. Either specify 46 * the parts or specify the minutes, seconds, and milliseconds, but not both. 47 * 48 * <li><i>minute</i> - 0 to 59 49 * 50 * <li><i>second</i> - 0 to 59 51 * 52 * <li><i>millisecond</i> - 0 to 999 53 * 54 * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one. 55 * </ul> 56 * 57 * If the constructor is called with another Hebrew date instance instead of 58 * a parameter block, the other instance acts as a parameter block and its 59 * settings are copied into the current instance.<p> 60 * 61 * If the constructor is called with no arguments at all or if none of the 62 * properties listed above are present, then the RD is calculate based on 63 * the current date at the time of instantiation. <p> 64 * 65 * If any of the properties from <i>year</i> through <i>millisecond</i> are not 66 * specified in the params, it is assumed that they have the smallest possible 67 * value in the range for the property (zero or one).<p> 68 * 69 * 70 * @private 71 * @constructor 72 * @extends RataDie 73 * @param {Object=} params parameters that govern the settings and behaviour of this Hebrew RD date 74 */ 75 var HebrewRataDie = function(params) { 76 this.cal = params && params.cal || new HebrewCal(); 77 this.rd = NaN; 78 RataDie.call(this, params); 79 }; 80 81 HebrewRataDie.prototype = new RataDie(); 82 HebrewRataDie.prototype.parent = RataDie; 83 HebrewRataDie.prototype.constructor = HebrewRataDie; 84 85 /** 86 * The difference between a zero Julian day and the first day of the Hebrew 87 * calendar: sunset on Monday, Tishri 1, 1 = September 7, 3760 BC Gregorian = JD 347997.25 88 * @private 89 * @type number 90 */ 91 HebrewRataDie.prototype.epoch = 347997.25; 92 93 /** 94 * the cumulative lengths of each month for a non-leap year, without new years corrections 95 * @private 96 * @const 97 * @type Array.<number> 98 */ 99 HebrewRataDie.cumMonthLengths = [ 100 176, /* Nisan */ 101 206, /* Iyyar */ 102 235, /* Sivan */ 103 265, /* Tammuz */ 104 294, /* Av */ 105 324, /* Elul */ 106 0, /* Tishri - Jewish New Year (Rosh HaShanah) starts in month 7 */ 107 30, /* Heshvan */ 108 59, /* Kislev */ 109 88, /* Teveth */ 110 117, /* Shevat */ 111 147 /* Adar I */ 112 ]; 113 114 /** 115 * the cumulative lengths of each month for a leap year, without new years corrections 116 * @private 117 * @const 118 * @type Array.<number> 119 */ 120 HebrewRataDie.cumMonthLengthsLeap = [ 121 206, /* Nisan */ 122 236, /* Iyyar */ 123 265, /* Sivan */ 124 295, /* Tammuz */ 125 324, /* Av */ 126 354, /* Elul */ 127 0, /* Tishri - Jewish New Year (Rosh HaShanah) starts in month 7 */ 128 30, /* Heshvan */ 129 59, /* Kislev */ 130 88, /* Teveth */ 131 117, /* Shevat */ 132 147, /* Adar I */ 133 177 /* Adar II */ 134 ]; 135 136 /** 137 * Calculate the Rata Die (fixed day) number of the given date from the 138 * date components. 139 * 140 * @private 141 * @param {Object} date the date components to calculate the RD from 142 */ 143 HebrewRataDie.prototype._setDateComponents = function(date) { 144 var elapsed = HebrewCal.elapsedDays(date.year); 145 var days = elapsed + 146 HebrewCal.newYearsCorrection(date.year, elapsed) + 147 date.day - 1; 148 var sum = 0, table; 149 150 //console.log("getRataDie: converting " + JSON.stringify(date)); 151 //console.log("getRataDie: days is " + days); 152 //console.log("getRataDie: new years correction is " + HebrewCal.newYearsCorrection(date.year, elapsed)); 153 154 table = this.cal.isLeapYear(date.year) ? 155 HebrewRataDie.cumMonthLengthsLeap : 156 HebrewRataDie.cumMonthLengths; 157 sum = table[date.month-1]; 158 159 // gets cumulative without correction, so now add in the correction 160 if ((date.month < 7 || date.month > 8) && HebrewCal.longHeshvan(date.year)) { 161 sum++; 162 } 163 if ((date.month < 7 || date.month > 9) && HebrewCal.longKislev(date.year)) { 164 sum++; 165 } 166 // console.log("getRataDie: cum days is now " + sum); 167 168 days += sum; 169 170 // the date starts at sunset, which we take as 18:00, so the hours from 171 // midnight to 18:00 are on the current Gregorian day, and the hours from 172 // 18:00 to midnight are on the previous Gregorian day. So to calculate the 173 // number of hours into the current day that this time represents, we have 174 // to count from 18:00 to midnight first, and add in 6 hours if the time is 175 // less than 18:00 176 var minute, second, millisecond; 177 178 if (typeof(date.parts) !== 'undefined') { 179 // The parts (halaqim) of the hour. This can be a number from 0 to 1079. 180 var parts = parseInt(date.parts, 10); 181 var seconds = parseInt(parts, 10) * 3.333333333333; 182 minute = Math.floor(seconds / 60); 183 seconds -= minute * 60; 184 second = Math.floor(seconds); 185 millisecond = (seconds - second); 186 } else { 187 minute = parseInt(date.minute, 10) || 0; 188 second = parseInt(date.second, 10) || 0; 189 millisecond = parseInt(date.millisecond, 10) || 0; 190 } 191 192 var time; 193 if (date.hour >= 18) { 194 time = ((date.hour - 18 || 0) * 3600000 + 195 (minute || 0) * 60000 + 196 (second || 0) * 1000 + 197 (millisecond || 0)) / 198 86400000; 199 } else { 200 time = 0.25 + // 6 hours from 18:00 to midnight on the previous gregorian day 201 ((date.hour || 0) * 3600000 + 202 (minute || 0) * 60000 + 203 (second || 0) * 1000 + 204 (millisecond || 0)) / 205 86400000; 206 } 207 208 //console.log("getRataDie: rd is " + (days + time)); 209 this.rd = days + time; 210 }; 211 212 /** 213 * Return the rd number of the particular day of the week on or before the 214 * given rd. eg. The Sunday on or before the given rd. 215 * @private 216 * @param {number} rd the rata die date of the reference date 217 * @param {number} dayOfWeek the day of the week that is being sought relative 218 * to the current date 219 * @return {number} the rd of the day of the week 220 */ 221 HebrewRataDie.prototype._onOrBefore = function(rd, dayOfWeek) { 222 return rd - MathUtils.mod(Math.floor(rd) - dayOfWeek + 1, 7); 223 }; 224 225 module.exports = HebrewRataDie; 226