Open tysen opened 10 months ago
I am aware that the "technically correct" definition of Julian day numbers has them start at noon. I believe my thinking for the behavior of this crate went as follows:
For reasons mostly involving simplicity, focus on core functionality, and a distrust of floating-point, this crate only works with dates without time-of-day components (not counting the small number of functions & methods that use timestamps[^1]). Thus, all conversions are between 24-hour periods like "2024-01-13" and JDNs.
Thus, given a timeless date like 2024-01-13 as input, the possible JDN outputs are:
Thus, each date corresponds to one JDN and vice versa, and because dates tick over at midnight, JDNs have to tick over at midnight.
For consistency with the date-JDN conversion methods, the timestamp-JDN methods also tick over at midnight, as I felt that following the strict rules for JDNs here would lead to user confusion when compared against the rest of the crate.
So:
_astro
" suffix for "astronomical day"?[^1]: That is, Calendar::now()
, Calendar::at_system_time()
, Calendar::at_unix_time()
, system2jdn()
, unix2jdn()
, and jdn2unix()
.
All of my interaction w/ Julian dates has been in astronomy, wherein the 12 hour difference is relevant. Certainly, the whole noon thing is awkward (hence the move to MJD). I understand that there are other uses for the Julian day numbering system for which this discrepancy is not relevant.
My goal is predict the sky position (right ascension / declination) of various solar system objects (the planets, the sun, and Earth's moon) at specific points in the future at specific places on the planet. I have a separate tool to achieve this, and it takes as its input Julian dates. So I would like to convert from chrono::DateTime<Utc>
to Julian dates. The 12 hours matter for most of these objects, and especially for the moon.
Here are some preliminary ideas for how to support this in this crate (any subset of these would help):
julian::Date
to julian::Day
The thought here is to use the distinction noted here between "Date" and "Day" where the former is the instant in time (including the fractional amount since the last noon) and the latter is only the integral part of this value.
00:00:00 UTC
timestamp for conversion to julian::Date
and julian::Day
from chrono::NaiveDate
That is:
// chrono::NaiveDate uses the Gregorian calendar, and a year 0, so this is November 24, 4714 BC
let start = chrono::NaiveDate::from_ymd_opt(-4713, 11, 24).unwrap();
let date: julian::Date = start.into(); // would be same for `julian::Day`
assert_eq(-1, date.julian_day_number()); // not 0
I think these are the least astonishing assumptions (midnight in UTC) to make for a chrono::NaiveDate
.
Date
and/or Day
::modified_julian_day_number
fnIn my opinion, MJD is the appropriate value to support if ticking over at midnight is a primary design goal.
julian::Date
Date
could have an impl of From<DateTime<Utc>>
and perhaps a Date::instant
fn (maybe a better name exists) returning an f64
which is the (noon-based) Julian day number with the fractional (since noon) day included.
I've been thinking about this on & off, and while I'm still unsure whether I want to do this or even when I might get around to doing it, if I were to support JDN rollover at noon, I'd do something like the following, just adding functionality without breaking anything:
Add a Time
type that wraps a Duration
and limits it to fewer than 86400 seconds (taking a page out of Unix timestamps' book and pretending leap seconds don't exist)
Add a DateTime
type that combines a Date
and a Time
, including exposing (almost) all the same method as Date
does, plus stuff like hour()
, minute()
, and second()
DateLike
-trait for sharing methods between Date
and DateTime
is a no-go, as then the Date
methods would lose the precious const
ness I worked so hard on.Instead of a julian_day_number()
method, give DateTime
a fractional_jd(&self) -> FractionalJD
(Names are WIP) method, where FractionalJD
stores an integer Julian day number — with rollover at noon — plus a Duration
since noon
FractionalJD
can then have an as_f64(&self) -> f64
method or similar for converting to a floatThere will also have to be various methods for constructing a DateTime
:
Calendar::now()
, but returning a DateTime
Calendar
a YMDHMS tuple or structureCalendar
a FractionalJD
FractionalJD
to Unix)SystemTime
Date
and a Time
Hi, thanks for this crate. Any plans to handle the half day discrepancy caused by not considering the time of day? The documentation claims that Julian day 0 began at midnight, which is contrary to my understanding (that is, I understand that it began at noon UT on January 1, 4713 BC, proleptic Julian calendar).
I could handle this within my application but it seems better to handle it within this crate. I may be able to help with the implementation but I thought first to ask whether this was a conscious design decision.