diff --git a/.travis.yml b/.travis.yml index 3a3b039..3ec9d0d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: node_js node_js: -- "0.10" +- "4.4" +- "5.8" diff --git a/lib/julian.js b/lib/julian.js index 8882e0a..d714b92 100644 --- a/lib/julian.js +++ b/lib/julian.js @@ -1,14 +1,12 @@ -(function() { - "use strict"; +'use strict' - function fromDate(date) { - return date.getTime() / 86400000 + 2440587.5; - } +function fromDate (date) { + return date.getTime() / 86400000 + 2440587.5 +} - function toDate(julian) { - return new Date((julian - 2440587.5) * 86400000); - } +function toDate (julian) { + return new Date((julian - 2440587.5) * 86400000) +} - exports.fromDate = fromDate; - exports.toDate = toDate; -})(); +exports.fromDate = fromDate +exports.toDate = toDate diff --git a/lib/lune.js b/lib/lune.js index 83e95f9..00ac1cf 100644 --- a/lib/lune.js +++ b/lib/lune.js @@ -8,309 +8,245 @@ * Author: Ryan Seys (https://github.com/ryanseys) */ -(function() { - "use strict"; +'use strict' - var julian = require("./julian"); +const julian = require('./julian') - // Phases of the moon & precision - var PRECISION = 0.05; - var NEW = 0 / 4.0; - var FIRST = 1 / 4.0; - var FULL = 2 / 4.0; - var LAST = 3 / 4.0; - var NEXTNEW = 4 / 4.0; +// Phases of the moon & precision +const NEW = 0 +const FIRST = 1 +const FULL = 2 +const LAST = 3 +const PHASE_MASK = 3 - // Astronomical Constants - // JDN stands for Julian Day Number - // Angles here are in degrees +// Astronomical Constants +// JDN stands for Julian Day Number +// Angles here are in degrees +// 1980 January 0.0 in JDN +// XXX: DateTime(1980).jdn yields 2444239.5 -- which one is right? +// XXX: even though 2444239.5 is correct for the 1 Jan 1980, 2444238.5 gives +// better accuracy results... possibly somebody chose all of the below +// constants based on the wrong epoch? +const EPOCH = 2444238.5 - // 1980 January 0.0 in JDN - // XXX: DateTime(1980).jdn yields 2444239.5 -- which one is right? - var EPOCH = 2444238.5; +// Ecliptic longitude of the Sun at epoch 1980.0 +const ECLIPTIC_LONGITUDE_EPOCH = 278.833540 - // Ecliptic longitude of the Sun at epoch 1980.0 - var ECLIPTIC_LONGITUDE_EPOCH = 278.833540; +// Ecliptic longitude of the Sun at perigee +const ECLIPTIC_LONGITUDE_PERIGEE = 282.596403 - // Ecliptic longitude of the Sun at perigee - var ECLIPTIC_LONGITUDE_PERIGEE = 282.596403; +// Eccentricity of Earth's orbit +const ECCENTRICITY = 0.016718 - // Eccentricity of Earth's orbit - var ECCENTRICITY = 0.016718; +// Semi-major axis of Earth's orbit, in kilometers +const SUN_SMAXIS = 1.49585e8 - // Semi-major axis of Earth's orbit, in kilometers - var SUN_SMAXIS = 1.49585e8; +// Sun's angular size, in degrees, at semi-major axis distance +const SUN_ANGULAR_SIZE_SMAXIS = 0.533128 - // Sun's angular size, in degrees, at semi-major axis distance - var SUN_ANGULAR_SIZE_SMAXIS = 0.533128; +// Elements of the Moon's orbit, epoch 1980.0 +// Moon's mean longitude at the epoch +const MOON_MEAN_LONGITUDE_EPOCH = 64.975464 - // Elements of the Moon's orbit, epoch 1980.0 - // Moon's mean longitude at the epoch - var MOON_MEAN_LONGITUDE_EPOCH = 64.975464; +// Mean longitude of the perigee at the epoch +const MOON_MEAN_PERIGEE_EPOCH = 349.383063 - // Mean longitude of the perigee at the epoch - var MOON_MEAN_PERIGEE_EPOCH = 349.383063; +// Eccentricity of the Moon's orbit +const MOON_ECCENTRICITY = 0.054900 - // Mean longitude of the node at the epoch - var NODE_MEAN_LONGITUDE_EPOCH = 151.950429; +// Semi-major axis of the Moon's orbit, in kilometers +const MOON_SMAXIS = 384401.0 - // Inclination of the Moon's orbit - var MOON_INCLINATION = 5.145396; +// MOON_SMAXIS premultiplied by the angular size of the Moon from the Earth +const MOON_ANGULAR_SIZE_SMAXIS = MOON_SMAXIS * 0.5181 - // Eccentricity of the Moon's orbit - var MOON_ECCENTRICITY = 0.054900; +// Synodic month (new Moon to new Moon), in days +const SYNODIC_MONTH = 29.53058868 - // Moon's angular size at distance a from Earth - var MOON_ANGULAR_SIZE = 0.5181; +function fixangle (a) { + return a - 360.0 * Math.floor(a / 360.0) +} - // Semi-mojor axis of the Moon's orbit, in kilometers - var MOON_SMAXIS = 384401.0; - - // Parallax at a distance a from Earth - var MOON_PARALLAX = 0.9507; - - // Synodic month (new Moon to new Moon), in days - var SYNODIC_MONTH = 29.53058868; - - // Base date for E. W. Brown's numbered series of lunations (1923 January 16) - var LUNATIONS_BASE = 2423436.0; - - // Properties of the Earth - var EARTH_RADIUS = 6378.16; +/** + * Convert degrees to radians + * @param {Number} d Angle in degrees + * @return {Number} Angle in radians + */ +function torad (d) { + return (Math.PI / 180.0) * d +} - function fixangle(a) { - return a - 360.0 * Math.floor(a/360.0); - } +/** + * Convert radians to degrees + * @param {Number} r Angle in radians + * @return {Number} Angle in degrees + */ +function todeg (r) { + return (180.0 / Math.PI) * r +} - /** - * Convert degrees to radians - * @param {Number} d Angle in degrees - * @return {Number} Angle in radians - */ - function torad(d) { - return d * Math.PI / 180.0; - } +function dsin (d) { + return Math.sin(torad(d)) +} - /** - * Convert radians to degrees - * @param {Number} r Angle in radians - * @return {Number} Angle in degrees - */ - function todeg(r) { - return r * 180.0 / Math.PI; - } +function dcos (d) { + return Math.cos(torad(d)) +} - function dsin(d) { - return Math.sin(torad(d)); - } +/** + * Solve the equation of Kepler. + */ +function kepler (m, ecc) { + const epsilon = 1e-6 - function dcos(d) { - return Math.cos(torad(d)); - } + m = torad(m) + let e = m + while (1) { + const delta = e - ecc * Math.sin(e) - m + e -= delta / (1.0 - ecc * Math.cos(e)) - /** - * Solve the equation of Kepler. - */ - function kepler(m, ecc) { - var epsilon = 1e-6; - - m = torad(m); - var e = m; - while(1) { - var delta = e - ecc * Math.sin(e) - m; - e = e - delta / (1.0 - ecc * Math.cos(e)); - - if (Math.abs(delta) <= epsilon) { - break; - } + if (Math.abs(delta) <= epsilon) { + break } - - return e; } - /** - * Finds the phase information for specific date. - * @param {Date} phase_date Date to get phase information of. - * @return {Object} Phase data - */ - function phase(phase_date) { - if(!phase_date) { - phase_date = new Date(); - } - phase_date = julian.fromDate(phase_date); - - var day = phase_date - EPOCH; - - // Mean anomaly of the Sun - var N = fixangle((360/365.2422) * day); - //Convert from perigee coordinates to epoch 1980 - var M = fixangle(N + ECLIPTIC_LONGITUDE_EPOCH - ECLIPTIC_LONGITUDE_PERIGEE); - - // Solve Kepler's equation - var Ec = kepler(M, ECCENTRICITY); - Ec = Math.sqrt((1 + ECCENTRICITY) / (1 - ECCENTRICITY)) * Math.tan(Ec / 2); - // True anomaly - Ec = 2 * todeg(Math.atan(Ec)); - // Suns's geometric ecliptic longuitude - var lambda_sun = fixangle(Ec + ECLIPTIC_LONGITUDE_PERIGEE); - - // Orbital distance factor - var F = ((1 + ECCENTRICITY * Math.cos(torad(Ec))) / (1 - ECCENTRICITY * ECCENTRICITY)); - - // Distance to Sun in km - var sun_dist = SUN_SMAXIS / F; - var sun_angular_diameter = F * SUN_ANGULAR_SIZE_SMAXIS; - - // Calculation of the Moon's position - - // Moon's mean longitude - var moon_longitude = fixangle(13.1763966 * day + MOON_MEAN_LONGITUDE_EPOCH); - - // Moon's mean anomaly - var MM = fixangle(moon_longitude - 0.1114041 * day - MOON_MEAN_PERIGEE_EPOCH); - - // Moon's ascending node mean longitude - // MN = fixangle(NODE_MEAN_LONGITUDE_EPOCH - 0.0529539 * day) - - var evection = 1.2739 * Math.sin(torad(2*(moon_longitude - lambda_sun) - MM)); - - // Annual equation - var annual_eq = 0.1858 * Math.sin(torad(M)); - - // Correction term - var A3 = 0.37 * Math.sin(torad(M)); - - var MmP = MM + evection - annual_eq - A3; - - // Correction for the equation of the centre - var mEc = 6.2886 * Math.sin(torad(MmP)); - - // Another correction term - var A4 = 0.214 * Math.sin(torad(2 * MmP)); - - // Corrected longitude - var lP = moon_longitude + evection + mEc - annual_eq + A4; - - // Variation - var variation = 0.6583 * Math.sin(torad(2*(lP - lambda_sun))); - - // True longitude - var lPP = lP + variation; + return e +} - // Calculation of the phase of the Moon - - // Age of the Moon, in degrees - var moon_age = lPP - lambda_sun; - - // Phase of the Moon - var moon_phase = (1 - Math.cos(torad(moon_age))) / 2.0; - - // Calculate distance of Moon from the centre of the Earth - var moon_dist = (MOON_SMAXIS * (1 - MOON_ECCENTRICITY * MOON_ECCENTRICITY)) / (1 + MOON_ECCENTRICITY * Math.cos(torad(MmP + mEc))); - - // Calculate Moon's angular diameter - var moon_diam_frac = moon_dist / MOON_SMAXIS; - var moon_angular_diameter = MOON_ANGULAR_SIZE / moon_diam_frac; - - // Calculate Moon's parallax (unused?) - // moon_parallax = MOON_PARALLAX / moon_diam_frac - - return { - phase: fixangle(moon_age) / 360.0, - illuminated: moon_phase, - age: SYNODIC_MONTH * fixangle(moon_age) / 360.0, - distance: moon_dist, - angular_diameter: moon_angular_diameter, - sun_distance: sun_dist, - sun_angular_diameter: sun_angular_diameter - }; +/** + * Finds the phase information for specific date. + * @param {Date} phase_date Date to get phase information of. + * @return {Object} Phase data + */ +function phase (phase_date) { + if (!phase_date) { + phase_date = new Date() } - - /** - * Find time of phases of the moon which surround the current date. - * Five phases are found, starting and ending with the new moons - * which bound the current lunation. - * @param {Date} sdate Date to start hunting from (defaults to current date) - * @return {Object} Object containing recent past and future phases - */ - function phase_hunt(sdate) { - if(!sdate) { - sdate = new Date(); - } - - var adate = new Date(sdate.getTime()); // today! - var x = 45; // go back 45 days! - adate.setDate(adate.getDate() - x); - - var k1 = Math.floor((adate.getFullYear() + ((adate.getMonth()) * (1.0/12.0)) - 1900) * 12.3685); - var nt1 = meanphase(adate, k1); - adate = nt1; - - sdate = julian.fromDate(sdate); - var k2; - while(1) { - adate = adate + SYNODIC_MONTH; - k2 = k1 + 1; - var nt2 = meanphase(adate, k2); - if(nt1 <= sdate && sdate < nt2) { - break; - } - nt1 = nt2; - k1 = k2; - } - var ks = [k1, k1, k1, k1, k2]; - var tphases = [NEW, FIRST, FULL, LAST, NEW]; - var phase_names = ['new_date', 'q1_date', 'full_date', 'q3_date', 'nextnew_date']; - var phases = {}; - - for (var i = 0; i < ks.length; i++) { - phases[phase_names[i]] = truephase(ks[i], tphases[i]); - } - - return phases; + phase_date = julian.fromDate(phase_date) + + const day = phase_date - EPOCH + + // calculate sun position + const sun_mean_anomaly = + (360.0 / 365.2422) * day + + (ECLIPTIC_LONGITUDE_EPOCH - ECLIPTIC_LONGITUDE_PERIGEE) + const sun_true_anomaly = + 2 * todeg(Math.atan( + Math.sqrt((1.0 + ECCENTRICITY) / (1.0 - ECCENTRICITY)) * + Math.tan(0.5 * kepler(sun_mean_anomaly, ECCENTRICITY)) + )) + const sun_ecliptic_longitude = + ECLIPTIC_LONGITUDE_PERIGEE + sun_true_anomaly + const sun_orbital_distance_factor = + (1 + ECCENTRICITY * dcos(sun_true_anomaly)) / + (1 - ECCENTRICITY * ECCENTRICITY) + + // calculate moon position + const moon_mean_longitude = + MOON_MEAN_LONGITUDE_EPOCH + 13.1763966 * day + const moon_mean_anomaly = + moon_mean_longitude - 0.1114041 * day - MOON_MEAN_PERIGEE_EPOCH + const moon_evection = + 1.2739 * dsin( + 2 * (moon_mean_longitude - sun_ecliptic_longitude) - moon_mean_anomaly + ) + const moon_annual_equation = + 0.1858 * dsin(sun_mean_anomaly) + // XXX: what is the proper name for this value? + const moon_mp = + moon_mean_anomaly + + moon_evection - + moon_annual_equation - + 0.37 * dsin(sun_mean_anomaly) + const moon_equation_center_correction = + 6.2886 * dsin(moon_mp) + const moon_corrected_longitude = + moon_mean_longitude + + moon_evection + + moon_equation_center_correction - + moon_annual_equation + + 0.214 * dsin(2.0 * moon_mp) + const moon_age = + fixangle( + moon_corrected_longitude - + sun_ecliptic_longitude + + 0.6583 * dsin( + 2 * (moon_corrected_longitude - sun_ecliptic_longitude) + ) + ) + const moon_distance = + (MOON_SMAXIS * (1.0 - MOON_ECCENTRICITY * MOON_ECCENTRICITY)) / + (1.0 + MOON_ECCENTRICITY * dcos(moon_mp + moon_equation_center_correction)) + + return { + phase: (1.0 / 360.0) * moon_age, + illuminated: 0.5 * (1.0 - dcos(moon_age)), + age: (SYNODIC_MONTH / 360.0) * moon_age, + distance: moon_distance, + angular_diameter: MOON_ANGULAR_SIZE_SMAXIS / moon_distance, + sun_distance: SUN_SMAXIS / sun_orbital_distance_factor, + sun_angular_diameter: SUN_ANGULAR_SIZE_SMAXIS * sun_orbital_distance_factor } +} - /** - * Given a K value used to determine the mean phase of the new - * moon, and a phase selector (0.0, 0.25, 0.5, 0.75), obtain the - * true, corrected phase time. - * @param {[type]} k [description] - * @param {[type]} tphase [description] - * @return {[type]} [description] - */ - function truephase(k, tphase) { - - var apcor = false; +/** + * Calculates time of the mean new Moon for a given base date. + * This argument K to this function is the precomputed synodic month + * index, given by: + * K = (year - 1900) * 12.3685 + * where year is expressed as a year and fractional year. + * @param {Date} sdate Start date + * @param {[type]} k [description] + * @return {[type]} [description] + */ +function meanphase (sdate, k) { + // Time in Julian centuries from 1900 January 12 noon UTC + const delta_t = (sdate - -2208945600000.0) / 86400000.0 + const t = delta_t / 36525 + return 2415020.75933 + + SYNODIC_MONTH * k + + (0.0001178 - 0.000000155 * t) * t * t + + 0.00033 * dsin(166.56 + (132.87 - 0.009173 * t) * t) +} - // add phase to new moon time - k = k + tphase; - // Time in Julian centuries from 1900 January 0.5 - var t = k / 1236.85; +/** + * Given a K value used to determine the mean phase of the new moon, and a + * phase selector (0, 1, 2, 3), obtain the true, corrected phase time. + * @param {[type]} k [description] + * @param {[type]} tphase [description] + * @return {[type]} [description] + */ +function truephase (k, tphase) { + // restrict tphase to (0, 1, 2, 3) + tphase = tphase & PHASE_MASK - var t2 = t * t; - var t3 = t2 * t; + // add phase to new moon time + k = k + 0.25 * tphase - // Mean time of phase - var pt = ( - 2415020.75933 + SYNODIC_MONTH * k + 0.0001178 * t2 - - 0.000000155 * t3 + 0.00033 * dsin(166.56 + 132.87 * t - - 0.009173 * t2) - ); + // Time in Julian centuries from 1900 January 0.5 + const t = (1.0 / 1236.85) * k - // Sun's mean anomaly - var m = 359.2242 + 29.10535608 * k - 0.0000333 * t2 - 0.00000347 * t3; + // Mean time of phase + let pt = 2415020.75933 + + SYNODIC_MONTH * k + + (0.0001178 - 0.000000155 * t) * t * t + + 0.00033 * dsin(166.56 + (132.87 - 0.009173 * t) * t) - // Moon's mean anomaly - var mprime = 306.0253 + 385.81691806 * k + 0.0107306 * t2 + 0.00001236 * t3; + // Sun's mean anomaly + const m = 359.2242 + 29.10535608 * k - (0.0000333 - 0.00000347 * t) * t * t - // Moon's argument of latitude - var f = 21.2964 + 390.67050646 * k - 0.0016528 * t2 - 0.00000239 * t3; + // Moon's mean anomaly + const mprime = 306.0253 + 385.81691806 * k + (0.0107306 + 0.00001236 * t) * t * t - if ((tphase < 0.01) || (Math.abs(tphase - 0.5) < 0.01)) { + // Moon's argument of latitude + const f = 21.2964 + 390.67050646 * k - (0.0016528 - 0.00000239 * t) * t * t - // Corrections for New and Full Moon - pt = pt + ( - (0.1734 - 0.000393 * t) * dsin(m) + + // use different correction equations depending on the phase being sought + switch (tphase) { + // new and full moon use one correction + case NEW: + case FULL: + pt += (0.1734 - 0.000393 * t) * dsin(m) + 0.0021 * dsin(2 * m) - 0.4068 * dsin(mprime) + 0.0161 * dsin(2 * mprime) - @@ -323,76 +259,74 @@ 0.0006 * dsin(2 * f + mprime) + 0.0010 * dsin(2 * f - mprime) + 0.0005 * dsin(m + 2 * mprime) - ); + break - apcor = true; - } - else if ((Math.abs(tphase - 0.25) < 0.01) || (Math.abs(tphase - 0.75) < 0.01)) { - pt = pt + ( - (0.1721 - 0.0004 * t) * dsin(m) + - 0.0021 * dsin(2 * m) - - 0.6280 * dsin(mprime) + - 0.0089 * dsin(2 * mprime) - - 0.0004 * dsin(3 * mprime) + - 0.0079 * dsin(2 * f) - - 0.0119 * dsin(m + mprime) - - 0.0047 * dsin(m - mprime) + - 0.0003 * dsin(2 * f + m) - - 0.0004 * dsin(2 * f - m) - - 0.0006 * dsin(2 * f + mprime) + - 0.0021 * dsin(2 * f - mprime) + - 0.0003 * dsin(m + 2 * mprime) + - 0.0004 * dsin(m - 2 * mprime) - - 0.0003 * dsin(2 * m + mprime) - ); - if (tphase < 0.5) { - // First quarter correction - pt = pt + 0.0028 - 0.0004 * dcos(m) + 0.0003 * dcos(mprime); - } - else { - // Last quarter correction - pt = pt + -0.0028 + 0.0004 * dcos(m) - 0.0003 * dcos(mprime); - } - apcor = true; - } + // first and last quarter moon use a different correction + case FIRST: + case LAST: + pt += (0.1721 - 0.0004 * t) * dsin(m) + + 0.0021 * dsin(2 * m) - + 0.6280 * dsin(mprime) + + 0.0089 * dsin(2 * mprime) - + 0.0004 * dsin(3 * mprime) + + 0.0079 * dsin(2 * f) - + 0.0119 * dsin(m + mprime) - + 0.0047 * dsin(m - mprime) + + 0.0003 * dsin(2 * f + m) - + 0.0004 * dsin(2 * f - m) - + 0.0006 * dsin(2 * f + mprime) + + 0.0021 * dsin(2 * f - mprime) + + 0.0003 * dsin(m + 2 * mprime) + + 0.0004 * dsin(m - 2 * mprime) - + 0.0003 * dsin(2 * m + mprime) - if (!apcor) { - console.log("TRUEPHASE called with invalid phase selector ", tphase); - } + // the sign of the last term depends on whether we're looking for a first + // or last quarter moon! + const sign = (tphase < FULL) ? +1 : -1 + pt += sign * (0.0028 - 0.0004 * dcos(m) + 0.0003 * dcos(mprime)) + + break + } + + return julian.toDate(pt) +} + +/** + * Find time of phases of the moon which surround the current date. + * Five phases are found, starting and ending with the new moons + * which bound the current lunation. + * @param {Date} sdate Date to start hunting from (defaults to current date) + * @return {Object} Object containing recent past and future phases + */ +function phase_hunt (sdate) { + if (!sdate) { + sdate = new Date() + } - return julian.toDate(pt); + let adate = new Date(sdate.getTime() - (45 * 86400000)) // 45 days prior + let k1 = Math.floor(12.3685 * (adate.getFullYear() + ((1.0 / 12.0) * adate.getMonth()) - 1900)) + let nt1 = meanphase(adate.getTime(), k1) + + sdate = julian.fromDate(sdate) + adate = nt1 + SYNODIC_MONTH + let k2 = k1 + 1 + let nt2 = meanphase(adate, k2) + while (nt1 > sdate || sdate >= nt2) { + adate += SYNODIC_MONTH + k1++ + k2++ + nt1 = nt2 + nt2 = meanphase(adate, k2) } - /** - * Calculates time of the mean new Moon for a given base date. - * This argument K to this function is the precomputed synodic month - * index, given by: - * K = (year - 1900) * 12.3685 - * where year is expressed as a year and fractional year. - * @param {Date} sdate Start date - * @param {[type]} k [description] - * @return {[type]} [description] - */ - function meanphase(sdate, k) { - - // Time in Julian centuries from 1900 January 12 noon UTC - var delta_t = (sdate - (-2208945600000)) / (1000*60*60*24); - var t = delta_t / 36525; - - // square for frequent use - var t2 = t * t; - // and cube - var t3 = t2 * t; - - var nt1 = ( - 2415020.75933 + SYNODIC_MONTH * k + 0.0001178 * t2 - - 0.000000155 * t3 + 0.00033 * dsin(166.56 + 132.87 * t - - 0.009173 * t2) - ); - - return nt1; + return { + new_date: truephase(k1, NEW), + q1_date: truephase(k1, FIRST), + full_date: truephase(k1, FULL), + q3_date: truephase(k1, LAST), + nextnew_date: truephase(k2, NEW) } +} - exports.phase = phase; - exports.phase_hunt = phase_hunt; -})(); +exports.phase = phase +exports.phase_hunt = phase_hunt diff --git a/package.json b/package.json index 8cc4760..547e9c8 100644 --- a/package.json +++ b/package.json @@ -22,9 +22,10 @@ "license": "Apache-2.0", "devDependencies": { "chai": "~3.5.0", - "mocha": "~2.4.5" + "mocha": "~2.4.5", + "standard": "^6.0.8" }, "scripts": { - "test": "mocha --reporter min" + "test": "standard && mocha --reporter min" } } diff --git a/test/index.js b/test/index.js index 3c55c24..0950494 100644 --- a/test/index.js +++ b/test/index.js @@ -1,113 +1,117 @@ -var assert = require("chai").assert; -var lune = require("../lib/lune"); -var julian = require("../lib/julian"); +/* global describe, it */ +'use strict' +const assert = require('chai').assert +const julian = require('../lib/julian') +const lune = require('../lib/lune') -describe("lune", function() { - describe("#phase()", function() { - it("should return expected values for Feb 17th data", function() { - var phase = lune.phase(new Date("2014-02-17T00:00-0500")); +describe('lune', function () { + describe('#phase()', function () { + it('should return expected values for Feb 17th data', function () { + const phase = lune.phase(new Date('2014-02-17T00:00-0500')) - assert.closeTo(phase.phase, 0.568 , 0.001 ); - assert.closeTo(phase.illuminated, 0.955 , 0.001 ); - assert.closeTo(phase.age, 16.779 , 0.030 ); - assert.closeTo(phase.distance, 396084.5 , 384.4 ); - assert.closeTo(phase.angular_diameter, 0.5028, 0.0005); - assert.closeTo(phase.sun_distance, 147822500 , 149600 ); - assert.closeTo(phase.sun_angular_diameter, 0.5395, 0.0005); - }); + assert.closeTo(phase.phase, 0.568, 0.001) + assert.closeTo(phase.illuminated, 0.955, 0.001) + assert.closeTo(phase.age, 16.779, 0.030) + assert.closeTo(phase.distance, 396084.5, 384.4) + assert.closeTo(phase.angular_diameter, 0.5028, 0.0005) + assert.closeTo(phase.sun_distance, 147822500, 149600) + assert.closeTo(phase.sun_angular_diameter, 0.5395, 0.0005) + }) // http://bazaar.launchpad.net/~keturn/py-moon-phase/trunk/view/head:/moontest.py - it("should be accurate to astronomical observations", function() { - var observations = [ - ["1989-01-07T19:22Z", 0.00], - ["1989-01-14T13:58Z", 0.25], - ["1989-01-21T21:33Z", 0.50], - ["1989-01-30T02:02Z", 0.75], - ["1989-02-06T07:37Z", 0.00], - ["1989-02-12T23:15Z", 0.25], - ["1989-02-20T15:32Z", 0.50], - ["1989-02-28T20:08Z", 0.75], - ["1989-03-07T18:19Z", 0.00], - ["1989-03-14T10:11Z", 0.25], - ["1989-03-22T09:58Z", 0.50], - ["1989-03-30T10:21Z", 0.75], - ["1989-04-06T03:33Z", 0.00], - ["1989-04-12T23:13Z", 0.25], - ["1989-04-21T03:13Z", 0.50], - ["1989-04-28T20:46Z", 0.75], - ["1989-05-05T11:46Z", 0.00], - ["1989-05-12T14:19Z", 0.25], - ["1989-05-20T18:16Z", 0.50], - ["1989-05-28T04:01Z", 0.75], - ["1989-06-03T19:53Z", 0.00], - ["1989-06-11T06:59Z", 0.25], - ["1989-06-19T06:57Z", 0.50], - ["1989-06-26T09:09Z", 0.75], - ["1989-07-03T04:59Z", 0.00], - ["1989-07-11T00:19Z", 0.25], - ["1989-07-18T17:42Z", 0.50], - ["1989-07-25T13:31Z", 0.75], - ["1989-08-01T16:06Z", 0.00], - ["1989-08-09T17:28Z", 0.25], - ["1989-08-17T03:07Z", 0.50], - ["1989-08-23T18:40Z", 0.75], - ["1989-08-31T05:44Z", 0.00], - ["1989-09-08T09:49Z", 0.25], - ["1989-09-15T11:51Z", 0.50], - ["1989-09-22T02:10Z", 0.75], - ["1989-09-29T21:47Z", 0.00] - ]; + it('should be accurate to astronomical observations', function () { + const observations = [ + ['1989-01-07T19:22Z', 0.00], + ['1989-01-14T13:58Z', 0.25], + ['1989-01-21T21:33Z', 0.50], + ['1989-01-30T02:02Z', 0.75], + ['1989-02-06T07:37Z', 0.00], + ['1989-02-12T23:15Z', 0.25], + ['1989-02-20T15:32Z', 0.50], + ['1989-02-28T20:08Z', 0.75], + ['1989-03-07T18:19Z', 0.00], + ['1989-03-14T10:11Z', 0.25], + ['1989-03-22T09:58Z', 0.50], + ['1989-03-30T10:21Z', 0.75], + ['1989-04-06T03:33Z', 0.00], + ['1989-04-12T23:13Z', 0.25], + ['1989-04-21T03:13Z', 0.50], + ['1989-04-28T20:46Z', 0.75], + ['1989-05-05T11:46Z', 0.00], + ['1989-05-12T14:19Z', 0.25], + ['1989-05-20T18:16Z', 0.50], + ['1989-05-28T04:01Z', 0.75], + ['1989-06-03T19:53Z', 0.00], + ['1989-06-11T06:59Z', 0.25], + ['1989-06-19T06:57Z', 0.50], + ['1989-06-26T09:09Z', 0.75], + ['1989-07-03T04:59Z', 0.00], + ['1989-07-11T00:19Z', 0.25], + ['1989-07-18T17:42Z', 0.50], + ['1989-07-25T13:31Z', 0.75], + ['1989-08-01T16:06Z', 0.00], + ['1989-08-09T17:28Z', 0.25], + ['1989-08-17T03:07Z', 0.50], + ['1989-08-23T18:40Z', 0.75], + ['1989-08-31T05:44Z', 0.00], + ['1989-09-08T09:49Z', 0.25], + ['1989-09-15T11:51Z', 0.50], + ['1989-09-22T02:10Z', 0.75], + ['1989-09-29T21:47Z', 0.00] + ] - var error = 0; - var i; - var obs; - var e; - for(i = 0; i < observations.length; i++) { - obs = observations[i]; - e = Math.abs(lune.phase(new Date(obs[0])).phase - obs[1]); - if(e > 0.5) { + let error = 0 + for (let i = 0; i < observations.length; i++) { + const obs = observations[i] + + let e = Math.abs(lune.phase(new Date(obs[0])).phase - obs[1]) + if (e > 0.5) { // phase is circular - e = 1 - e; + e = 1 - e } - error += e; + + error += e } - assert.isAtMost(error / observations.length, 0.001); - }); - }); - describe("#phase_hunt", function() { - it("should handle timezones correctly", function() { - var d = new Date("2014-11-01T06:26-0400"); - var hunt = lune.phase_hunt(d); + assert.isAtMost(error / observations.length, 0.001) + }) + }) + + describe('#phase_hunt', function () { + it('should handle timezones correctly', function () { // 1415292777000 incorrect EST time // 1415312577000 correct UTC time // date conversion is now accurate to the millisecond, but these tests // were written when they were only accurate to the second - assert.closeTo(hunt.full_date.getTime(), 1415312577000, 500); - }); - }); -}); + assert.closeTo( + lune.phase_hunt(new Date('2014-11-01T06:26-0400')).full_date.getTime(), + 1415312577000, + 500 + ) + }) + }) +}) -describe("julian", function() { - describe("#fromDate", function() { +describe('julian', function () { + describe('#fromDate', function () { /* http://aa.usno.navy.mil/data/docs/JulianDate.php */ - it("should convert 2000-01-01T00:00Z to 2451544.5", function() { + it('should convert 2000-01-01T00:00Z to 2451544.5', function () { assert.closeTo( - julian.fromDate(new Date("2000-01-01T00:00Z")), + julian.fromDate(new Date('2000-01-01T00:00Z')), 2451544.5, - 0.5/86400 - ); - }); - }); + 0.5 / 86400 + ) + }) + }) - describe("#toDate", function() { + describe('#toDate', function () { /* http://aa.usno.navy.mil/data/docs/JulianDate.php */ - it("should convert 2457464.179862 to 2016-03-16T16:19Z", function() { + it('should convert 2457464.179862 to 2016-03-16T16:19Z', function () { assert.closeTo( julian.toDate(2457464.179862).getTime(), - (new Date("2016-03-16T16:19Z")).getTime(), + (new Date('2016-03-16T16:19Z')).getTime(), 500 - ); - }); - }); -}); + ) + }) + }) +})