From 3913e79acf3470d4780670219bb59b820ceba5e9 Mon Sep 17 00:00:00 2001 From: YK Date: Sat, 7 Dec 2024 06:37:36 +0300 Subject: [PATCH] refactor: code deduplication, extracted conversion into utils module --- src/julian.rs | 96 +++++++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/src/julian.rs b/src/julian.rs index 0fc51b6..9ad0011 100644 --- a/src/julian.rs +++ b/src/julian.rs @@ -13,48 +13,36 @@ pub struct NaiveJulianDate { #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] struct JulianDayNumber (u32); -impl From for JulianDayNumber { - fn from (value: NaiveDate) -> Self { +pub struct JulianDayNumberUtils; + +impl JulianDayNumberUtils { + + /// Given a month, day, and year, converts them into a julian day number (first return tuple member) + /// Second tuple member -- value of g that is required to calculate additional subtrahend for J for gregorian dates + pub fn julian_into_julian_day_number (day: i32, month: i32, year: i32) -> (i32, i32) { 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 h = month - m; + let g = year + y - (n - h) / n; let f = (h - 1 + n) % n; - let e = (p * g + q) / r + D as i32 - 1 - j; + let e = (p * g + q) / r + day - 1 - j; - let J = e + (s * f + t) / u; - - let J = J - (3 * ((g + A) / 100)) / 4 - C; - - Self(J as u32) + (e + (s * f + t) / u, g) } -} -impl From for JulianDayNumber { - fn from (NaiveJulianDate { day: D, year: Y, month: M }: NaiveJulianDate) -> Self { + pub fn gregorian_into_julian_day_number (day: i32, month: i32, year: i32) -> i32 { + use tables::julian_gregorian::*; + let (J, g) = Self::julian_into_julian_day_number(day, month, year); + J - (3 * ((g + A) / 100)) / 4 - C + } + + /// Converts Julian Day Number into a generic year-month-day tuple. + /// For gregorian dates, `f_extra` must be calculated with `JulianDayNumberUtils::gregorian_f_extra_for_julian_day`. + /// For julian dates, f_extra must be 0. + pub fn julian_day_number_into_ymd (julian_day: i32, f_extra: i32) -> (i32, u32, u32) { 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 for NaiveJulianDate { - fn from (JulianDayNumber(J): JulianDayNumber) -> Self { - use tables::julian_gregorian::*; - - let f = J as i32 + j; + let f = julian_day + j + f_extra; let e = r * f + v; let g = e % p / r; let h = u * g + w; @@ -63,6 +51,33 @@ impl From for NaiveJulianDate { let month = ((h / s + m) % n + 1) as u32; let year = e / p - y + (n + m - month as i32) / n; + (year, month, day) + } + + /// Returns extra `f` addend for calculating Gregorian calendar date from Julian Day Number + pub fn gregorian_f_extra_for_julian_day (julian_day: i32) -> i32 { + use tables::julian_gregorian::*; + (((julian_day * 4 + B) / 146_097) * 3) / 4 + C + } +} + +impl From for JulianDayNumber { + fn from (value: NaiveDate) -> Self { + let D = value.day(); let M = value.month(); let Y = value.year(); + let J = JulianDayNumberUtils::gregorian_into_julian_day_number(D as i32, M as i32, Y); + Self(J as u32) + } +} + +impl From for JulianDayNumber { + fn from (NaiveJulianDate { day: D, year: Y, month: M }: NaiveJulianDate) -> Self { + Self(JulianDayNumberUtils::julian_into_julian_day_number(D as i32, M as i32, Y).0 as u32) + } +} + +impl From for NaiveJulianDate { + fn from (JulianDayNumber(jd): JulianDayNumber) -> Self { + let (year, month, day) = JulianDayNumberUtils::julian_day_number_into_ymd(jd as i32, 0); Self { year, day, month } } } @@ -70,17 +85,8 @@ impl From for NaiveJulianDate { impl TryFrom for NaiveDate { type Error = ConversionError; - fn try_from (JulianDayNumber(J): JulianDayNumber) -> Result { - 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; + fn try_from (JulianDayNumber(jd): JulianDayNumber) -> Result { + let (year, month, day) = JulianDayNumberUtils::julian_day_number_into_ymd(jd as i32, JulianDayNumberUtils::gregorian_f_extra_for_julian_day(jd as i32)); Self::from_ymd_opt(year, month, day).ok_or_else(|| ConversionError::Generic) }