1 /* 2 * HanDate.js - Represent a date in the Han algorithmic calendar 3 * 4 * Copyright © 2014-2015, 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 ilib = require("./ilib.js"); 21 var MathUtils = require("./MathUtils.js"); 22 var HanCal = require("./HanCal.js"); 23 var RataDie = require("./RataDie.js"); 24 25 /** 26 * Construct a new Han 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, Gregorian 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>cycle</i> - any integer giving the number of 60-year cycle in which the date is located. 37 * If the cycle is not given but the year is, it is assumed that the year parameter is a fictitious 38 * linear count of years since the beginning of the epoch, much like other calendars. This linear 39 * count is never used. If both the cycle and year are given, the year is wrapped to the range 0 40 * to 60 and treated as if it were a year in the regular 60-year cycle. 41 * 42 * <li><i>year</i> - any integer, including 0 43 * 44 * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc. 45 * 46 * <li><i>day</i> - 1 to 31 47 * 48 * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 49 * is always done with an unambiguous 24 hour representation 50 * 51 * <li><i>minute</i> - 0 to 59 52 * 53 * <li><i>second</i> - 0 to 59 54 * 55 * <li><i>millisecond</i> - 0 to 999 56 * 57 * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one. 58 * </ul> 59 * 60 * If the constructor is called with another Han date instance instead of 61 * a parameter block, the other instance acts as a parameter block and its 62 * settings are copied into the current instance.<p> 63 * 64 * If the constructor is called with no arguments at all or if none of the 65 * properties listed above are present, then the RD is calculate based on 66 * the current date at the time of instantiation. <p> 67 * 68 * If any of the properties from <i>year</i> through <i>millisecond</i> are not 69 * specified in the params, it is assumed that they have the smallest possible 70 * value in the range for the property (zero or one).<p> 71 * 72 * 73 * @private 74 * @class 75 * @constructor 76 * @extends RataDie 77 * @param {Object=} params parameters that govern the settings and behaviour of this Han RD date 78 */ 79 var HanRataDie = function(params) { 80 this.rd = NaN; 81 if (params && params.cal) { 82 this.cal = params.cal; 83 RataDie.call(this, params); 84 if (params && typeof(params.callback) === 'function') { 85 params.callback(this); 86 } 87 } else { 88 new HanCal({ 89 sync: params && params.sync, 90 loadParams: params && params.loadParams, 91 onLoad: ilib.bind(this, function(c) { 92 this.cal = c; 93 RataDie.call(this, params); 94 if (params && typeof(params.callback) === 'function') { 95 params.callback(this); 96 } 97 }) 98 }); 99 } 100 }; 101 102 HanRataDie.prototype = new RataDie(); 103 HanRataDie.prototype.parent = RataDie; 104 HanRataDie.prototype.constructor = HanRataDie; 105 106 /** 107 * The difference between a zero Julian day and the first Han date 108 * which is February 15, -2636 (Gregorian). 109 * @private 110 * @type number 111 */ 112 HanRataDie.epoch = 758325.5; 113 114 /** 115 * Calculate the Rata Die (fixed day) number of the given date from the 116 * date components. 117 * 118 * @protected 119 * @param {Object} date the date components to calculate the RD from 120 */ 121 HanRataDie.prototype._setDateComponents = function(date) { 122 var calc = HanCal._leapYearCalc(date.year, date.cycle); 123 var m2 = HanCal._newMoonOnOrAfter(calc.m1+1); 124 var newYears; 125 this.leapYear = (Math.round((calc.m2 - calc.m1) / 29.530588853000001) === 12); 126 if (this.leapYear && (HanCal._noMajorST(calc.m1) || HanCal._noMajorST(m2)) ) { 127 newYears = HanCal._newMoonOnOrAfter(m2+1); 128 } else { 129 newYears = m2; 130 } 131 132 var priorNewMoon = HanCal._newMoonOnOrAfter(calc.m1 + date.month * 29); // this is a julian day 133 this.priorLeapMonth = HanRataDie._priorLeapMonth(newYears, HanCal._newMoonBefore(priorNewMoon)); 134 this.leapMonth = (this.leapYear && HanCal._noMajorST(priorNewMoon) && !this.priorLeapMonth); 135 136 var rdtime = (date.hour * 3600000 + 137 date.minute * 60000 + 138 date.second * 1000 + 139 date.millisecond) / 140 86400000; 141 142 /* 143 console.log("getRataDie: converting " + JSON.stringify(date) + " to an RD"); 144 console.log("getRataDie: year is " + date.year + " plus cycle " + date.cycle); 145 console.log("getRataDie: isLeapYear is " + this.leapYear); 146 console.log("getRataDie: priorNewMoon is " + priorNewMoon); 147 console.log("getRataDie: day in month is " + date.day); 148 console.log("getRataDie: rdtime is " + rdtime); 149 console.log("getRataDie: rd is " + (priorNewMoon + date.day - 1 + rdtime)); 150 */ 151 152 this.rd = priorNewMoon + date.day - 1 + rdtime - RataDie.gregorianEpoch; 153 }; 154 155 /** 156 * Return the rd number of the particular day of the week on or before the 157 * given rd. eg. The Sunday on or before the given rd. 158 * @private 159 * @param {number} rd the rata die date of the reference date 160 * @param {number} dayOfWeek the day of the week that is being sought relative 161 * to the current date 162 * @return {number} the rd of the day of the week 163 */ 164 HanRataDie.prototype._onOrBefore = function(rd, dayOfWeek) { 165 return rd - MathUtils.mod(Math.floor(rd) - dayOfWeek, 7); 166 }; 167 168 /** 169 * @protected 170 * @static 171 * @param {number} jd1 first julian day 172 * @param {number} jd2 second julian day 173 * @returns {boolean} true if there is a leap month earlier in the same year 174 * as the given months 175 */ 176 HanRataDie._priorLeapMonth = function(jd1, jd2) { 177 return jd2 >= jd1 && 178 (HanRataDie._priorLeapMonth(jd1, HanCal._newMoonBefore(jd2)) || 179 HanCal._noMajorST(jd2)); 180 }; 181 182 183 module.exports = HanRataDie;