1- use std:: f64:: consts:: PI ;
2- use chrono:: NaiveDate ;
3- pub struct Bikram {
4- year : i32 ,
5- month : i32 ,
6- day : i32 ,
7- yuga_rotation_star : f64 ,
8- yuga_rotation_sun : f64 ,
9- yuga_civil_days : f64 ,
10- planet_apogee_sun : f64 ,
11- planet_circum_sun : f64 ,
12- rad : f64 ,
13- }
14-
15- impl Bikram {
16- pub fn new ( ) -> Self {
17- Self {
18- year : 0 ,
19- month : -1 ,
20- day : 0 ,
21- yuga_rotation_star : 1582237828.0 ,
22- yuga_rotation_sun : 4320000.0 ,
23- yuga_civil_days : 0.0 ,
24- planet_apogee_sun : 77.0 + 17.0 / 60.0 ,
25- planet_circum_sun : 13.0 + 50.0 / 60.0 ,
26- rad : 180.0 / PI ,
27- }
28- }
29-
30- pub fn get_saura_masa_day ( & self , ahar : i64 ) -> ( i32 , i32 ) {
31- if self . today_saura_masa_first_p ( ahar) {
32- let tslong_tomorrow = self . get_tslong ( ahar + 1 ) ;
33- let month = ( ( tslong_tomorrow / 30.0 ) as i32 ) % 12 ;
34- ( month, 1 )
35- } else {
36- let ( prev_month, mut day) = self . get_saura_masa_day ( ahar - 1 ) ;
37- day += 1 ;
38- ( prev_month, day)
39- }
40- }
41-
42- pub fn today_saura_masa_first_p ( & self , ahar : i64 ) -> bool {
43- let tslong_today = self . get_tslong ( ahar) % 30.0 ;
44- let tslong_tomorrow = self . get_tslong ( ahar + 1 ) % 30.0 ;
45- tslong_today > 25.0 && tslong_tomorrow < 5.0
46- }
47-
48- pub fn get_tslong ( & self , ahar : i64 ) -> f64 {
49- let t1 = ( self . yuga_rotation_sun * ahar as f64 / self . yuga_civil_days ) % 1.0 ;
50- let mslong = 360.0 * t1;
51- let x1 = mslong - self . planet_apogee_sun ;
52- let y1 = self . planet_circum_sun / 360.0 ;
53- let y2 = ( x1 / self . rad ) . sin ( ) ;
54- let y3 = y1 * y2;
55- let x2 = ( y3. asin ( ) ) * self . rad ;
56- mslong - x2
57- }
58-
59- pub fn get_julian_date ( & self , year : i32 , month : i32 , day : i32 ) -> f64 {
60- let ( mut year, mut month) = ( year, month) ;
61- if month <= 2 {
62- year -= 1 ;
63- month += 12 ;
64- }
65- let a = ( year as f64 / 100.0 ) . floor ( ) ;
66- let b = 2.0 - a + ( a / 4.0 ) . floor ( ) ;
67- ( 365.25 * ( year as f64 + 4716.0 ) ) . floor ( ) + ( 30.6001 * ( month as f64 + 1.0 ) ) . floor ( ) + day as f64 + b - 1524.5
68- }
69-
70- pub fn from_julian_date ( & self , julian_date : f64 ) -> ( i32 , i32 , i32 ) {
71- let z = ( julian_date + 0.5 ) . floor ( ) as i32 ;
72- let a = if z < 2299161 {
73- z
74- } else {
75- let alpha = ( ( z as f64 - 1867216.25 ) / 36524.25 ) . floor ( ) as i32 ;
76- z + 1 + alpha - ( alpha / 4 )
77- } ;
78- let b = a + 1524 ;
79- let c = ( ( b as f64 - 122.1 ) / 365.25 ) . floor ( ) as i32 ;
80- let d = ( 365.25 * c as f64 ) . floor ( ) as i32 ;
81- let e = ( ( b - d) as f64 / 30.6001 ) . floor ( ) as i32 ;
82-
83- let day = b - d - ( 30.6001 * e as f64 ) as i32 ;
84- let month = if e < 14 { e - 1 } else { e - 13 } ;
85- let year = if month > 2 { c - 4716 } else { c - 4715 } ;
86-
87- ( year, month, day)
88- }
89-
90- pub fn from_gregorian ( & mut self , y : i32 , m : i32 , d : i32 ) {
91- self . yuga_civil_days = self . yuga_rotation_star - self . yuga_rotation_sun ;
92- let julian = self . get_julian_date ( y, m, d) ;
93- let ahar = julian as i64 - 588465 ;
94- let ( saura_masa_num, saura_masa_day) = self . get_saura_masa_day ( ahar) ;
95- let year_kali = ( ahar as f64 * self . yuga_rotation_sun / self . yuga_civil_days ) . floor ( ) as i64 ;
96- let year_saka = year_kali - 3179 ;
97- let nepalimonth = saura_masa_num % 12 ;
98- self . year = ( year_saka + 135 + ( ( saura_masa_num - nepalimonth) / 12 ) as i64 ) as i32 ;
99- self . month = ( saura_masa_num + 12 ) % 12 ;
100- self . day = saura_masa_day;
101- }
102-
103- pub fn to_gregorian ( & mut self , bs_year : i32 , bs_month : i32 , bs_day : i32 ) -> ( i32 , i32 , i32 ) {
104- let mut bs_month = bs_month;
105- self . yuga_civil_days = self . yuga_rotation_star - self . yuga_rotation_sun ;
106- let year_saka = bs_year - 135 ;
107- let year_kali = year_saka + 3179 ;
108- let mut ahar = ( ( year_kali as f64 * self . yuga_civil_days ) / self . yuga_rotation_sun ) . floor ( ) as i64 ;
109- let mut saura_masa_num;
110- let mut saura_masa_day;
111- bs_month = ( bs_month + 11 ) % 12 ;
112- loop {
113- let result = self . get_saura_masa_day ( ahar) ;
114- saura_masa_num = result. 0 ;
115- saura_masa_day = result. 1 ;
116- if saura_masa_num == bs_month && saura_masa_day == bs_day {
117- break ;
118- }
119- ahar += if saura_masa_num < bs_month || ( saura_masa_num == bs_month && saura_masa_day < bs_day) {
120- 1
121- } else {
122- -1
123- } ;
124- }
125- let julian_date = ahar as f64 + 588465.5 ;
126- self . from_julian_date ( julian_date)
127- }
128-
129- pub fn from_nepali ( & mut self , bs_year : i32 , bs_month : i32 , bs_day : i32 ) {
130- let ( g_year, g_month, g_day) = self . to_gregorian ( bs_year, bs_month, bs_day) ;
131- self . year = g_year;
132- self . month = g_month - 1 ;
133- self . day = g_day;
134- }
135-
136- pub fn get_year ( & self ) -> i32 {
137- self . year
138- }
139-
140- pub fn get_month ( & self ) -> i32 {
141- self . month + 1
142- }
143-
144- pub fn get_day ( & self ) -> i32 {
145- self . day
146- }
147-
148- pub fn get_weekday_name ( & self , year : i32 , month : i32 , day : i32 ) -> String {
149- if let Some ( date) = NaiveDate :: from_ymd_opt ( year, month as u32 , day as u32 ) {
150- date. format ( "%A" ) . to_string ( )
151- } else {
152- "Invalid date" . to_string ( ) // Handle invalid date case
153- }
154- }
155-
156- pub fn days_in_month ( & mut self , bs_year : i32 , bs_month : i32 ) -> i32 {
157- let next_month = ( bs_month % 12 ) + 1 ;
158- let next_year = if bs_month == 12 { bs_year + 1 } else { bs_year } ;
159- let ( g_year_start, g_month_start, g_day_start) = self . to_gregorian ( bs_year, bs_month, 1 ) ;
160- let julian_start = self . get_julian_date ( g_year_start, g_month_start, g_day_start) ;
161- let ( g_year_end, g_month_end, g_day_end) = self . to_gregorian ( next_year, next_month, 1 ) ;
162- let julian_end = self . get_julian_date ( g_year_end, g_month_end, g_day_end) ;
163- ( julian_end - julian_start) as i32
164- }
165- }
1+ /*
2+ * Copyright (C) 2024 Khumnath CG
3+ 4+ *
5+ * This program is free software: you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published by
7+ * the Free Software Foundation, either version 3 of the License, or
8+ * (at your option) any later version.
9+ *
10+ * This program is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License
16+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
17+ */
18+
19+
20+
21+ #[ allow( dead_code) ] // Allow unused fields that are initialized and used for derived values
22+ pub struct Bikram {
23+ year : i32 ,
24+ month : i32 ,
25+ day : i32 ,
26+ yuga_rotation_star : f64 ,
27+ yuga_rotation_sun : f64 ,
28+ yuga_civil_days : f64 ,
29+ planet_apogee_sun : f64 ,
30+ planet_circum_sun : f64 ,
31+ }
32+
33+ const RAD : f64 = 180.0 / std:: f64:: consts:: PI ;
34+ const BS_START_YEAR : i32 = 2000 ;
35+ const JULIAN_EPOCH_2000_BS : f64 = 2430910.5 ; // 14 April 1943
36+
37+ include ! ( "./precomputed_data.rs" ) ; // Contains NP_MONTHS_DATA: [[i32; 13]; N], NP_DATA_YEAR_COUNT
38+
39+ impl Bikram {
40+ pub fn new ( ) -> Self {
41+ let yuga_rotation_star = 1582237828.0 ;
42+ let yuga_rotation_sun = 4320000.0 ;
43+ Self {
44+ year : 0 ,
45+ month : -1 ,
46+ day : 0 ,
47+ yuga_rotation_star,
48+ yuga_rotation_sun,
49+ yuga_civil_days : yuga_rotation_star - yuga_rotation_sun,
50+ planet_apogee_sun : 77.0 + 17.0 / 60.0 ,
51+ planet_circum_sun : 13.0 + 50.0 / 60.0 ,
52+ }
53+ }
54+
55+ pub fn from_gregorian ( & mut self , y : i32 , m : i32 , d : i32 ) {
56+ let julian = self . get_julian_date ( y, m, d) ;
57+ let diff = ( julian - JULIAN_EPOCH_2000_BS ) as i64 ;
58+ let mut bs_year = BS_START_YEAR ;
59+ if diff >= 0 {
60+ // Ensure we don't go out of bounds for NP_MONTHS_DATA
61+ while ( bs_year - BS_START_YEAR ) < NP_DATA_YEAR_COUNT as i32 {
62+ let mut current_year_diff = diff;
63+ let mut found_in_precomputed = false ;
64+ for month_idx in 0 ..12 {
65+ let days = NP_MONTHS_DATA [ ( bs_year - BS_START_YEAR ) as usize ] [ month_idx] ;
66+ if current_year_diff < days as i64 {
67+ self . year = bs_year;
68+ self . month = ( month_idx + 1 ) as i32 ;
69+ self . day = ( current_year_diff + 1 ) as i32 ;
70+ found_in_precomputed = true ;
71+ break ;
72+ } else {
73+ current_year_diff -= days as i64 ;
74+ }
75+ }
76+ if found_in_precomputed {
77+ return ;
78+ }
79+ bs_year += 1 ; // Move to the next year
80+ }
81+ }
82+ // Fallback to astronomical if outside precomputed range or diff is negative
83+ self . from_gregorian_astronomical ( y, m, d) ;
84+ }
85+
86+ pub fn to_gregorian ( & self , bs_year : i32 , bs_month : i32 , bs_day : i32 ) -> ( i32 , i32 , i32 ) {
87+ if bs_year >= BS_START_YEAR && ( bs_year - BS_START_YEAR ) < NP_DATA_YEAR_COUNT as i32 {
88+ let mut days = 0 ;
89+ for y_idx in 0 ..( bs_year - BS_START_YEAR ) {
90+ days += NP_MONTHS_DATA [ y_idx as usize ] [ 12 ] ; // Total days in that BS year
91+ }
92+ for m_idx in 0 ..( bs_month - 1 ) {
93+ days += NP_MONTHS_DATA [ ( bs_year - BS_START_YEAR ) as usize ] [ m_idx as usize ] ;
94+ }
95+ days += bs_day - 1 ;
96+ let target_julian = JULIAN_EPOCH_2000_BS + days as f64 ;
97+ return self . from_julian_date ( target_julian) ;
98+ }
99+ self . to_gregorian_astronomical ( bs_year, bs_month, bs_day)
100+ }
101+
102+ fn from_gregorian_astronomical ( & mut self , y : i32 , m : i32 , d : i32 ) {
103+ let julian = self . get_julian_date ( y, m, d) ;
104+ let ahar = ( julian - 588465.5 ) as i64 ;
105+ let ( sm_num, sm_day) = self . get_saura_masa_day ( ahar) ;
106+ let year_kali = ( ( ahar as f64 * self . yuga_rotation_sun ) / self . yuga_civil_days ) . floor ( ) as i64 ;
107+ let year_saka = year_kali - 3179 ;
108+ let nepali_month = sm_num % 12 ;
109+ self . year = ( year_saka + 135 + ( ( sm_num - nepali_month) / 12 ) as i64 ) as i32 ;
110+ self . month = ( ( sm_num + 12 ) % 12 ) + 1 ;
111+ self . day = sm_day;
112+ }
113+
114+ fn to_gregorian_astronomical ( & self , bs_year : i32 , bs_month : i32 , bs_day : i32 ) -> ( i32 , i32 , i32 ) {
115+ let year_saka = bs_year - 135 ;
116+ let year_kali = year_saka + 3179 ;
117+ let mut ahar = ( ( year_kali as f64 * self . yuga_civil_days ) / self . yuga_rotation_sun ) . floor ( ) as i64 ;
118+ // Removed 'mut' as it's not reassigned after initialization
119+ let bs_month_zero_indexed = ( bs_month + 11 ) % 12 ; // Convert to 0-indexed for comparison
120+ loop {
121+ let ( sm, sd) = self . get_saura_masa_day ( ahar) ;
122+ if sm == bs_month_zero_indexed && sd == bs_day {
123+ break ;
124+ }
125+ ahar += if sm < bs_month_zero_indexed || ( sm == bs_month_zero_indexed && sd < bs_day) { 1 } else { -1 } ;
126+ }
127+ let jd = ahar as f64 + 588465.5 ;
128+ self . from_julian_date ( jd)
129+ }
130+
131+ fn get_saura_masa_day ( & self , ahar : i64 ) -> ( i32 , i32 ) {
132+ if self . today_saura_masa_first_p ( ahar) {
133+ let tslong_tomorrow = self . get_tslong ( ahar + 1 ) ;
134+ let month = ( ( tslong_tomorrow / 30.0 ) as i32 + 12 ) % 12 ;
135+ ( month, 1 )
136+ } else {
137+ let ( prev_month, mut day) = self . get_saura_masa_day ( ahar - 1 ) ;
138+ day += 1 ;
139+ ( prev_month, day)
140+ }
141+ }
142+
143+ fn today_saura_masa_first_p ( & self , ahar : i64 ) -> bool {
144+ let today = self . get_tslong ( ahar) % 30.0 ;
145+ let tomorrow = self . get_tslong ( ahar + 1 ) % 30.0 ;
146+ // Handle negative modulo results for consistency if any intermediate calculation leads to it
147+ let today_mod = ( today + 30.0 ) % 30.0 ;
148+ let tomorrow_mod = ( tomorrow + 30.0 ) % 30.0 ;
149+ today_mod > 25.0 && tomorrow_mod < 5.0
150+ }
151+
152+ fn get_tslong ( & self , ahar : i64 ) -> f64 {
153+ let mut t1 = ( self . yuga_rotation_sun * ahar as f64 ) / self . yuga_civil_days ;
154+ t1 -= t1. floor ( ) ;
155+ let mslong = 360.0 * t1;
156+ let x1 = mslong - self . planet_apogee_sun ;
157+ let y1 = self . planet_circum_sun / 360.0 ;
158+ let y2 = ( x1 / RAD ) . sin ( ) ;
159+ let y3 = y1 * y2;
160+ let x2 = y3. asin ( ) * RAD ;
161+ mslong - x2
162+ }
163+
164+ fn get_julian_date ( & self , y : i32 , m : i32 , d : i32 ) -> f64 {
165+ let ( mut y, mut m) = ( y, m) ;
166+ if m <= 2 {
167+ y -= 1 ;
168+ m += 12 ;
169+ }
170+ let a = ( y as f64 / 100.0 ) . floor ( ) ;
171+ let b = 2.0 - a + ( a / 4.0 ) . floor ( ) ;
172+ ( 365.25 * ( y as f64 + 4716.0 ) ) . floor ( )
173+ + ( 30.6001 * ( m as f64 + 1.0 ) ) . floor ( )
174+ + d as f64 + b - 1524.5
175+ }
176+
177+ fn from_julian_date ( & self , jd : f64 ) -> ( i32 , i32 , i32 ) {
178+ let z = ( jd + 0.5 ) . floor ( ) as i32 ;
179+ let a = if z < 2299161 {
180+ z
181+ } else {
182+ let alpha = ( ( z as f64 - 1867216.25 ) / 36524.25 ) . floor ( ) as i32 ;
183+ z + 1 + alpha - ( alpha / 4 )
184+ } ;
185+ let b = a + 1524 ;
186+ let c = ( ( b as f64 - 122.1 ) / 365.25 ) . floor ( ) as i32 ;
187+ let d = ( 365.25 * c as f64 ) . floor ( ) as i32 ;
188+ let e = ( ( b - d) as f64 / 30.6001 ) . floor ( ) as i32 ;
189+ let day = b - d - ( 30.6001 * e as f64 ) as i32 ;
190+ let month = if e < 14 { e - 1 } else { e - 13 } ;
191+ let year = if month > 2 { c - 4716 } else { c - 4715 } ;
192+ ( year, month, day)
193+ }
194+
195+ pub fn get_year ( & self ) -> i32 { self . year }
196+ pub fn get_month ( & self ) -> i32 { self . month }
197+ pub fn get_day ( & self ) -> i32 { self . day }
198+
199+ pub fn days_in_month ( & self , bs_year : i32 , bs_month : i32 ) -> i32 {
200+ if bs_year >= BS_START_YEAR && ( bs_year - BS_START_YEAR ) < NP_DATA_YEAR_COUNT as i32 {
201+ NP_MONTHS_DATA [ ( bs_year - BS_START_YEAR ) as usize ] [ ( bs_month - 1 ) as usize ]
202+ } else {
203+ let ( gy1, gm1, gd1) = self . to_gregorian ( bs_year, bs_month, 1 ) ;
204+ let ( gy2, gm2, gd2) = if bs_month == 12 {
205+ self . to_gregorian ( bs_year + 1 , 1 , 1 )
206+ } else {
207+ self . to_gregorian ( bs_year, bs_month + 1 , 1 )
208+ } ;
209+ let jd1 = self . get_julian_date ( gy1, gm1, gd1) ;
210+ let jd2 = self . get_julian_date ( gy2, gm2, gd2) ;
211+ ( jd2 - jd1) as i32
212+ }
213+ }
214+
215+ }
216+
0 commit comments