index.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /* global describe, it */
  2. 'use strict'
  3. const assert = require('chai').assert
  4. const julian = require('../lib/julian')
  5. const lune = require('../lib/lune')
  6. describe('lune', function () {
  7. const observations = [
  8. ['1989-01-07T19:22Z', 0.00, lune.PHASE_NEW],
  9. ['1989-01-14T13:58Z', 0.25, lune.PHASE_FIRST],
  10. ['1989-01-21T21:33Z', 0.50, lune.PHASE_FULL],
  11. ['1989-01-30T02:02Z', 0.75, lune.PHASE_LAST],
  12. ['1989-02-06T07:37Z', 0.00, lune.PHASE_NEW],
  13. ['1989-02-12T23:15Z', 0.25, lune.PHASE_FIRST],
  14. ['1989-02-20T15:32Z', 0.50, lune.PHASE_FULL],
  15. ['1989-02-28T20:08Z', 0.75, lune.PHASE_LAST],
  16. ['1989-03-07T18:19Z', 0.00, lune.PHASE_NEW],
  17. ['1989-03-14T10:11Z', 0.25, lune.PHASE_FIRST],
  18. ['1989-03-22T09:58Z', 0.50, lune.PHASE_FULL],
  19. ['1989-03-30T10:21Z', 0.75, lune.PHASE_LAST],
  20. ['1989-04-06T03:33Z', 0.00, lune.PHASE_NEW],
  21. ['1989-04-12T23:13Z', 0.25, lune.PHASE_FIRST],
  22. ['1989-04-21T03:13Z', 0.50, lune.PHASE_FULL],
  23. ['1989-04-28T20:46Z', 0.75, lune.PHASE_LAST],
  24. ['1989-05-05T11:46Z', 0.00, lune.PHASE_NEW],
  25. ['1989-05-12T14:19Z', 0.25, lune.PHASE_FIRST],
  26. ['1989-05-20T18:16Z', 0.50, lune.PHASE_FULL],
  27. ['1989-05-28T04:01Z', 0.75, lune.PHASE_LAST],
  28. ['1989-06-03T19:53Z', 0.00, lune.PHASE_NEW],
  29. ['1989-06-11T06:59Z', 0.25, lune.PHASE_FIRST],
  30. ['1989-06-19T06:57Z', 0.50, lune.PHASE_FULL],
  31. ['1989-06-26T09:09Z', 0.75, lune.PHASE_LAST],
  32. ['1989-07-03T04:59Z', 0.00, lune.PHASE_NEW],
  33. ['1989-07-11T00:19Z', 0.25, lune.PHASE_FIRST],
  34. ['1989-07-18T17:42Z', 0.50, lune.PHASE_FULL],
  35. ['1989-07-25T13:31Z', 0.75, lune.PHASE_LAST],
  36. ['1989-08-01T16:06Z', 0.00, lune.PHASE_NEW],
  37. ['1989-08-09T17:28Z', 0.25, lune.PHASE_FIRST],
  38. ['1989-08-17T03:07Z', 0.50, lune.PHASE_FULL],
  39. ['1989-08-23T18:40Z', 0.75, lune.PHASE_LAST],
  40. ['1989-08-31T05:44Z', 0.00, lune.PHASE_NEW],
  41. ['1989-09-08T09:49Z', 0.25, lune.PHASE_FIRST],
  42. ['1989-09-15T11:51Z', 0.50, lune.PHASE_FULL],
  43. ['1989-09-22T02:10Z', 0.75, lune.PHASE_LAST],
  44. ['1989-09-29T21:47Z', 0.00, lune.PHASE_NEW]
  45. ]
  46. describe('#phase()', function () {
  47. it('should return expected values for 2014-02-17', function () {
  48. const phase = lune.phase(new Date('2014-02-17T00:00-0500'))
  49. assert.closeTo(phase.phase, 0.568, 0.001)
  50. assert.closeTo(phase.illuminated, 0.955, 0.001)
  51. assert.closeTo(phase.age, 16.779, 0.030)
  52. assert.closeTo(phase.sun_distance, 147822500, 149600)
  53. assert.closeTo(phase.sun_angular_diameter, 0.5395, 0.0005)
  54. })
  55. // Astronomical Algorithms, 2nd ed., p. 347
  56. it('should return expected values for 1992-04-12', function () {
  57. const phase = lune.phase(new Date('1992-04-12'))
  58. assert.closeTo(phase.illuminated, 0.6802, 0.0001)
  59. assert.closeTo(phase.distance, 368405, 400)
  60. assert.closeTo(phase.angular_diameter, 0.5405, 0.0005)
  61. })
  62. // Astronomical Algorithms, 2nd ed., p. 169
  63. it('should return expected values for 1992-10-13', function () {
  64. const phase = lune.phase(new Date('1992-10-13'))
  65. assert.closeTo(phase.sun_distance, 149240000, 10000)
  66. })
  67. // http://bazaar.launchpad.net/~keturn/py-moon-phase/trunk/view/head:/moontest.py
  68. it('should be accurate to astronomical observations', function () {
  69. let error = 0
  70. for (let obs of observations) {
  71. let e = Math.abs(lune.phase(new Date(obs[0])).phase - obs[1])
  72. if (e > 0.5) {
  73. // phase is circular
  74. e = 1 - e
  75. }
  76. error += e
  77. }
  78. // tolerate an average error of up to a tenth of a percent
  79. assert.isAtMost(error / observations.length, 0.001)
  80. })
  81. })
  82. describe('#phase_hunt', function () {
  83. it('should handle timezones correctly', function () {
  84. // 1415292777000 incorrect EST time
  85. // 1415312577000 correct UTC time
  86. // date conversion is now accurate to the millisecond, but these tests
  87. // were written when they were only accurate to the second
  88. assert.closeTo(
  89. lune.phase_hunt(new Date('2014-11-01T06:26-0400')).full_date.getTime(),
  90. 1415312577000,
  91. 500
  92. )
  93. })
  94. })
  95. describe('#phase_range', function () {
  96. const PHASES = [
  97. lune.PHASE_NEW,
  98. lune.PHASE_FIRST,
  99. lune.PHASE_FULL,
  100. lune.PHASE_LAST
  101. ]
  102. /* http://aa.usno.navy.mil/data/docs/JulianDate.php */
  103. it('should return all moon phases within a time range', function () {
  104. let error = 0
  105. for (let phase of PHASES) {
  106. const actual = lune.phase_range(
  107. new Date('1989-01-01T00:00Z'),
  108. new Date('1989-10-01T00:00Z'),
  109. phase
  110. )
  111. const expected = observations.filter(function (obs) {
  112. return obs[2] === phase
  113. })
  114. assert.strictEqual(actual.length, expected.length)
  115. for (let i = 0; i < actual.length; i++) {
  116. const date = actual[i]
  117. const obs = new Date(expected[i][0])
  118. error += Math.abs(date.getTime() - obs.getTime())
  119. }
  120. }
  121. // tolerate an average error of up to five minutes
  122. assert.isAtMost(error / observations.length, 300000)
  123. })
  124. })
  125. })
  126. describe('julian', function () {
  127. describe('#fromDate', function () {
  128. /* http://aa.usno.navy.mil/data/docs/JulianDate.php */
  129. it('should convert 2000-01-01T00:00Z to 2451544.5', function () {
  130. assert.closeTo(
  131. julian.fromDate(new Date('2000-01-01T00:00Z')),
  132. 2451544.5,
  133. 0.5 / 86400
  134. )
  135. })
  136. })
  137. describe('#toDate', function () {
  138. /* http://aa.usno.navy.mil/data/docs/JulianDate.php */
  139. it('should convert 2457464.179862 to 2016-03-16T16:19Z', function () {
  140. assert.closeTo(
  141. julian.toDate(2457464.179862).getTime(),
  142. (new Date('2016-03-16T16:19Z')).getTime(),
  143. 500
  144. )
  145. })
  146. })
  147. })