Skip to main content

amlich_core/
lib.rs

1// amlich-core - Vietnamese Lunar Calendar Core Library
2//
3// This library provides comprehensive Vietnamese lunar calendar calculations including:
4// - Solar ↔ Lunar date conversion
5// - Can Chi (Heavenly Stems & Earthly Branches) calculations
6// - Tiết Khí (24 Solar Terms)
7// - Giờ Hoàng Đạo (Auspicious Hours)
8// - Vietnamese holidays and festivals
9
10pub mod canchi;
11pub mod gio_hoang_dao;
12pub mod holiday_data;
13pub mod holidays;
14pub mod insight_data;
15pub mod julian;
16pub mod lunar;
17pub mod sun;
18pub mod tietkhi;
19pub mod types;
20
21// Re-export main types
22pub use types::*;
23
24use canchi::{get_day_canchi, get_month_canchi, get_year_canchi};
25use gio_hoang_dao::{get_gio_hoang_dao, GioHoangDao};
26use julian::jd_from_date;
27use lunar::convert_solar_to_lunar;
28use tietkhi::{get_tiet_khi, SolarTerm};
29
30/// Solar date information
31#[derive(Debug, Clone)]
32pub struct SolarInfo {
33    pub day: i32,
34    pub month: i32,
35    pub year: i32,
36    pub day_of_week: usize,
37    pub day_of_week_name: String,
38    pub date_string: String,
39}
40
41/// Lunar date information
42#[derive(Debug, Clone)]
43pub struct LunarInfo {
44    pub day: i32,
45    pub month: i32,
46    pub year: i32,
47    pub is_leap_month: bool,
48    pub date_string: String,
49}
50
51/// Can Chi information for day, month, and year
52#[derive(Debug, Clone)]
53pub struct CanChiInfo {
54    pub day: CanChi,
55    pub month: CanChi,
56    pub year: CanChi,
57    pub full: String,
58}
59
60/// Complete information about a day
61#[derive(Debug, Clone)]
62pub struct DayInfo {
63    pub solar: SolarInfo,
64    pub lunar: LunarInfo,
65    pub jd: i32,
66    pub canchi: CanChiInfo,
67    pub tiet_khi: SolarTerm,
68    pub gio_hoang_dao: GioHoangDao,
69}
70
71/// Get comprehensive information for a given solar date
72///
73/// # Arguments
74/// * `day` - Day (1-31)
75/// * `month` - Month (1-12)
76/// * `year` - Year
77///
78/// # Returns
79/// Complete day information including solar, lunar, Can Chi, solar terms, and auspicious hours
80///
81/// # Example
82/// ```
83/// use amlich_core::get_day_info;
84///
85/// // Get info for Tết 2024 (February 10, 2024)
86/// let info = get_day_info(10, 2, 2024);
87/// println!("Lunar date: {}/{}/{}", info.lunar.day, info.lunar.month, info.lunar.year);
88/// println!("Day Can Chi: {}", info.canchi.day.full);
89/// ```
90pub fn get_day_info(day: i32, month: i32, year: i32) -> DayInfo {
91    get_day_info_with_timezone(day, month, year, VIETNAM_TIMEZONE)
92}
93
94/// Get comprehensive information for a given solar date with custom timezone
95///
96/// # Arguments
97/// * `day` - Day (1-31)
98/// * `month` - Month (1-12)
99/// * `year` - Year
100/// * `time_zone` - Timezone offset (default: VIETNAM_TIMEZONE for Vietnam UTC+7)
101///
102/// # Returns
103/// Complete day information
104pub fn get_day_info_with_timezone(day: i32, month: i32, year: i32, time_zone: f64) -> DayInfo {
105    // Calculate Julian Day Number
106    let jd = jd_from_date(day, month, year);
107
108    // Convert to lunar date
109    let lunar_date = convert_solar_to_lunar(day, month, year, time_zone);
110
111    // Calculate day of week (JD + 1 because JD 0 was Monday)
112    let day_of_week = ((jd + 1) % 7) as usize;
113
114    // Calculate Can Chi for day, month, year
115    let day_canchi = get_day_canchi(jd);
116    let month_canchi = get_month_canchi(lunar_date.month, lunar_date.year, lunar_date.is_leap);
117    let year_canchi = get_year_canchi(lunar_date.year);
118
119    // Calculate Solar Term (Tiết Khí)
120    let tiet_khi = get_tiet_khi(jd, time_zone);
121
122    // Calculate Auspicious Hours (Giờ Hoàng Đạo)
123    let gio_hoang_dao = get_gio_hoang_dao(day_canchi.chi_index);
124
125    // Build solar info
126    let solar = SolarInfo {
127        day,
128        month,
129        year,
130        day_of_week,
131        day_of_week_name: THU[day_of_week].to_string(),
132        date_string: format!("{}-{:02}-{:02}", year, month, day),
133    };
134
135    // Build lunar info
136    let lunar = LunarInfo {
137        day: lunar_date.day,
138        month: lunar_date.month,
139        year: lunar_date.year,
140        is_leap_month: lunar_date.is_leap,
141        date_string: format!(
142            "{}/{}/{}{}",
143            lunar_date.day,
144            lunar_date.month,
145            lunar_date.year,
146            if lunar_date.is_leap { " (nhuận)" } else { "" }
147        ),
148    };
149
150    // Build Can Chi info
151    let canchi = CanChiInfo {
152        day: day_canchi.clone(),
153        month: month_canchi.clone(),
154        year: year_canchi.clone(),
155        full: format!(
156            "{}, tháng {}, năm {}",
157            day_canchi.full, month_canchi.full, year_canchi.full
158        ),
159    };
160
161    DayInfo {
162        solar,
163        lunar,
164        jd,
165        canchi,
166        tiet_khi,
167        gio_hoang_dao,
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174
175    #[test]
176    fn test_get_day_info_tet_2024() {
177        // Tết 2024: February 10, 2024
178        let info = get_day_info(10, 2, 2024);
179
180        // Check solar date
181        assert_eq!(info.solar.day, 10);
182        assert_eq!(info.solar.month, 2);
183        assert_eq!(info.solar.year, 2024);
184
185        // Check lunar date (should be 1/1/2024)
186        assert_eq!(info.lunar.day, 1);
187        assert_eq!(info.lunar.month, 1);
188        assert_eq!(info.lunar.year, 2024);
189        assert!(!info.lunar.is_leap_month);
190
191        // Check Can Chi
192        assert_eq!(info.canchi.day.full, "Giáp Thìn");
193        assert_eq!(info.canchi.year.full, "Giáp Thìn");
194    }
195
196    #[test]
197    fn test_get_day_info_tet_2025() {
198        // Tết 2025: January 29, 2025
199        let info = get_day_info(29, 1, 2025);
200
201        // Check lunar date (should be 1/1/2025)
202        assert_eq!(info.lunar.day, 1);
203        assert_eq!(info.lunar.month, 1);
204        assert_eq!(info.lunar.year, 2025);
205
206        // Check Can Chi
207        assert_eq!(info.canchi.day.full, "Mậu Tuất");
208        assert_eq!(info.canchi.year.full, "Ất Tỵ");
209    }
210
211    #[test]
212    fn test_day_of_week() {
213        // Test a known day: January 1, 2000 was a Saturday (index 6)
214        let info = get_day_info(1, 1, 2000);
215        assert_eq!(info.solar.day_of_week, 6);
216        assert_eq!(info.solar.day_of_week_name, "Thứ Bảy");
217    }
218
219    #[test]
220    fn test_gio_hoang_dao_present() {
221        let info = get_day_info(10, 2, 2024);
222
223        // Should have 6 good hours
224        assert_eq!(info.gio_hoang_dao.good_hour_count, 6);
225        assert_eq!(info.gio_hoang_dao.good_hours.len(), 6);
226    }
227
228    #[test]
229    fn test_custom_timezone() {
230        // Test with different timezone (should work but give potentially different results)
231        let info = get_day_info_with_timezone(10, 2, 2024, 8.0);
232
233        // Should still work
234        assert_eq!(info.solar.day, 10);
235        assert_eq!(info.solar.month, 2);
236        assert_eq!(info.solar.year, 2024);
237    }
238}