-- v016_features.sql -- Tests for v0.16.0: twilight, lunar phase, planet magnitude -- -- Verifies twilight dawn/dusk, lunar phase calculations, -- and planet apparent magnitude. CREATE EXTENSION IF NOT EXISTS pg_orrery; -- ============================================================ -- Twilight: ordering (astronomical < nautical < civil < sunrise) -- Eagle, Idaho on the 2024 summer solstice -- ============================================================ -- Dawn ordering: astronomical dawn < nautical dawn < civil dawn < sunrise -- Use midnight MDT (07:00 UTC) so all "next" events land on the same morning SELECT sun_astronomical_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz) < sun_nautical_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz) AS astro_before_nautical; SELECT sun_nautical_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz) < sun_civil_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz) AS nautical_before_civil; SELECT sun_civil_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz) < sun_next_rise('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz) AS civil_before_sunrise; -- Dusk ordering: sunset < civil dusk < nautical dusk < astronomical dusk -- Noon MDT (18:00 UTC) ensures all dusk events are still ahead SELECT sun_next_set('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz) < sun_civil_dusk('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz) AS sunset_before_civil; SELECT sun_civil_dusk('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz) < sun_nautical_dusk('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz) AS civil_before_nautical; SELECT sun_nautical_dusk('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz) < sun_astronomical_dusk('(43.7,-116.4,800)'::observer, '2024-06-21 18:00:00+00'::timestamptz) AS nautical_before_astro; -- ============================================================ -- Twilight: civil dawn ~30 min before sunrise at mid-latitude -- ============================================================ SELECT extract(epoch FROM sun_next_rise('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz) - sun_civil_dawn('(43.7,-116.4,800)'::observer, '2024-06-21 07:00:00+00'::timestamptz) ) BETWEEN 1200 AND 3600 AS civil_dawn_reasonable_offset; -- ============================================================ -- Twilight: high latitude summer -- no astronomical darkness -- At 60N in June, astronomical dusk should be NULL (never gets dark enough) -- ============================================================ SELECT sun_astronomical_dusk('(60.0,25.0,0)'::observer, '2024-06-21 00:00:00+00'::timestamptz) IS NULL AS no_astro_dark_60n_summer; -- ============================================================ -- Lunar phase: known full moon (2024-01-25 ~17:54 UTC) -- Phase angle should be near 180 deg, illumination near 1.0 -- ============================================================ SELECT round(moon_phase_angle('2024-01-25 18:00:00+00'::timestamptz)::numeric, 0) BETWEEN 170 AND 190 AS full_moon_angle_near_180; SELECT round(moon_illumination('2024-01-25 18:00:00+00'::timestamptz)::numeric, 2) >= 0.95 AS full_moon_high_illumination; SELECT moon_phase_name('2024-01-25 18:00:00+00'::timestamptz) = 'full_moon' AS full_moon_named; -- ============================================================ -- Lunar phase: known new moon (2024-01-11 ~11:57 UTC) -- Phase angle should be near 0 or 360, illumination near 0 -- ============================================================ SELECT moon_illumination('2024-01-11 12:00:00+00'::timestamptz) < 0.05 AS new_moon_low_illumination; SELECT moon_phase_name('2024-01-11 12:00:00+00'::timestamptz) = 'new_moon' AS new_moon_named; -- ============================================================ -- Lunar phase: first quarter (2024-01-18 ~03:53 UTC) -- Phase angle near 90, illumination near 0.5 -- ============================================================ SELECT round(moon_phase_angle('2024-01-18 04:00:00+00'::timestamptz)::numeric, 0) BETWEEN 80 AND 100 AS first_quarter_angle_near_90; SELECT moon_illumination('2024-01-18 04:00:00+00'::timestamptz) BETWEEN 0.4 AND 0.6 AS first_quarter_half_illuminated; SELECT moon_phase_name('2024-01-18 04:00:00+00'::timestamptz) = 'first_quarter' AS first_quarter_named; -- ============================================================ -- Moon age: new moon has age near 0, full moon near 14.7 -- ============================================================ SELECT moon_age('2024-01-11 12:00:00+00'::timestamptz) < 2.0 AS new_moon_young; SELECT moon_age('2024-01-25 18:00:00+00'::timestamptz) BETWEEN 12.0 AND 17.0 AS full_moon_age_midcycle; -- ============================================================ -- Illumination range: always [0, 1] -- ============================================================ SELECT moon_illumination('2024-06-01 00:00:00+00'::timestamptz) BETWEEN 0.0 AND 1.0 AND moon_illumination('2024-09-01 00:00:00+00'::timestamptz) BETWEEN 0.0 AND 1.0 AND moon_illumination('2024-12-01 00:00:00+00'::timestamptz) BETWEEN 0.0 AND 1.0 AS illumination_always_valid; -- ============================================================ -- Planet magnitude: Jupiter should be bright (negative mag) -- ============================================================ SELECT planet_magnitude(5, '2024-01-15 00:00:00+00'::timestamptz) < 0.0 AS jupiter_is_bright; -- ============================================================ -- Planet magnitude: Venus is the brightest planet -- ============================================================ SELECT planet_magnitude(2, '2024-06-01 12:00:00+00'::timestamptz) < planet_magnitude(4, '2024-06-01 12:00:00+00'::timestamptz) AS venus_brighter_than_mars; -- ============================================================ -- Planet magnitude: Neptune is faint (~+7-8) -- ============================================================ SELECT planet_magnitude(8, '2024-01-15 00:00:00+00'::timestamptz) > 7.0 AS neptune_is_faint; -- ============================================================ -- Planet magnitude: all planets return finite values -- ============================================================ SELECT bool_and( planet_magnitude(body_id, '2024-01-15 00:00:00+00'::timestamptz) IS NOT NULL AND planet_magnitude(body_id, '2024-01-15 00:00:00+00'::timestamptz) > -30 AND planet_magnitude(body_id, '2024-01-15 00:00:00+00'::timestamptz) < 30 ) AS all_magnitudes_finite FROM (VALUES (1),(2),(4),(5),(6),(7),(8)) AS t(body_id); -- ============================================================ -- Planet magnitude: error cases -- ============================================================ DO $$ BEGIN PERFORM planet_magnitude(0, '2024-01-15 00:00:00+00'::timestamptz); EXCEPTION WHEN OTHERS THEN RAISE NOTICE 'body_id=0(Sun): %', SQLERRM; END $$; DO $$ BEGIN PERFORM planet_magnitude(3, '2024-01-15 00:00:00+00'::timestamptz); EXCEPTION WHEN OTHERS THEN RAISE NOTICE 'body_id=3(Earth): %', SQLERRM; END $$; DO $$ BEGIN PERFORM planet_magnitude(9, '2024-01-15 00:00:00+00'::timestamptz); EXCEPTION WHEN OTHERS THEN RAISE NOTICE 'body_id=9: %', SQLERRM; END $$;