1 /*
  2  * ThaiSolarDate.js - Represent a date in the ThaiSolar calendar
  3  *
  4  * Copyright © 2013-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 ilib = require("./ilib.js");
 21 var JSUtils = require("./JSUtils.js");
 22 
 23 var IDate = require("./IDate.js");
 24 
 25 var ThaiSolarCal = require("./ThaiSolarCal.js");
 26 var GregorianDate = require("./GregorianDate.js");
 27 
 28 /**
 29  * @class
 30  * Construct a new Thai solar date object. The constructor parameters can
 31  * contain any of the following properties:
 32  *
 33  * <ul>
 34  * <li><i>unixtime<i> - sets the time of this instance according to the given
 35  * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970.
 36  *
 37  * <li><i>julianday</i> - sets the time of this instance according to the given
 38  * Julian Day instance or the Julian Day given as a float
 39  *
 40  * <li><i>year</i> - any integer, including 0
 41  *
 42  * <li><i>month</i> - 1 to 12, where 1 means January, 2 means February, etc.
 43  *
 44  * <li><i>day</i> - 1 to 31
 45  *
 46  * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation
 47  * is always done with an unambiguous 24 hour representation
 48  *
 49  * <li><i>minute</i> - 0 to 59
 50  *
 51  * <li><i>second</i> - 0 to 59
 52  *
 53  * <li><i>millisecond</i> - 0 to 999
 54  *
 55  * <li><i>timezone</i> - the TimeZone instance or time zone name as a string
 56  * of this Thai solar date. The date/time is kept in the local time. The time zone
 57  * is used later if this date is formatted according to a different time zone and
 58  * the difference has to be calculated, or when the date format has a time zone
 59  * component in it.
 60  *
 61  * <li><i>locale</i> - locale for this Thai solar date. If the time zone is not
 62  * given, it can be inferred from this locale. For locales that span multiple
 63  * time zones, the one with the largest population is chosen as the one that
 64  * represents the locale.
 65  * </ul>
 66  *
 67  * If the constructor is called with another Thai solar date instance instead of
 68  * a parameter block, the other instance acts as a parameter block and its
 69  * settings are copied into the current instance.<p>
 70  *
 71  * If the constructor is called with no arguments at all or if none of the
 72  * properties listed above
 73  * from <i>unixtime</i> through <i>millisecond</i> are present, then the date
 74  * components are
 75  * filled in with the current date at the time of instantiation. Note that if
 76  * you do not give the time zone when defaulting to the current time and the
 77  * time zone for all of ilib was not set with <i>ilib.setTimeZone()</i>, then the
 78  * time zone will default to UTC ("Universal Time, Coordinated" or "Greenwich
 79  * Mean Time").<p>
 80  *
 81  * If any of the properties from <i>year</i> through <i>millisecond</i> are not
 82  * specified in the params, it is assumed that they have the smallest possible
 83  * value in the range for the property (zero or one).<p>
 84  *
 85  *
 86  * @constructor
 87  * @extends GregorianDate
 88  * @param {Object=} params parameters that govern the settings and behaviour of this Thai solar date
 89  */
 90 var ThaiSolarDate = function(params) {
 91     var p = {};
 92 
 93     if (params) {
 94         JSUtils.shallowCopy(params, p);
 95 
 96         // there is 198327 days difference between the Thai solar and
 97         // Gregorian epochs which is equivalent to 543 years
 98         if (typeof(p.year) !== 'undefined') {
 99             p.year -= 543;
100         }
101         if (typeof(p.rd) !== 'undefined') {
102             p.rd -= 198327;
103         }
104     }
105     this.rd = null; // clear these out so that the GregorianDate constructor can set it
106     this.offset = undefined;
107     //console.log("ThaiSolarDate.constructor: date is " + JSON.stringify(this) + " parent is " + JSON.stringify(this.parent) + " and parent.parent is " + JSON.stringify(this.parent.parent));
108 
109     p.onLoad = ilib.bind(this, function(gd) {
110         this.cal = new ThaiSolarCal();
111 
112         // make sure the year is set correctly from the original params
113         if (params && typeof(params.year) !== 'undefined') {
114             this.year = parseInt(params.year, 10);
115         }
116 
117         if (params && typeof(params.onLoad) === "function") {
118             params.onLoad(gd);
119         }
120     });
121 
122     GregorianDate.call(this, p);
123 };
124 
125 ThaiSolarDate.prototype = new GregorianDate({noinstance: true});
126 ThaiSolarDate.prototype.parent = GregorianDate.prototype;
127 ThaiSolarDate.prototype.constructor = ThaiSolarDate;
128 
129 /**
130  * the difference between a zero Julian day and the zero Thai Solar date.
131  * This is some 543 years before the start of the Gregorian epoch.
132  * @private
133  * @type number
134  */
135 ThaiSolarDate.epoch = 1523097.5;
136 
137 /**
138  * Calculate the date components for the current time zone
139  * @protected
140  */
141 ThaiSolarDate.prototype._calcDateComponents = function () {
142     // there is 198327 days difference between the Thai solar and
143     // Gregorian epochs which is equivalent to 543 years
144     // console.log("ThaiSolarDate._calcDateComponents: date is " + JSON.stringify(this) + " parent is " + JSON.stringify(this.parent) + " and parent.parent is " + JSON.stringify(this.parent.parent));
145     this.parent._calcDateComponents.call(this);
146     this.year += 543;
147 };
148 
149 /**
150  * Return the Rata Die (fixed day) number of this date.
151  *
152  * @protected
153  * @return {number} the rd date as a number
154  */
155 ThaiSolarDate.prototype.getRataDie = function() {
156     // there is 198327 days difference between the Thai solar and
157     // Gregorian epochs which is equivalent to 543 years
158     return this.rd.getRataDie() + 198327;
159 };
160 
161 /**
162  * Return a new Gregorian date instance that represents the first instance of the
163  * given day of the week before the current date. The day of the week is encoded
164  * as a number where 0 = Sunday, 1 = Monday, etc.
165  *
166  * @param {number} dow the day of the week before the current date that is being sought
167  * @return {IDate} the date being sought
168  */
169 ThaiSolarDate.prototype.before = function (dow) {
170     return new ThaiSolarDate({
171         rd: this.rd.before(dow, this.offset) + 198327,
172         timezone: this.timezone
173     });
174 };
175 
176 /**
177  * Return a new Gregorian date instance that represents the first instance of the
178  * given day of the week after the current date. The day of the week is encoded
179  * as a number where 0 = Sunday, 1 = Monday, etc.
180  *
181  * @param {number} dow the day of the week after the current date that is being sought
182  * @return {IDate} the date being sought
183  */
184 ThaiSolarDate.prototype.after = function (dow) {
185     return new ThaiSolarDate({
186         rd: this.rd.after(dow, this.offset) + 198327,
187         timezone: this.timezone
188     });
189 };
190 
191 /**
192  * Return a new Gregorian date instance that represents the first instance of the
193  * given day of the week on or before the current date. The day of the week is encoded
194  * as a number where 0 = Sunday, 1 = Monday, etc.
195  *
196  * @param {number} dow the day of the week on or before the current date that is being sought
197  * @return {IDate} the date being sought
198  */
199 ThaiSolarDate.prototype.onOrBefore = function (dow) {
200     return new ThaiSolarDate({
201         rd: this.rd.onOrBefore(dow, this.offset) + 198327,
202         timezone: this.timezone
203     });
204 };
205 
206 /**
207  * Return a new Gregorian date instance that represents the first instance of the
208  * given day of the week on or after the current date. The day of the week is encoded
209  * as a number where 0 = Sunday, 1 = Monday, etc.
210  *
211  * @param {number} dow the day of the week on or after the current date that is being sought
212  * @return {IDate} the date being sought
213  */
214 ThaiSolarDate.prototype.onOrAfter = function (dow) {
215     return new ThaiSolarDate({
216         rd: this.rd.onOrAfter(dow, this.offset) + 198327,
217         timezone: this.timezone
218     });
219 };
220 
221 /**
222  * Return the name of the calendar that governs this date.
223  *
224  * @return {string} a string giving the name of the calendar
225  */
226 ThaiSolarDate.prototype.getCalendar = function() {
227     return "thaisolar";
228 };
229 
230 //register with the factory method
231 IDate._constructors["thaisolar"] = ThaiSolarDate;
232 
233 module.exports = ThaiSolarDate;
234