1 /* 2 * PersRataDie.js - Represent a rata die date in the Persian 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 ilib = require("./ilib.js"); 21 var MathUtils = require("./MathUtils.js"); 22 23 var Astro = require("./Astro.js"); 24 var RataDie = require("./RataDie.js"); 25 var GregorianDate = require("./GregorianDate.js"); 26 27 /** 28 * @class 29 * Construct a new Persian RD date number object. The constructor parameters can 30 * contain any of the following properties: 31 * 32 * <ul> 33 * <li><i>unixtime<i> - sets the time of this instance according to the given 34 * unix time. Unix time is the number of milliseconds since midnight on Jan 1, 1970, Gregorian 35 * 36 * <li><i>julianday</i> - sets the time of this instance according to the given 37 * Julian Day instance or the Julian Day given as a float 38 * 39 * <li><i>year</i> - any integer, including 0 40 * 41 * <li><i>month</i> - 1 to 12, where 1 means Farvardin, 2 means Ordibehesht, etc. 42 * 43 * <li><i>day</i> - 1 to 31 44 * 45 * <li><i>hour</i> - 0 to 23. A formatter is used to display 12 hour clocks, but this representation 46 * is always done with an unambiguous 24 hour representation 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 Persian 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 Persian RD date 74 */ 75 var PersRataDie = function(params) { 76 this.rd = NaN; 77 Astro.initAstro( 78 params && typeof(params.sync) === 'boolean' ? params.sync : true, 79 params && params.loadParams, 80 ilib.bind(this, function (x) { 81 RataDie.call(this, params); 82 if (params && typeof(params.callback) === 'function') { 83 params.callback(this); 84 } 85 }) 86 ); 87 }; 88 89 PersRataDie.prototype = new RataDie(); 90 PersRataDie.prototype.parent = RataDie; 91 PersRataDie.prototype.constructor = PersRataDie; 92 93 /** 94 * The difference between a zero Julian day and the first Persian date 95 * @private 96 * @type number 97 */ 98 PersRataDie.prototype.epoch = 1948319.5; 99 100 /** 101 * @protected 102 */ 103 PersRataDie.prototype._tehranEquinox = function(year) { 104 var equJED, equJD, equAPP, equTehran, dtTehran, eot; 105 106 // March equinox in dynamical time 107 equJED = Astro._equinox(year, 0); 108 109 // Correct for delta T to obtain Universal time 110 equJD = equJED - (Astro._deltat(year) / (24 * 60 * 60)); 111 112 // Apply the equation of time to yield the apparent time at Greenwich 113 eot = Astro._equationOfTime(equJED) * 360; 114 eot = (eot - 20 * Math.floor(eot/20)) / 360; 115 equAPP = equJD + eot; 116 117 /* 118 * Finally, we must correct for the constant difference between 119 * the Greenwich meridian and the time zone standard for Iran 120 * Standard time, 52 degrees 30 minutes to the East. 121 */ 122 123 dtTehran = 52.5 / 360; 124 equTehran = equAPP + dtTehran; 125 126 return equTehran; 127 }; 128 129 /** 130 * Calculate the year based on the given Julian day. 131 * @protected 132 * @param {number} jd the Julian day to get the year for 133 * @return {{year:number,equinox:number}} the year and the last equinox 134 */ 135 PersRataDie.prototype._getYear = function(jd) { 136 var gd = new GregorianDate({julianday: jd}); 137 var guess = gd.getYears() - 2, 138 nexteq, 139 ret = {}; 140 141 //ret.equinox = Math.floor(this._tehranEquinox(guess)); 142 ret.equinox = this._tehranEquinox(guess); 143 while (ret.equinox > jd) { 144 guess--; 145 // ret.equinox = Math.floor(this._tehranEquinox(guess)); 146 ret.equinox = this._tehranEquinox(guess); 147 } 148 nexteq = ret.equinox - 1; 149 // if the equinox falls after noon, then the day after that is the start of the 150 // next year, so truncate the JD to get the noon of the day before the day with 151 //the equinox on it, then add 0.5 to get the midnight of that day 152 while (!(Math.floor(ret.equinox) + 0.5 <= jd && jd < Math.floor(nexteq) + 0.5)) { 153 ret.equinox = nexteq; 154 guess++; 155 // nexteq = Math.floor(this._tehranEquinox(guess)); 156 nexteq = this._tehranEquinox(guess); 157 } 158 159 // Mean solar tropical year is 365.24219878 days 160 ret.year = Math.round((ret.equinox - this.epoch - 1) / 365.24219878) + 1; 161 162 return ret; 163 }; 164 165 /** 166 * Calculate the Rata Die (fixed day) number of the given date from the 167 * date components. 168 * 169 * @protected 170 * @param {Object} date the date components to calculate the RD from 171 */ 172 PersRataDie.prototype._setDateComponents = function(date) { 173 var adr, guess, jd; 174 175 // Mean solar tropical year is 365.24219878 days 176 guess = this.epoch + 1 + 365.24219878 * ((date.year || 0) - 2); 177 adr = {year: (date.year || 0) - 1, equinox: 0}; 178 179 while (adr.year < date.year) { 180 adr = this._getYear(guess); 181 guess = adr.equinox + (365.24219878 + 2); 182 } 183 184 jd = Math.floor(adr.equinox) + 185 (((date.month || 0) <= 7) ? 186 (((date.month || 1) - 1) * 31) : 187 ((((date.month || 1) - 1) * 30) + 6) 188 ) + 189 ((date.day || 1) - 1 + 0.5); // add 0.5 so that we convert JDs, which start at noon to RDs which start at midnight 190 191 jd += ((date.hour || 0) * 3600000 + 192 (date.minute || 0) * 60000 + 193 (date.second || 0) * 1000 + 194 (date.millisecond || 0)) / 195 86400000; 196 197 this.rd = jd - this.epoch; 198 }; 199 200 /** 201 * Return the rd number of the particular day of the week on or before the 202 * given rd. eg. The Sunday on or before the given rd. 203 * @private 204 * @param {number} rd the rata die date of the reference date 205 * @param {number} dayOfWeek the day of the week that is being sought relative 206 * to the current date 207 * @return {number} the rd of the day of the week 208 */ 209 PersRataDie.prototype._onOrBefore = function(rd, dayOfWeek) { 210 return rd - MathUtils.mod(Math.floor(rd) - dayOfWeek - 3, 7); 211 }; 212 213 module.exports = PersRataDie;