1 /*
  2  * GregRataDie.js - Represent the RD date number in the Gregorian calendar
  3  *
  4  * Copyright © 2014-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 MathUtils = require("./MathUtils.js");
 21 var GregorianCal = require("./GregorianCal.js");
 22 var RataDie = require("./RataDie.js");
 23 
 24 /**
 25  * @class
 26  * Construct a new Gregorian 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>minute</i> - 0 to 59
 46  *
 47  * <li><i>second</i> - 0 to 59
 48  *
 49  * <li><i>millisecond</i> - 0 to 999
 50  *
 51  * <li><i>date</i> - use the given intrinsic Javascript date to initialize this one.
 52  * </ul>
 53  *
 54  * If the constructor is called with another Gregorian date instance instead of
 55  * a parameter block, the other instance acts as a parameter block and its
 56  * settings are copied into the current instance.<p>
 57  *
 58  * If the constructor is called with no arguments at all or if none of the
 59  * properties listed above are present, then the RD is calculate based on
 60  * the current date at the time of instantiation. <p>
 61  *
 62  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
 63  * specified in the params, it is assumed that they have the smallest possible
 64  * value in the range for the property (zero or one).<p>
 65  *
 66  *
 67  * @private
 68  * @constructor
 69  * @extends RataDie
 70  * @param {Object=} params parameters that govern the settings and behaviour of this Gregorian RD date
 71  */
 72 var GregRataDie = function(params) {
 73     this.cal = params && params.cal || new GregorianCal();
 74     /** @type {number|undefined} */
 75     this.rd = NaN;
 76     RataDie.call(this, params);
 77 };
 78 
 79 GregRataDie.prototype = new RataDie();
 80 GregRataDie.prototype.parent = RataDie;
 81 GregRataDie.prototype.constructor = GregRataDie;
 82 
 83 /**
 84  * the cumulative lengths of each month, for a non-leap year
 85  * @private
 86  * @const
 87  * @type Array.<number>
 88  */
 89 GregRataDie.cumMonthLengths = [
 90     0,   /* Jan */
 91     31,  /* Feb */
 92     59,  /* Mar */
 93     90,  /* Apr */
 94     120, /* May */
 95     151, /* Jun */
 96     181, /* Jul */
 97     212, /* Aug */
 98     243, /* Sep */
 99     273, /* Oct */
100     304, /* Nov */
101     334, /* Dec */
102     365
103 ];
104 
105 /**
106  * the cumulative lengths of each month, for a leap year
107  * @private
108  * @const
109  * @type Array.<number>
110  */
111 GregRataDie.cumMonthLengthsLeap = [
112     0,   /* Jan */
113     31,  /* Feb */
114     60,  /* Mar */
115     91,  /* Apr */
116     121, /* May */
117     152, /* Jun */
118     182, /* Jul */
119     213, /* Aug */
120     244, /* Sep */
121     274, /* Oct */
122     305, /* Nov */
123     335, /* Dec */
124     366
125 ];
126 
127 /**
128  * Calculate the Rata Die (fixed day) number of the given date.
129  *
130  * @private
131  * @param {Object} date the date components to calculate the RD from
132  */
133 GregRataDie.prototype._setDateComponents = function(date) {
134     var year = parseInt(date.year, 10) || 0;
135     var month = parseInt(date.month, 10) || 1;
136     var day = parseInt(date.day, 10) || 1;
137     var hour = parseInt(date.hour, 10) || 0;
138     var minute = parseInt(date.minute, 10) || 0;
139     var second = parseInt(date.second, 10) || 0;
140     var millisecond = parseInt(date.millisecond, 10) || 0;
141 
142     var years = 365 * (year - 1) +
143         Math.floor((year-1)/4) -
144         Math.floor((year-1)/100) +
145         Math.floor((year-1)/400);
146 
147     var dayInYear = (month > 1 ? GregRataDie.cumMonthLengths[month-1] : 0) +
148         day +
149         (GregorianCal.prototype.isLeapYear.call(this.cal, year) && month > 2 ? 1 : 0);
150     var rdtime = (hour * 3600000 +
151         minute * 60000 +
152         second * 1000 +
153         millisecond) /
154         86400000;
155     /*
156     debug("getRataDie: converting " +  JSON.stringify(this));
157     debug("getRataDie: year is " +  years);
158     debug("getRataDie: day in year is " +  dayInYear);
159     debug("getRataDie: rdtime is " +  rdtime);
160     debug("getRataDie: rd is " +  (years + dayInYear + rdtime));
161     */
162 
163     /**
164      * @type {number|undefined} the RD number of this Gregorian date
165      */
166     this.rd = years + dayInYear + rdtime;
167 };
168 
169 /**
170  * Return the rd number of the particular day of the week on or before the
171  * given rd. eg. The Sunday on or before the given rd.
172  * @private
173  * @param {number} rd the rata die date of the reference date
174  * @param {number} dayOfWeek the day of the week that is being sought relative
175  * to the current date
176  * @return {number} the rd of the day of the week
177  */
178 GregRataDie.prototype._onOrBefore = function(rd, dayOfWeek) {
179     return rd - MathUtils.mod(Math.floor(rd) - dayOfWeek, 7);
180 };
181 
182 module.exports = GregRataDie;
183