esbat/lib.rs
1// Copyright (c) 2020 iliana destroyer of worlds <iliana@buttslol.net>
2// SPDX-License-Identifier: CC-BY-NC-4.0
3//
4// This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 International
5// License. To view a copy of this license, visit https://creativecommons.org/licenses/by-nc/4.0/
6// or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
7
8//! esbat provides functions for lunar phase calculations.
9//!
10//! The algorithms are as published in [<i>Calendrical Calculations: The Ultimate
11//! Edition</i>][book] by Edward M. Reingold and Nachum Dershowitz, used with permission. The book
12//! notes:
13//!
14//! > ... the algorithms are centered around the present date, for which they are accurate to
15//! > within about 2 minutes. Their accuracy decreases for the far-distant past or future.
16//!
17//! # License
18//!
19//! **This crate uses a non-commercial license**, a [Creative Commons Attribution-NonCommercial 4.0
20//! International License][license], at the request of the authors of <i>Calendrical
21//! Calculations</i>. Please contact the author of this crate at
22//! [iliana@buttslol.net][mail] for any licensing questions.
23//!
24//! [book]: https://doi.org/10.1017/9781107415058
25//! [license]: https://creativecommons.org/licenses/by-nc/4.0/
26//! [mail]: mailto:iliana@buttslol.net
27
28#![warn(
29 absolute_paths_not_starting_with_crate,
30 trivial_casts,
31 trivial_numeric_casts,
32 rust_2018_idioms,
33 clippy::pedantic
34)]
35#![allow(
36 clippy::module_name_repetitions,
37 clippy::must_use_candidate,
38 clippy::needless_pass_by_value
39)]
40
41mod calendar;
42mod conv;
43mod data;
44mod iter;
45mod phase;
46mod util;
47
48pub use crate::iter::{daily_lunar_phase_iter, lunar_phase_iter, DailyIter, Iter};
49pub use crate::phase::{Phase, PrincipalPhase};
50
51use crate::conv::fixed_from_chrono;
52use chrono::{Date, DateTime, Duration, TimeZone, Utc};
53
54/// Calculates the lunar phase for a given moment.
55///
56/// This determines the difference in longitudes of the Sun and the Moon, in degrees, for the
57/// moment `t`. The result is clamped to 0° ≤ <i>x</i> < 360°.
58///
59/// The new moon is 0°, the first-quarter moon is 90°, the full moon is 180°, and the
60/// last-quarter moon is 270°.
61///
62/// ```
63/// use chrono::{DateTime, TimeZone, Utc};
64/// use esbat::lunar_phase;
65///
66/// let t = Utc.ymd(2020, 10, 31).and_hms_milli(14, 48, 59, 300);
67/// assert!((lunar_phase(t) - 180.0).abs() < 0.00001);
68/// ```
69pub fn lunar_phase<Tz: TimeZone>(t: DateTime<Tz>) -> f64 {
70 calendar::lunar_phase(fixed_from_chrono(t.with_timezone(&Utc)))
71}
72
73/// Calculates the lunar phase for a given date.
74///
75/// This determines the principal phase (new moon, first quarter, full moon, or third quarter) that
76/// occurs on the date `t` or the intermediate phase between the previous and next principal
77/// phases.
78///
79/// ```
80/// use chrono::{Date, TimeZone, Utc};
81/// use esbat::{Phase, daily_lunar_phase};
82///
83/// let t = Utc.ymd(2020, 10, 31);
84/// assert_eq!(daily_lunar_phase(t), Phase::FullMoon);
85/// ```
86pub fn daily_lunar_phase<Tz: TimeZone>(t: Date<Tz>) -> Phase {
87 let t = t.and_hms(0, 0, 0).with_timezone(&Utc);
88 Phase::from_phase_range(lunar_phase(t), lunar_phase(t + Duration::days(1)))
89}