initial commit: basic julian/gregorian tables + julian/gregorian date ⇔ julian day conversion
This commit is contained in:
commit
c4045c9142
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
/Cargo.lock
|
||||
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "esodate"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4.26"
|
||||
thiserror = "1.0.47"
|
||||
3
TODO.md
Normal file
3
TODO.md
Normal file
@ -0,0 +1,3 @@
|
||||
- [ ] use TryFrom for converting JulianDay into NaiveJulianDate instead of From
|
||||
- [ ] Sanity checks for NJD are needed (?)
|
||||
- [ ] Change trait impl
|
||||
8
src/error.rs
Normal file
8
src/error.rs
Normal file
@ -0,0 +1,8 @@
|
||||
use thiserror::Error;
|
||||
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ConversionError {
|
||||
#[error("Error during date conversion")]
|
||||
Generic
|
||||
}
|
||||
171
src/julian.rs
Normal file
171
src/julian.rs
Normal file
@ -0,0 +1,171 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use chrono::{ NaiveTime, NaiveDate, Datelike };
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone, Debug)]
|
||||
pub struct NaiveJulianDate {
|
||||
year: i32,
|
||||
day: u32,
|
||||
month: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct JulianDayNumber (u32);
|
||||
|
||||
impl From<NaiveDate> for JulianDayNumber {
|
||||
fn from (value: NaiveDate) -> Self {
|
||||
use tables::julian_gregorian::*;
|
||||
|
||||
let D = value.day();
|
||||
let M = value.month();
|
||||
let Y = value.year();
|
||||
|
||||
|
||||
let h = M as i32 - m;
|
||||
let g = Y as i32 + y - (n - h) / n;
|
||||
let f = (h - 1 + n) % n;
|
||||
let e = (p * g + q) / r + D as i32 - 1 - j;
|
||||
|
||||
let J = e + (s * f + t) / u;
|
||||
|
||||
let J = J - (3 * ((g + A) / 100)) / 4 - C;
|
||||
|
||||
Self(J as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NaiveJulianDate> for JulianDayNumber {
|
||||
fn from (NaiveJulianDate { day: D, year: Y, month: M }: NaiveJulianDate) -> Self {
|
||||
use tables::julian_gregorian::*;
|
||||
|
||||
let h = M as i32 - m;
|
||||
let g = Y as i32 + y - (n - h) / n;
|
||||
let f = (h - 1 + n) % n;
|
||||
let e = (p * g + q) / r + D as i32 - 1 - j;
|
||||
|
||||
let J = e + (s * f + t) / u;
|
||||
|
||||
Self(J as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JulianDayNumber> for NaiveJulianDate {
|
||||
fn from (JulianDayNumber(J): JulianDayNumber) -> Self {
|
||||
use tables::julian_gregorian::*;
|
||||
|
||||
let f = J as i32 + j;
|
||||
let e = r * f + v;
|
||||
let g = e % p / r;
|
||||
let h = u * g + w;
|
||||
|
||||
let day = (h % s / u + 1) as u32;
|
||||
let month = ((h / s + m) % n + 1) as u32;
|
||||
let year = e / p - y + (n + m - month as i32) / n;
|
||||
|
||||
Self { year, day, month }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl TryFrom<JulianDayNumber> for NaiveDate {
|
||||
type Error = ConversionError;
|
||||
fn try_from (JulianDayNumber(J): JulianDayNumber) -> Result<Self, Self::Error> {
|
||||
use tables::julian_gregorian::*;
|
||||
|
||||
let f = J as i32 + j + (((J as i32 * 4 + B) / 146_097) * 3) / 4 + C;
|
||||
let e = r * f + v;
|
||||
let g = e % p / r;
|
||||
let h = u * g + w;
|
||||
|
||||
let day = (h % s / u + 1) as u32;
|
||||
let month = ((h / s + m) % n + 1) as u32;
|
||||
let year = e / p - y + (n + m - month as i32) / n;
|
||||
|
||||
Self::from_ymd_opt(year, month, day).ok_or_else(|| ConversionError::Generic)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NaiveDate> for NaiveJulianDate {
|
||||
fn from (value: NaiveDate) -> Self {
|
||||
Into::<JulianDayNumber>::into(value).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<NaiveJulianDate> for NaiveDate {
|
||||
type Error = ConversionError;
|
||||
fn try_from (value: NaiveJulianDate) -> Result<Self, Self::Error> {
|
||||
Into::<JulianDayNumber>::into(value).try_into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)]
|
||||
pub struct NaiveJulianDateTime {
|
||||
pub date: NaiveJulianDate,
|
||||
pub time: NaiveTime,
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[allow(unused_imports)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::prelude::*;
|
||||
|
||||
const _jdt: NaiveJulianDate = NaiveJulianDate { year: 2024, day: 23, month: 11 };
|
||||
const _jd: JulianDayNumber = JulianDayNumber(2460651);
|
||||
|
||||
fn gd () -> NaiveDate {
|
||||
NaiveDate::from_ymd_opt(2024, 12, 6).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gregorian_date_to_julian_day_basic () {
|
||||
let gd = gd();
|
||||
let jd: JulianDayNumber = gd.into();
|
||||
|
||||
assert_eq!(_jd, jd);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn julian_day_to_julian_date_basic () {
|
||||
let jdt: NaiveJulianDate = _jd.into();
|
||||
|
||||
assert_eq!(_jdt, jdt);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gregorian_date_to_julian_day_to_gregorian_date_basic () {
|
||||
let gd = gd();
|
||||
let jd: JulianDayNumber = gd.into();
|
||||
let nd: NaiveDate = jd.try_into().unwrap();
|
||||
|
||||
assert_eq!(gd, nd);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn julian_date_to_julian_day_to_julian_date_basic () {
|
||||
let jd: JulianDayNumber = _jdt.into();
|
||||
let nd: NaiveJulianDate = jd.try_into().unwrap();
|
||||
|
||||
assert_eq!(_jdt, nd);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gregorian_date_to_julian_date_basic () {
|
||||
let gd = gd();
|
||||
let jd: NaiveJulianDate = gd.into();
|
||||
|
||||
assert_eq!(_jdt, jd);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn julian_date_to_gregorian_date_basic () {
|
||||
let _gd = gd();
|
||||
let gd: NaiveDate = _jdt.try_into().unwrap();
|
||||
|
||||
assert_eq!(gd, _gd);
|
||||
}
|
||||
}
|
||||
9
src/lib.rs
Normal file
9
src/lib.rs
Normal file
@ -0,0 +1,9 @@
|
||||
pub mod tables;
|
||||
pub mod julian;
|
||||
pub mod error;
|
||||
|
||||
pub mod prelude {
|
||||
pub use crate::tables;
|
||||
pub use crate::error::*;
|
||||
}
|
||||
|
||||
21
src/tables.rs
Normal file
21
src/tables.rs
Normal file
@ -0,0 +1,21 @@
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
pub mod julian_gregorian {
|
||||
// Taken from Explanatory Supplement to the Astronomical Almanac, 3rd Edition, p. 617
|
||||
pub const y: i32 = 4716;
|
||||
pub const j: i32 = 1401;
|
||||
pub const m: i32 = 2;
|
||||
pub const n: i32 = 12;
|
||||
pub const r: i32 = 4;
|
||||
pub const p: i32 = 1461;
|
||||
pub const q: i32 = 0;
|
||||
pub const v: i32 = 3;
|
||||
pub const u: i32 = 5;
|
||||
pub const s: i32 = 153;
|
||||
pub const t: i32 = 2;
|
||||
pub const w: i32 = 2;
|
||||
pub const A: i32 = 184;
|
||||
pub const B: i32 = 274244;
|
||||
pub const C: i32 = -38;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user