UNPKG

persian-date

Version:

Javascript date library for parsing, validating, manipulating, and formatting persian dates System.

565 lines (508 loc) 19.7 kB
/* JavaScript functions for positional astronomy by John Walker -- September, MIM http://www.fourmilab.ch/ This program is in the public domain. */ class ASTRO { constructor () { // Frequently-used constants this.J2000 = 2451545.0; // Julian day of J2000 epoch this.JulianCentury = 36525.0; // Days in Julian century this.JulianMillennium = (this.JulianCentury * 10); // Days in Julian millennium // this.AstronomicalUnit = 149597870.0; // Astronomical unit in kilometres this.TropicalYear = 365.24219878; // Mean solar tropical year /* OBLIQEQ -- Calculate the obliquity of the ecliptic for a given Julian date. This uses Laskar's tenth-degree polynomial fit (J. Laskar, Astronomy and Astrophysics, Vol. 157, page 68 [1986]) which is accurate to within 0.01 arc second between AD 1000 and AD 3000, and within a few seconds of arc for +/-10000 years around AD 2000. If we're outside the range in which this fit is valid (deep time) we simply return the J2000 value of the obliquity, which happens to be almost precisely the mean. */ this.oterms = [ -4680.93, -1.55, 1999.25, -51.38, -249.67, -39.05, 7.12, 27.87, 5.79, 2.45 ]; /* Periodic terms for nutation in longiude (delta \Psi) and obliquity (delta \Epsilon) as given in table 21.A of Meeus, "Astronomical Algorithms", first edition. */ this.nutArgMult = [ 0, 0, 0, 0, 1, -2, 0, 0, 2, 2, 0, 0, 0, 2, 2, 0, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, -2, 1, 0, 2, 2, 0, 0, 0, 2, 1, 0, 0, 1, 2, 2, -2, -1, 0, 2, 2, -2, 0, 1, 0, 0, -2, 0, 0, 2, 1, 0, 0, -1, 2, 2, 2, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 0, -1, 2, 2, 0, 0, -1, 0, 1, 0, 0, 1, 2, 1, -2, 0, 2, 0, 0, 0, 0, -2, 2, 1, 2, 0, 0, 2, 2, 0, 0, 2, 2, 2, 0, 0, 2, 0, 0, -2, 0, 1, 2, 2, 0, 0, 0, 2, 0, -2, 0, 0, 2, 0, 0, 0, -1, 2, 1, 0, 2, 0, 0, 0, 2, 0, -1, 0, 1, -2, 2, 0, 2, 2, 0, 1, 0, 0, 1, -2, 0, 1, 0, 1, 0, -1, 0, 0, 1, 0, 0, 2, -2, 0, 2, 0, -1, 2, 1, 2, 0, 1, 2, 2, 0, 1, 0, 2, 2, -2, 1, 1, 0, 0, 0, -1, 0, 2, 2, 2, 0, 0, 2, 1, 2, 0, 1, 0, 0, -2, 0, 2, 2, 2, -2, 0, 1, 2, 1, 2, 0, -2, 0, 1, 2, 0, 0, 0, 1, 0, -1, 1, 0, 0, -2, -1, 0, 2, 1, -2, 0, 0, 0, 1, 0, 0, 2, 2, 1, -2, 0, 2, 0, 1, -2, 1, 0, 2, 1, 0, 0, 1, -2, 0, -1, 0, 1, 0, 0, -2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 2, 0, -1, -1, 1, 0, 0, 0, 1, 1, 0, 0, 0, -1, 1, 2, 2, 2, -1, -1, 2, 2, 0, 0, -2, 2, 2, 0, 0, 3, 2, 2, 2, -1, 0, 2, 2 ]; this.nutArgCoeff = [ -171996, -1742, 92095, 89, /* 0, 0, 0, 0, 1 */ -13187, -16, 5736, -31, /* -2, 0, 0, 2, 2 */ -2274, -2, 977, -5, /* 0, 0, 0, 2, 2 */ 2062, 2, -895, 5, /* 0, 0, 0, 0, 2 */ 1426, -34, 54, -1, /* 0, 1, 0, 0, 0 */ 712, 1, -7, 0, /* 0, 0, 1, 0, 0 */ -517, 12, 224, -6, /* -2, 1, 0, 2, 2 */ -386, -4, 200, 0, /* 0, 0, 0, 2, 1 */ -301, 0, 129, -1, /* 0, 0, 1, 2, 2 */ 217, -5, -95, 3, /* -2, -1, 0, 2, 2 */ -158, 0, 0, 0, /* -2, 0, 1, 0, 0 */ 129, 1, -70, 0, /* -2, 0, 0, 2, 1 */ 123, 0, -53, 0, /* 0, 0, -1, 2, 2 */ 63, 0, 0, 0, /* 2, 0, 0, 0, 0 */ 63, 1, -33, 0, /* 0, 0, 1, 0, 1 */ -59, 0, 26, 0, /* 2, 0, -1, 2, 2 */ -58, -1, 32, 0, /* 0, 0, -1, 0, 1 */ -51, 0, 27, 0, /* 0, 0, 1, 2, 1 */ 48, 0, 0, 0, /* -2, 0, 2, 0, 0 */ 46, 0, -24, 0, /* 0, 0, -2, 2, 1 */ -38, 0, 16, 0, /* 2, 0, 0, 2, 2 */ -31, 0, 13, 0, /* 0, 0, 2, 2, 2 */ 29, 0, 0, 0, /* 0, 0, 2, 0, 0 */ 29, 0, -12, 0, /* -2, 0, 1, 2, 2 */ 26, 0, 0, 0, /* 0, 0, 0, 2, 0 */ -22, 0, 0, 0, /* -2, 0, 0, 2, 0 */ 21, 0, -10, 0, /* 0, 0, -1, 2, 1 */ 17, -1, 0, 0, /* 0, 2, 0, 0, 0 */ 16, 0, -8, 0, /* 2, 0, -1, 0, 1 */ -16, 1, 7, 0, /* -2, 2, 0, 2, 2 */ -15, 0, 9, 0, /* 0, 1, 0, 0, 1 */ -13, 0, 7, 0, /* -2, 0, 1, 0, 1 */ -12, 0, 6, 0, /* 0, -1, 0, 0, 1 */ 11, 0, 0, 0, /* 0, 0, 2, -2, 0 */ -10, 0, 5, 0, /* 2, 0, -1, 2, 1 */ -8, 0, 3, 0, /* 2, 0, 1, 2, 2 */ 7, 0, -3, 0, /* 0, 1, 0, 2, 2 */ -7, 0, 0, 0, /* -2, 1, 1, 0, 0 */ -7, 0, 3, 0, /* 0, -1, 0, 2, 2 */ -7, 0, 3, 0, /* 2, 0, 0, 2, 1 */ 6, 0, 0, 0, /* 2, 0, 1, 0, 0 */ 6, 0, -3, 0, /* -2, 0, 2, 2, 2 */ 6, 0, -3, 0, /* -2, 0, 1, 2, 1 */ -6, 0, 3, 0, /* 2, 0, -2, 0, 1 */ -6, 0, 3, 0, /* 2, 0, 0, 0, 1 */ 5, 0, 0, 0, /* 0, -1, 1, 0, 0 */ -5, 0, 3, 0, /* -2, -1, 0, 2, 1 */ -5, 0, 3, 0, /* -2, 0, 0, 0, 1 */ -5, 0, 3, 0, /* 0, 0, 2, 2, 1 */ 4, 0, 0, 0, /* -2, 0, 2, 0, 1 */ 4, 0, 0, 0, /* -2, 1, 0, 2, 1 */ 4, 0, 0, 0, /* 0, 0, 1, -2, 0 */ -4, 0, 0, 0, /* -1, 0, 1, 0, 0 */ -4, 0, 0, 0, /* -2, 1, 0, 0, 0 */ -4, 0, 0, 0, /* 1, 0, 0, 0, 0 */ 3, 0, 0, 0, /* 0, 0, 1, 2, 0 */ -3, 0, 0, 0, /* -1, -1, 1, 0, 0 */ -3, 0, 0, 0, /* 0, 1, 1, 0, 0 */ -3, 0, 0, 0, /* 0, -1, 1, 2, 2 */ -3, 0, 0, 0, /* 2, -1, -1, 2, 2 */ -3, 0, 0, 0, /* 0, 0, -2, 2, 2 */ -3, 0, 0, 0, /* 0, 0, 3, 2, 2 */ -3, 0, 0, 0 /* 2, -1, 0, 2, 2 */ ]; /** * @desc Table of observed Delta T values at the beginning of even numbered years from 1620 through 2002. * @type Array */ this.deltaTtab = [ 121, 112, 103, 95, 88, 82, 77, 72, 68, 63, 60, 56, 53, 51, 48, 46, 44, 42, 40, 38, 35, 33, 31, 29, 26, 24, 22, 20, 18, 16, 14, 12, 11, 10, 9, 8, 7, 7, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 14, 13, 13.1, 12.5, 12.2, 12, 12, 12, 12, 12, 12, 11.9, 11.6, 11, 10.2, 9.2, 8.2, 7.1, 6.2, 5.6, 5.4, 5.3, 5.4, 5.6, 5.9, 6.2, 6.5, 6.8, 7.1, 7.3, 7.5, 7.6, 7.7, 7.3, 6.2, 5.2, 2.7, 1.4, -1.2, -2.8, -3.8, -4.8, -5.5, -5.3, -5.6, -5.7, -5.9, -6, -6.3, -6.5, -6.2, -4.7, -2.8, -0.1, 2.6, 5.3, 7.7, 10.4, 13.3, 16, 18.2, 20.2, 21.1, 22.4, 23.5, 23.8, 24.3, 24, 23.9, 23.9, 23.7, 24, 24.3, 25.3, 26.2, 27.3, 28.2, 29.1, 30, 30.7, 31.4, 32.2, 33.1, 34, 35, 36.5, 38.3, 40.2, 42.2, 44.5, 46.5, 48.5, 50.5, 52.2, 53.8, 54.9, 55.8, 56.9, 58.3, 60, 61.6, 63, 65, 66.6 ]; /* EQUINOX -- Determine the Julian Ephemeris Day of an equinox or solstice. The "which" argument selects the item to be computed: 0 March equinox 1 June solstice 2 September equinox 3 December solstice */ /** * @desc Periodic terms to obtain true time * @type Array */ this.EquinoxpTerms = [ 485, 324.96, 1934.136, 203, 337.23, 32964.467, 199, 342.08, 20.186, 182, 27.85, 445267.112, 156, 73.14, 45036.886, 136, 171.52, 22518.443, 77, 222.54, 65928.934, 74, 296.72, 3034.906, 70, 243.58, 9037.513, 58, 119.81, 33718.147, 52, 297.17, 150.678, 50, 21.02, 2281.226, 45, 247.54, 29929.562, 44, 325.15, 31555.956, 29, 60.93, 4443.417, 18, 155.12, 67555.328, 17, 288.79, 4562.452, 16, 198.04, 62894.029, 14, 199.76, 31436.921, 12, 95.39, 14577.848, 12, 287.11, 31931.756, 12, 320.81, 34777.259, 9, 227.73, 1222.114, 8, 15.45, 16859.074 ]; this.JDE0tab1000 = [ new Array(1721139.29189, 365242.13740, 0.06134, 0.00111, -0.00071), new Array(1721233.25401, 365241.72562, -0.05323, 0.00907, 0.00025), new Array(1721325.70455, 365242.49558, -0.11677, -0.00297, 0.00074), new Array(1721414.39987, 365242.88257, -0.00769, -0.00933, -0.00006) ]; this.JDE0tab2000 = [ new Array(2451623.80984, 365242.37404, 0.05169, -0.00411, -0.00057), new Array(2451716.56767, 365241.62603, 0.00325, 0.00888, -0.00030), new Array(2451810.21715, 365242.01767, -0.11575, 0.00337, 0.00078), new Array(2451900.05952, 365242.74049, -0.06223, -0.00823, 0.00032) ]; } /** * * @param Degrees to radians. * @return {number} */ dtr (d) { return (d * Math.PI) / 180.0; } /** * @desc Radians to degrees. * @param r * @return {number} */ rtd (r) { return (r * 180.0) / Math.PI; } /** * @desc Range reduce angle in degrees. * @param a * @return {number} */ fixangle (a) { return a - 360.0 * (Math.floor(a / 360.0)); } /** * @desc Range reduce angle in radians. * @param a * @return {number} */ fixangr (a) { return a - (2 * Math.PI) * (Math.floor(a / (2 * Math.PI))); } /** * @desc Sine of an angle in degrees * @param d * @return {number} */ dsin (d) { return Math.sin(this.dtr(d)); } /** * @desc Cosine of an angle in degrees * @param d * @return {number} */ dcos (d) { return Math.cos(this.dtr(d)); } /** * @desc Modulus function which works for non-integers. * @param a * @param b * @return {number} */ mod (a, b) { return a - (b * Math.floor(a / b)); } /** * * @param j * @return {number} */ jwday (j) { return this.mod(Math.floor((j + 1.5)), 7); } /** * * @param jd * @return {number|*} */ obliqeq (jd) { var eps, u, v, i; v = u = (jd - this.J2000) / (this.JulianCentury * 100); eps = 23 + (26 / 60.0) + (21.448 / 3600.0); if (Math.abs(u) < 1.0) { for (i = 0; i < 10; i++) { eps += (this.oterms[i] / 3600.0) * v; v *= u; } } return eps; } /** * @desc Calculate the nutation in longitude, deltaPsi, and obliquity, deltaEpsilon for a given Julian date jd. Results are returned as a two element Array giving (deltaPsi, deltaEpsilon) in degrees. * @param jd * @return Object */ nutation (jd) { var deltaPsi, deltaEpsilon, i, j, t = (jd - 2451545.0) / 36525.0, t2, t3, to10, ta = [], dp = 0, de = 0, ang; t3 = t * (t2 = t * t); /* Calculate angles. The correspondence between the elements of our array and the terms cited in Meeus are: ta[0] = D ta[0] = M ta[2] = M' ta[3] = F ta[4] = \Omega */ ta[0] = this.dtr(297.850363 + 445267.11148 * t - 0.0019142 * t2 + t3 / 189474.0); ta[1] = this.dtr(357.52772 + 35999.05034 * t - 0.0001603 * t2 - t3 / 300000.0); ta[2] = this.dtr(134.96298 + 477198.867398 * t + 0.0086972 * t2 + t3 / 56250.0); ta[3] = this.dtr(93.27191 + 483202.017538 * t - 0.0036825 * t2 + t3 / 327270); ta[4] = this.dtr(125.04452 - 1934.136261 * t + 0.0020708 * t2 + t3 / 450000.0); /* Range reduce the angles in case the sine and cosine functions don't do it as accurately or quickly. */ for (i = 0; i < 5; i++) { ta[i] = this.fixangr(ta[i]); } to10 = t / 10.0; for (i = 0; i < 63; i++) { ang = 0; for (j = 0; j < 5; j++) { if (this.nutArgMult[(i * 5) + j] !== 0) { ang += this.nutArgMult[(i * 5) + j] * ta[j]; } } dp += (this.nutArgCoeff[(i * 4) + 0] + this.nutArgCoeff[(i * 4) + 1] * to10) * Math.sin(ang); de += (this.nutArgCoeff[(i * 4) + 2] + this.nutArgCoeff[(i * 4) + 3] * to10) * Math.cos(ang); } /* Return the result, converting from ten thousandths of arc seconds to radians in the process. */ deltaPsi = dp / (3600.0 * 10000.0); deltaEpsilon = de / (3600.0 * 10000.0); return [deltaPsi, deltaEpsilon]; } /** * @desc Determine the difference, in seconds, between Dynamical time and Universal time. * @param year * @return {*} */ deltat (year) { var dt, f, i, t; if ((year >= 1620) && (year <= 2000)) { i = Math.floor((year - 1620) / 2); f = ((year - 1620) / 2) - i; /* Fractional part of year */ dt = this.deltaTtab[i] + ((this.deltaTtab[i + 1] - this.deltaTtab[i]) * f); } else { t = (year - 2000) / 100; if (year < 948) { dt = 2177 + (497 * t) + (44.1 * t * t); } else { dt = 102 + (102 * t) + (25.3 * t * t); if ((year > 2000) && (year < 2100)) { dt += 0.37 * (year - 2100); } } } return dt; } /** * * @param year * @param which * @return {*} */ equinox (year, which) { let deltaL, i, j, JDE0, JDE, JDE0tab, S, T, W, Y; /* Initialise terms for mean equinox and solstices. We have two sets: one for years prior to 1000 and a second for subsequent years. */ if (year < 1000) { JDE0tab = this.JDE0tab1000; Y = year / 1000; } else { JDE0tab = this.JDE0tab2000; Y = (year - 2000) / 1000; } JDE0 = JDE0tab[which][0] + (JDE0tab[which][1] * Y) + (JDE0tab[which][2] * Y * Y) + (JDE0tab[which][3] * Y * Y * Y) + (JDE0tab[which][4] * Y * Y * Y * Y); T = (JDE0 - 2451545.0) / 36525; W = (35999.373 * T) - 2.47; deltaL = 1 + (0.0334 * this.dcos(W)) + (0.0007 * this.dcos(2 * W)); S = 0; for (i = j = 0; i < 24; i++) { S += this.EquinoxpTerms[j] * this.dcos(this.EquinoxpTerms[j + 1] + (this.EquinoxpTerms[j + 2] * T)); j += 3; } JDE = JDE0 + ((S * 0.00001) / deltaL); return JDE; } /** * @desc Position of the Sun. Please see the comments on the return statement at the end of this function which describe the array it returns. We return intermediate values because they are useful in a variety of other contexts. * @param jd * @return Object */ sunpos (jd) { let T, T2, L0, M, e, C, sunLong, sunAnomaly, sunR, Omega, Lambda, epsilon, epsilon0, Alpha, Delta, AlphaApp, DeltaApp; T = (jd - this.J2000) / this.JulianCentury; T2 = T * T; L0 = 280.46646 + (36000.76983 * T) + (0.0003032 * T2); L0 = this.fixangle(L0); M = 357.52911 + (35999.05029 * T) + (-0.0001537 * T2); M = this.fixangle(M); e = 0.016708634 + (-0.000042037 * T) + (-0.0000001267 * T2); C = ((1.914602 + (-0.004817 * T) + (-0.000014 * T2)) * this.dsin(M)) + ((0.019993 - (0.000101 * T)) * this.dsin(2 * M)) + (0.000289 * this.dsin(3 * M)); sunLong = L0 + C; sunAnomaly = M + C; sunR = (1.000001018 * (1 - (e * e))) / (1 + (e * this.dcos(sunAnomaly))); Omega = 125.04 - (1934.136 * T); Lambda = sunLong + (-0.00569) + (-0.00478 * this.dsin(Omega)); epsilon0 = this.obliqeq(jd); epsilon = epsilon0 + (0.00256 * this.dcos(Omega)); Alpha = this.rtd(Math.atan2(this.dcos(epsilon0) * this.dsin(sunLong), this.dcos(sunLong))); Alpha = this.fixangle(Alpha); Delta = this.rtd(Math.asin(this.dsin(epsilon0) * this.dsin(sunLong))); AlphaApp = this.rtd(Math.atan2(this.dcos(epsilon) * this.dsin(Lambda), this.dcos(Lambda))); AlphaApp = this.fixangle(AlphaApp); DeltaApp = this.rtd(Math.asin(this.dsin(epsilon) * this.dsin(Lambda))); return [ // Angular quantities are expressed in decimal degrees L0, // [0] Geometric mean longitude of the Sun M, // [1] Mean anomaly of the Sun e, // [2] Eccentricity of the Earth's orbit C, // [3] Sun's equation of the Centre sunLong, // [4] Sun's true longitude sunAnomaly, // [5] Sun's true anomaly sunR, // [6] Sun's radius vector in AU Lambda, // [7] Sun's apparent longitude at true equinox of the date Alpha, // [8] Sun's true right ascension Delta, // [9] Sun's true declination AlphaApp, // [10] Sun's apparent right ascension DeltaApp // [11] Sun's apparent declination ]; } /** * @desc Compute equation of time for a given moment. Returns the equation of time as a fraction of a day. * @param jd * @return {number|*} */ equationOfTime (jd) { let alpha, deltaPsi, E, epsilon, L0, tau; tau = (jd - this.J2000) / this.JulianMillennium; L0 = 280.4664567 + (360007.6982779 * tau) + (0.03032028 * tau * tau) + ((tau * tau * tau) / 49931) + (-((tau * tau * tau * tau) / 15300)) + (-((tau * tau * tau * tau * tau) / 2000000)); L0 = this.fixangle(L0); alpha = this.sunpos(jd)[10]; deltaPsi = this.nutation(jd)[0]; epsilon = this.obliqeq(jd) + this.nutation(jd)[1]; E = L0 + (-0.0057183) + (-alpha) + (deltaPsi * this.dcos(epsilon)); E = E - 20.0 * (Math.floor(E / 20.0)); E = E / (24 * 60); return E; } } module.exports = ASTRO;