#[allow(dead_code)] pub struct Bikram {
year: i32,
month: i32,
day: i32,
yuga_rotation_star: f64,
yuga_rotation_sun: f64,
yuga_civil_days: f64,
planet_apogee_sun: f64,
planet_circum_sun: f64,
}
const RAD: f64 = 180.0 / std::f64::consts::PI;
const BS_START_YEAR: i32 = 2000;
const JULIAN_EPOCH_2000_BS: f64 = 2430828.5;
include!("./precomputed_data.rs");
impl Bikram {
pub fn new() -> Self {
let yuga_rotation_star = 1582237828.0;
let yuga_rotation_sun = 4320000.0;
Self {
year: 0,
month: -1,
day: 0,
yuga_rotation_star,
yuga_rotation_sun,
yuga_civil_days: yuga_rotation_star - yuga_rotation_sun,
planet_apogee_sun: 77.0 + 17.0 / 60.0,
planet_circum_sun: 13.0 + 50.0 / 60.0,
}
}
pub fn from_gregorian(&mut self, y: i32, m: i32, d: i32) {
let julian = self.get_julian_date(y, m, d);
let mut diff = (julian - JULIAN_EPOCH_2000_BS) as i64;
let mut bs_year = BS_START_YEAR;
if diff >= 0 {
while (bs_year - BS_START_YEAR) < NP_DATA_YEAR_COUNT as i32 {
for month_idx in 0..12 {
let days = NP_MONTHS_DATA[(bs_year - BS_START_YEAR) as usize][month_idx];
if diff < days as i64 {
self.year = bs_year;
self.month = (month_idx + 1) as i32;
self.day = (diff + 1) as i32;
return;
} else {
diff -= days as i64;
}
}
bs_year += 1; }
}
self.from_gregorian_astronomical(y, m, d);
}
pub fn to_gregorian(&self, bs_year: i32, bs_month: i32, bs_day: i32) -> (i32, i32, i32) {
if bs_year >= BS_START_YEAR && (bs_year - BS_START_YEAR) < NP_DATA_YEAR_COUNT as i32 {
let mut days = 0;
for y_idx in 0..(bs_year - BS_START_YEAR) {
days += NP_MONTHS_DATA[y_idx as usize][12]; }
for m_idx in 0..(bs_month - 1) {
days += NP_MONTHS_DATA[(bs_year - BS_START_YEAR) as usize][m_idx as usize];
}
days += bs_day - 1;
let target_julian = JULIAN_EPOCH_2000_BS + days as f64;
return self.from_julian_date(target_julian);
}
self.to_gregorian_astronomical(bs_year, bs_month, bs_day)
}
fn from_gregorian_astronomical(&mut self, y: i32, m: i32, d: i32) {
let julian = self.get_julian_date(y, m, d);
let ahar = (julian - 588465.5) as i64;
let (sm_num, sm_day) = self.get_saura_masa_day(ahar);
let year_kali = ((ahar as f64 * self.yuga_rotation_sun) / self.yuga_civil_days).floor() as i64;
let year_saka = year_kali - 3179;
let nepali_month = sm_num % 12;
self.year = (year_saka + 135 + ((sm_num - nepali_month) / 12) as i64) as i32;
self.month = ((sm_num + 12) % 12) + 1;
self.day = sm_day;
}
fn to_gregorian_astronomical(&self, bs_year: i32, bs_month: i32, bs_day: i32) -> (i32, i32, i32) {
let year_saka = bs_year - 135;
let year_kali = year_saka + 3179;
let mut ahar = ((year_kali as f64 * self.yuga_civil_days) / self.yuga_rotation_sun).floor() as i64;
let bs_month_zero_indexed = (bs_month + 11) % 12; loop {
let (sm, sd) = self.get_saura_masa_day(ahar);
if sm == bs_month_zero_indexed && sd == bs_day {
break;
}
ahar += if sm < bs_month_zero_indexed || (sm == bs_month_zero_indexed && sd < bs_day) { 1 } else { -1 };
}
let jd = ahar as f64 + 588465.5;
self.from_julian_date(jd)
}
fn get_saura_masa_day(&self, ahar: i64) -> (i32, i32) {
if self.today_saura_masa_first_p(ahar) {
let tslong_tomorrow = self.get_tslong(ahar + 1);
let month = ((tslong_tomorrow / 30.0) as i32 + 12) % 12;
(month, 1)
} else {
let (prev_month, mut day) = self.get_saura_masa_day(ahar - 1);
day += 1;
(prev_month, day)
}
}
fn today_saura_masa_first_p(&self, ahar: i64) -> bool {
let today = self.get_tslong(ahar) % 30.0;
let tomorrow = self.get_tslong(ahar + 1) % 30.0;
let today_mod = (today + 30.0) % 30.0;
let tomorrow_mod = (tomorrow + 30.0) % 30.0;
today_mod > 25.0 && tomorrow_mod < 5.0
}
fn get_tslong(&self, ahar: i64) -> f64 {
let mut t1 = (self.yuga_rotation_sun * ahar as f64) / self.yuga_civil_days;
t1 -= t1.floor();
let mslong = 360.0 * t1;
let x1 = mslong - self.planet_apogee_sun;
let y1 = self.planet_circum_sun / 360.0;
let y2 = (x1 / RAD).sin();
let y3 = y1 * y2;
let x2 = y3.asin() * RAD;
mslong - x2
}
fn get_julian_date(&self, y: i32, m: i32, d: i32) -> f64 {
let (mut y, mut m) = (y, m);
if m <= 2 {
y -= 1;
m += 12;
}
let a = (y as f64 / 100.0).floor();
let b = 2.0 - a + (a / 4.0).floor();
(365.25 * (y as f64 + 4716.0)).floor()
+ (30.6001 * (m as f64 + 1.0)).floor()
+ d as f64 + b - 1524.5
}
fn from_julian_date(&self, jd: f64) -> (i32, i32, i32) {
let z = (jd + 0.5).floor() as i32;
let a = if z < 2299161 {
z
} else {
let alpha = ((z as f64 - 1867216.25) / 36524.25).floor() as i32;
z + 1 + alpha - (alpha / 4)
};
let b = a + 1524;
let c = ((b as f64 - 122.1) / 365.25).floor() as i32;
let d = (365.25 * c as f64).floor() as i32;
let e = ((b - d) as f64 / 30.6001).floor() as i32;
let day = b - d - (30.6001 * e as f64) as i32;
let month = if e < 14 { e - 1 } else { e - 13 };
let year = if month > 2 { c - 4716 } else { c - 4715 };
(year, month, day)
}
pub fn get_year(&self) -> i32 { self.year }
pub fn get_month(&self) -> i32 { self.month }
pub fn get_day(&self) -> i32 { self.day }
pub fn days_in_month(&self, bs_year: i32, bs_month: i32) -> i32 {
if bs_year >= BS_START_YEAR && (bs_year - BS_START_YEAR) < NP_DATA_YEAR_COUNT as i32 {
NP_MONTHS_DATA[(bs_year - BS_START_YEAR) as usize][(bs_month - 1) as usize]
} else {
let (gy1, gm1, gd1) = self.to_gregorian(bs_year, bs_month, 1);
let (gy2, gm2, gd2) = if bs_month == 12 {
self.to_gregorian(bs_year + 1, 1, 1)
} else {
self.to_gregorian(bs_year, bs_month + 1, 1)
};
let jd1 = self.get_julian_date(gy1, gm1, gd1);
let jd2 = self.get_julian_date(gy2, gm2, gd2);
(jd2 - jd1) as i32
}
}
}