oxedyne/fe2o3/fe2o3_datime/tests/calendar.rs
22.1 KiB, 13 runs
created by r1870400018:6407, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | //! [Written with AI entirely](https://need2know.ai/entirely-ai/code)\ |
| 2 | //! Anthropic Claude |
| 3 | |
| 4 | use oxedyne_fe2o3_core::{ |
| 5 | prelude::*, |
| 6 | test::test_it, |
| 7 | }; |
| 8 | use oxedyne_fe2o3_datime::{ |
| 9 | calendar::Calendar, |
| 10 | constant::DayOfWeek, |
| 11 | core::Time, |
| 12 | time::CalClockZone, |
| 13 | }; |
| 14 | |
| 15 | pub fn test_calendar(filter: &str) -> Outcome<()> { |
| 16 | |
| 17 | res!(test_it(filter, &["calendar_creation", "all", "calendar", "comprehensive"], || { |
| 18 | // Test creating different calendar types |
| 19 | let gregorian = Calendar::new(); |
| 20 | assert_eq!(gregorian, Calendar::Gregorian); |
| 21 | assert_eq!(gregorian.name(), "Gregorian"); |
| 22 | assert_eq!(gregorian.id(), "gregorian"); |
| 23 | |
| 24 | let islamic = Calendar::Islamic; |
| 25 | assert_eq!(islamic.name(), "Islamic"); |
| 26 | assert_eq!(islamic.id(), "islamic"); |
| 27 | |
| 28 | let japanese = Calendar::Japanese; |
| 29 | assert_eq!(japanese.name(), "Japanese"); |
| 30 | assert_eq!(japanese.id(), "japanese"); |
| 31 | |
| 32 | let thai = Calendar::Thai; |
| 33 | assert_eq!(thai.name(), "Thai Buddhist"); |
| 34 | assert_eq!(thai.id(), "thai"); |
| 35 | |
| 36 | let minguo = Calendar::Minguo; |
| 37 | assert_eq!(minguo.name(), "Minguo"); |
| 38 | assert_eq!(minguo.id(), "minguo"); |
| 39 | |
| 40 | let holocene = Calendar::Holocene; |
| 41 | assert_eq!(holocene.name(), "Holocene"); |
| 42 | assert_eq!(holocene.id(), "holocene"); |
| 43 | |
| 44 | println!("✅ All calendar types created successfully"); |
| 45 | Ok(()) |
| 46 | })); |
| 47 | |
| 48 | res!(test_it(filter, &["calendar_date_creation", "all", "calendar", "comprehensive"], || { |
| 49 | let zone = CalClockZone::utc(); |
| 50 | |
| 51 | // Test Gregorian date creation (the new API) |
| 52 | let gregorian = Calendar::Gregorian; |
| 53 | let greg_date = res!(gregorian.date(2024, 1, 15, zone.clone())); |
| 54 | assert_eq!(greg_date.year(), 2024); |
| 55 | assert_eq!(greg_date.month(), 1); |
| 56 | assert_eq!(greg_date.day(), 15); |
| 57 | |
| 58 | // Test Thai Buddhist calendar (2567 = 2024 Gregorian) |
| 59 | let thai = Calendar::Thai; |
| 60 | let thai_date = res!(thai.date(2567, 1, 15, zone.clone())); |
| 61 | assert_eq!(thai_date.year(), 2024); // Internal Gregorian representation |
| 62 | |
| 63 | // Test Minguo calendar (113 = 2024 Gregorian) |
| 64 | let minguo = Calendar::Minguo; |
| 65 | let minguo_date = res!(minguo.date(113, 1, 15, zone.clone())); |
| 66 | assert_eq!(minguo_date.year(), 2024); // Internal Gregorian representation |
| 67 | |
| 68 | // Test Holocene calendar (12024 = 2024 Gregorian) |
| 69 | let holocene = Calendar::Holocene; |
| 70 | let holocene_date = res!(holocene.date(12024, 1, 15, zone.clone())); |
| 71 | assert_eq!(holocene_date.year(), 2024); // Internal Gregorian representation |
| 72 | |
| 73 | // Test Islamic calendar basic creation |
| 74 | let islamic = Calendar::Islamic; |
| 75 | let islamic_date = res!(islamic.date(1445, 1, 15, zone.clone())); |
| 76 | // Islamic dates are converted internally - the exact conversion is complex |
| 77 | assert!(islamic_date.year() > 1000); // Should be a reasonable Gregorian year |
| 78 | |
| 79 | println!("✅ Date creation with new Calendar API works correctly"); |
| 80 | Ok(()) |
| 81 | })); |
| 82 | |
| 83 | res!(test_it(filter, &["calendar_leap_years", "all", "calendar", "comprehensive"], || { |
| 84 | // Test leap year calculations for different calendars |
| 85 | |
| 86 | // Gregorian leap years |
| 87 | let gregorian = Calendar::Gregorian; |
| 88 | assert!(gregorian.is_leap_year(2024)); // Divisible by 4 |
| 89 | assert!(!gregorian.is_leap_year(1900)); // Century not divisible by 400 |
| 90 | assert!(gregorian.is_leap_year(2000)); // Century divisible by 400 |
| 91 | assert!(!gregorian.is_leap_year(2023)); // Not divisible by 4 |
| 92 | |
| 93 | // Julian leap years (every 4 years, no exceptions) |
| 94 | let julian = Calendar::Julian; |
| 95 | assert!(julian.is_leap_year(2024)); |
| 96 | assert!(julian.is_leap_year(1900)); // Leap in Julian, not Gregorian |
| 97 | assert!(julian.is_leap_year(2000)); |
| 98 | assert!(!julian.is_leap_year(2023)); |
| 99 | |
| 100 | // Islamic leap years (30-year cycle) |
| 101 | let islamic = Calendar::Islamic; |
| 102 | assert!(islamic.is_leap_year(2)); // 2nd year of cycle |
| 103 | assert!(islamic.is_leap_year(5)); // 5th year of cycle |
| 104 | assert!(!islamic.is_leap_year(1)); // 1st year not leap |
| 105 | assert!(!islamic.is_leap_year(3)); // 3rd year not leap |
| 106 | |
| 107 | // Thai, Minguo, and Holocene use Gregorian rules |
| 108 | let thai = Calendar::Thai; |
| 109 | let minguo = Calendar::Minguo; |
| 110 | let holocene = Calendar::Holocene; |
| 111 | |
| 112 | assert!(thai.is_leap_year(2567)); // Thai 2567 = Gregorian 2024 |
| 113 | assert!(minguo.is_leap_year(113)); // Minguo 113 = Gregorian 2024 |
| 114 | assert!(holocene.is_leap_year(12024)); // Holocene 12024 = Gregorian 2024 |
| 115 | |
| 116 | println!("✅ Leap year calculations work correctly for all calendars"); |
| 117 | Ok(()) |
| 118 | })); |
| 119 | |
| 120 | res!(test_it(filter, &["calendar_month_days", "all", "calendar", "comprehensive"], || { |
| 121 | // Test days in month for different calendars |
| 122 | |
| 123 | // Gregorian/Thai/Minguo/Holocene all use same month structure |
| 124 | let gregorian = Calendar::Gregorian; |
| 125 | assert_eq!(res!(gregorian.days_in_month(2024, 1)), 31); // January |
| 126 | assert_eq!(res!(gregorian.days_in_month(2024, 2)), 29); // February leap year |
| 127 | assert_eq!(res!(gregorian.days_in_month(2023, 2)), 28); // February non-leap |
| 128 | assert_eq!(res!(gregorian.days_in_month(2024, 4)), 30); // April |
| 129 | |
| 130 | // Islamic calendar has different month structure |
| 131 | let islamic = Calendar::Islamic; |
| 132 | assert_eq!(res!(islamic.days_in_month(1445, 1)), 30); // Muharram (odd month) |
| 133 | assert_eq!(res!(islamic.days_in_month(1445, 2)), 29); // Safar (even month) |
| 134 | |
| 135 | // Year 1445 is cycle year 5, which IS a leap year |
| 136 | assert!(islamic.is_leap_year(1445)); // Year 5 of 30-year cycle |
| 137 | assert_eq!(res!(islamic.days_in_month(1445, 12)), 30); // Dhul-Hijjah leap year |
| 138 | |
| 139 | // Test non-leap year (1444 is cycle year 4, not leap) |
| 140 | assert!(!islamic.is_leap_year(1444)); // Year 4 of 30-year cycle, not leap |
| 141 | assert_eq!(res!(islamic.days_in_month(1444, 12)), 29); // Dhul-Hijjah non-leap year |
| 142 | |
| 143 | println!("✅ Days in month calculations work correctly for all calendars"); |
| 144 | Ok(()) |
| 145 | })); |
| 146 | |
| 147 | res!(test_it(filter, &["calendar_validation", "all", "calendar", "comprehensive"], || { |
| 148 | // Test date validation for different calendars |
| 149 | |
| 150 | let gregorian = Calendar::Gregorian; |
| 151 | let islamic = Calendar::Islamic; |
| 152 | let thai = Calendar::Thai; |
| 153 | let japanese = Calendar::Japanese; |
| 154 | |
| 155 | // Valid dates |
| 156 | assert!(gregorian.validate_date(2024, 2, 29).is_ok()); // Leap year |
| 157 | assert!(islamic.validate_date(1445, 1, 30).is_ok()); // Valid Islamic date |
| 158 | assert!(thai.validate_date(2567, 1, 31).is_ok()); // Valid Thai date |
| 159 | assert!(japanese.validate_date(5, 1, 15).is_ok()); // Valid Japanese era year |
| 160 | |
| 161 | // Invalid dates |
| 162 | assert!(gregorian.validate_date(2023, 2, 29).is_err()); // Non-leap year Feb 29 |
| 163 | assert!(gregorian.validate_date(2024, 4, 31).is_err()); // April has 30 days |
| 164 | assert!(islamic.validate_date(1445, 1, 31).is_err()); // Month 1 has 30 days |
| 165 | assert!(islamic.validate_date(1445, 13, 1).is_err()); // Month 13 doesn't exist |
| 166 | assert!(islamic.validate_date(0, 1, 1).is_err()); // Year 0 invalid |
| 167 | assert!(thai.validate_date(0, 1, 1).is_err()); // Year 0 invalid |
| 168 | |
| 169 | // Day 0 invalid for all calendars |
| 170 | assert!(gregorian.validate_date(2024, 1, 0).is_err()); |
| 171 | assert!(islamic.validate_date(1445, 1, 0).is_err()); |
| 172 | |
| 173 | println!("✅ Date validation works correctly for all calendars"); |
| 174 | Ok(()) |
| 175 | })); |
| 176 | |
| 177 | res!(test_it(filter, &["calendar_parsing", "all", "calendar", "comprehensive"], || { |
| 178 | // Test parsing calendar names from strings |
| 179 | |
| 180 | assert_eq!(res!(Calendar::from_str("gregorian")), Calendar::Gregorian); |
| 181 | assert_eq!(res!(Calendar::from_str("GREGORIAN")), Calendar::Gregorian); |
| 182 | assert_eq!(res!(Calendar::from_str("greg")), Calendar::Gregorian); |
| 183 | assert_eq!(res!(Calendar::from_str("g")), Calendar::Gregorian); |
| 184 | |
| 185 | assert_eq!(res!(Calendar::from_str("julian")), Calendar::Julian); |
| 186 | assert_eq!(res!(Calendar::from_str("jul")), Calendar::Julian); |
| 187 | assert_eq!(res!(Calendar::from_str("j")), Calendar::Julian); |
| 188 | |
| 189 | assert_eq!(res!(Calendar::from_str("islamic")), Calendar::Islamic); |
| 190 | assert_eq!(res!(Calendar::from_str("hijri")), Calendar::Islamic); |
| 191 | assert_eq!(res!(Calendar::from_str("muslim")), Calendar::Islamic); |
| 192 | assert_eq!(res!(Calendar::from_str("i")), Calendar::Islamic); |
| 193 | |
| 194 | assert_eq!(res!(Calendar::from_str("japanese")), Calendar::Japanese); |
| 195 | assert_eq!(res!(Calendar::from_str("jp")), Calendar::Japanese); |
| 196 | assert_eq!(res!(Calendar::from_str("imperial")), Calendar::Japanese); |
| 197 | |
| 198 | assert_eq!(res!(Calendar::from_str("thai")), Calendar::Thai); |
| 199 | assert_eq!(res!(Calendar::from_str("buddhist")), Calendar::Thai); |
| 200 | assert_eq!(res!(Calendar::from_str("th")), Calendar::Thai); |
| 201 | |
| 202 | assert_eq!(res!(Calendar::from_str("minguo")), Calendar::Minguo); |
| 203 | assert_eq!(res!(Calendar::from_str("roc")), Calendar::Minguo); |
| 204 | assert_eq!(res!(Calendar::from_str("taiwan")), Calendar::Minguo); |
| 205 | |
| 206 | assert_eq!(res!(Calendar::from_str("holocene")), Calendar::Holocene); |
| 207 | assert_eq!(res!(Calendar::from_str("human")), Calendar::Holocene); |
| 208 | assert_eq!(res!(Calendar::from_str("h")), Calendar::Holocene); |
| 209 | |
| 210 | // Invalid calendar name |
| 211 | assert!(Calendar::from_str("invalid").is_err()); |
| 212 | |
| 213 | println!("✅ Calendar name parsing works correctly"); |
| 214 | Ok(()) |
| 215 | })); |
| 216 | |
| 217 | res!(test_it(filter, &["calendar_year_conversions", "all", "calendar", "comprehensive"], || { |
| 218 | // Test year conversions between different calendars |
| 219 | |
| 220 | // Test known conversions |
| 221 | let gregorian = Calendar::Gregorian; |
| 222 | let thai = Calendar::Thai; |
| 223 | let minguo = Calendar::Minguo; |
| 224 | let holocene = Calendar::Holocene; |
| 225 | |
| 226 | // Thai Buddhist = Gregorian + 543 |
| 227 | // So Thai 2567 = Gregorian 2024 |
| 228 | assert_eq!(thai.to_gregorian_year(2567), 2024); |
| 229 | |
| 230 | // Minguo = Gregorian - 1911 |
| 231 | // So Minguo 113 = Gregorian 2024 |
| 232 | assert_eq!(minguo.to_gregorian_year(113), 2024); |
| 233 | |
| 234 | // Holocene = Gregorian + 10000 |
| 235 | // So Holocene 12024 = Gregorian 2024 |
| 236 | assert_eq!(holocene.to_gregorian_year(12024), 2024); |
| 237 | |
| 238 | // Test epoch years |
| 239 | assert_eq!(gregorian.epoch_year(), 1); |
| 240 | assert_eq!(thai.epoch_year(), -543); // 544 BCE |
| 241 | assert_eq!(minguo.epoch_year(), 1912); |
| 242 | assert_eq!(holocene.epoch_year(), -9999); // 10,000 BCE |
| 243 | |
| 244 | println!("✅ Year conversions work correctly between calendars"); |
| 245 | Ok(()) |
| 246 | })); |
| 247 | |
| 248 | res!(test_it(filter, &["calendar_info_methods", "all", "calendar", "comprehensive"], || { |
| 249 | // Test informational methods |
| 250 | |
| 251 | let calendars = Calendar::all().collect::<Vec<_>>(); |
| 252 | assert_eq!(calendars.len(), 8); |
| 253 | |
| 254 | for calendar in calendars { |
| 255 | // Each calendar should have non-empty name, id, and description |
| 256 | assert!(!calendar.name().is_empty()); |
| 257 | assert!(!calendar.id().is_empty()); |
| 258 | assert!(!calendar.description().is_empty()); |
| 259 | |
| 260 | // Test display |
| 261 | let display_string = format!("{}", calendar); |
| 262 | assert_eq!(display_string, calendar.name()); |
| 263 | } |
| 264 | |
| 265 | // Test specific descriptions |
| 266 | assert!(Calendar::Gregorian.description().contains("1582")); |
| 267 | assert!(Calendar::Islamic.description().contains("Lunar")); |
| 268 | assert!(Calendar::Japanese.description().contains("era")); |
| 269 | assert!(Calendar::Thai.description().contains("Buddhist")); |
| 270 | assert!(Calendar::Minguo.description().contains("Republic")); |
| 271 | assert!(Calendar::Holocene.description().contains("Scientific")); |
| 272 | |
| 273 | println!("✅ Calendar information methods work correctly"); |
| 274 | Ok(()) |
| 275 | })); |
| 276 | |
| 277 | res!(test_it(filter, &["calendar_conversion_matrix", "all", "calendar", "comprehensive"], || { |
| 278 | // Test comprehensive conversion matrix between all calendar systems |
| 279 | let zone = CalClockZone::utc(); |
| 280 | |
| 281 | // Test data: same date represented in different calendar systems |
| 282 | // Note: Islamic and Japanese calendars are excluded from comprehensive testing |
| 283 | // as they need more sophisticated conversion algorithms |
| 284 | let test_cases: Vec<(Calendar, i32, u8, u8)> = vec![ |
| 285 | (Calendar::Gregorian, 2024, 1, 15), |
| 286 | (Calendar::Thai, 2567, 1, 15), // Thai 2567 = Gregorian 2024 |
| 287 | (Calendar::Minguo, 113, 1, 15), // Minguo 113 = Gregorian 2024 |
| 288 | (Calendar::Holocene, 12024, 1, 15), // Holocene 12024 = Gregorian 2024 |
| 289 | (Calendar::Julian, 2024, 1, 15), // Julian and Gregorian coincide for modern dates |
| 290 | ]; |
| 291 | |
| 292 | // Test conversions between supported calendars (excluding Islamic and Japanese for now) |
| 293 | let supported_calendars = vec![ |
| 294 | Calendar::Gregorian, |
| 295 | Calendar::Julian, |
| 296 | Calendar::Thai, |
| 297 | Calendar::Minguo, |
| 298 | Calendar::Holocene, |
| 299 | ]; |
| 300 | |
| 301 | for (source_calendar, year, month, day) in &test_cases { |
| 302 | let source_date = res!(source_calendar.date(*year, *month, *day, zone.clone())); |
| 303 | |
| 304 | for target_calendar in &supported_calendars { |
| 305 | if source_calendar == target_calendar { |
| 306 | continue; // Skip self-conversion |
| 307 | } |
| 308 | |
| 309 | // Convert to target calendar |
| 310 | let converted_date = res!(source_calendar.convert_date(&source_date, target_calendar)); |
| 311 | |
| 312 | // Convert back to source calendar |
| 313 | let round_trip_date = res!(target_calendar.convert_date(&converted_date, source_calendar)); |
| 314 | |
| 315 | // Round-trip should return to original date (allowing for precision differences) |
| 316 | assert_eq!( |
| 317 | round_trip_date.year(), source_date.year(), |
| 318 | "Round-trip conversion failed: {} -> {} -> {} (year mismatch)", |
| 319 | source_calendar.name(), target_calendar.name(), source_calendar.name() |
| 320 | ); |
| 321 | assert_eq!( |
| 322 | round_trip_date.month(), source_date.month(), |
| 323 | "Round-trip conversion failed: {} -> {} -> {} (month mismatch)", |
| 324 | source_calendar.name(), target_calendar.name(), source_calendar.name() |
| 325 | ); |
| 326 | assert_eq!( |
| 327 | round_trip_date.day(), source_date.day(), |
| 328 | "Round-trip conversion failed: {} -> {} -> {} (day mismatch)", |
| 329 | source_calendar.name(), target_calendar.name(), source_calendar.name() |
| 330 | ); |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | // Test specific Islamic calendar conversions (more complex due to lunar nature) |
| 335 | let islamic = Calendar::Islamic; |
| 336 | let gregorian = Calendar::Gregorian; |
| 337 | |
| 338 | let islamic_date = res!(islamic.date(1445, 7, 15, zone.clone())); // Islamic date |
| 339 | let gregorian_equivalent = res!(islamic.convert_date(&islamic_date, &gregorian)); |
| 340 | let back_to_islamic = res!(gregorian.convert_date(&gregorian_equivalent, &islamic)); |
| 341 | |
| 342 | // Islamic conversions may have slight variations due to lunar vs solar calendar differences |
| 343 | // Just ensure the conversion is reasonable (should be in early 2024) |
| 344 | assert!(gregorian_equivalent.year() >= 2023 && gregorian_equivalent.year() <= 2025, |
| 345 | "Islamic to Gregorian conversion should yield date around 2024, got {}", |
| 346 | gregorian_equivalent.year()); |
| 347 | |
| 348 | println!("✅ Calendar conversion matrix tested successfully"); |
| 349 | Ok(()) |
| 350 | })); |
| 351 | |
| 352 | res!(test_it(filter, &["calendar_practical_examples", "all", "calendar", "comprehensive"], || { |
| 353 | // Test practical usage examples |
| 354 | let zone = CalClockZone::utc(); |
| 355 | |
| 356 | // Example 1: Creating dates in different calendar systems |
| 357 | let gregorian = Calendar::new(); // Default to Gregorian |
| 358 | let date_2024 = res!(gregorian.date(2024, 1, 15, zone.clone())); |
| 359 | |
| 360 | // Same date in different calendars |
| 361 | let thai = Calendar::Thai; |
| 362 | let thai_date = res!(thai.date(2567, 1, 15, zone.clone())); // Thai 2567 = Gregorian 2024 |
| 363 | |
| 364 | let holocene = Calendar::Holocene; |
| 365 | let holocene_date = res!(holocene.date(12024, 1, 15, zone.clone())); // Holocene 12024 = Gregorian 2024 |
| 366 | |
| 367 | // All should represent the same date internally |
| 368 | assert_eq!(date_2024.year(), thai_date.year()); |
| 369 | assert_eq!(date_2024.year(), holocene_date.year()); |
| 370 | assert_eq!(date_2024.month(), thai_date.month()); |
| 371 | assert_eq!(date_2024.month(), holocene_date.month()); |
| 372 | assert_eq!(date_2024.day(), thai_date.day()); |
| 373 | assert_eq!(date_2024.day(), holocene_date.day()); |
| 374 | |
| 375 | // Example 2: Working with Islamic calendar |
| 376 | let islamic = Calendar::Islamic; |
| 377 | let _islamic_date = res!(islamic.date(1445, 7, 15, zone.clone())); |
| 378 | |
| 379 | // Islamic calendar should have different month structure |
| 380 | assert_eq!(res!(islamic.days_in_month(1445, 7)), 30); // 7th month (Rajab) has 30 days |
| 381 | assert_eq!(res!(islamic.days_in_month(1445, 8)), 29); // 8th month (Sha'ban) has 29 days |
| 382 | |
| 383 | // Example 3: Leap year differences |
| 384 | let julian = Calendar::Julian; |
| 385 | |
| 386 | // Year 1900: leap in Julian, not in Gregorian |
| 387 | assert!(julian.is_leap_year(1900)); |
| 388 | assert!(!gregorian.is_leap_year(1900)); |
| 389 | |
| 390 | // This affects February days |
| 391 | assert_eq!(res!(julian.days_in_month(1900, 2)), 29); |
| 392 | assert_eq!(res!(gregorian.days_in_month(1900, 2)), 28); |
| 393 | |
| 394 | println!("✅ Practical calendar examples work correctly"); |
| 395 | Ok(()) |
| 396 | })); |
| 397 | |
| 398 | // Additional comprehensive tests merged from calendar.rs |
| 399 | |
| 400 | res!(test_it(filter, &["day_of_week", "all", "calendar", "comprehensive"], || { |
| 401 | let zone = CalClockZone::utc(); |
| 402 | let gregorian = Calendar::Gregorian; |
| 403 | |
| 404 | // Some known dates |
| 405 | let date1 = res!(gregorian.date(2024, 1, 1, zone.clone())); // Monday |
| 406 | assert_eq!(date1.day_of_week(), DayOfWeek::Monday); |
| 407 | |
| 408 | let date2 = res!(gregorian.date(2024, 3, 15, zone.clone())); // Friday |
| 409 | assert_eq!(date2.day_of_week(), DayOfWeek::Friday); |
| 410 | |
| 411 | let date3 = res!(gregorian.date(2000, 1, 1, zone.clone())); // Saturday |
| 412 | assert_eq!(date3.day_of_week(), DayOfWeek::Saturday); |
| 413 | |
| 414 | // Dates whose Zeller numerator is negative, which a plain % turned |
| 415 | // into an unreachable panic. Weekdays confirmed against `date -d`. |
| 416 | let date4 = res!(gregorian.date(2004, 3, 15, zone.clone())); // Monday |
| 417 | assert_eq!(date4.day_of_week(), DayOfWeek::Monday); |
| 418 | |
| 419 | let date5 = res!(gregorian.date(2000, 5, 1, zone.clone())); // Monday |
| 420 | assert_eq!(date5.day_of_week(), DayOfWeek::Monday); |
| 421 | |
| 422 | let date6 = res!(gregorian.date(1999, 8, 14, zone.clone())); // Saturday |
| 423 | assert_eq!(date6.day_of_week(), DayOfWeek::Saturday); |
| 424 | |
| 425 | println!("✅ Day of week calculations work correctly"); |
| 426 | Ok(()) |
| 427 | })); |
| 428 | |
| 429 | res!(test_it(filter, &["date_arithmetic", "all", "calendar", "comprehensive"], || { |
| 430 | let zone = CalClockZone::utc(); |
| 431 | let gregorian = Calendar::Gregorian; |
| 432 | |
| 433 | // Test adding days |
| 434 | let date1 = res!(gregorian.date(2024, 1, 31, zone.clone())); |
| 435 | let date2 = res!(date1.add_days(1)); |
| 436 | assert_eq!(date2.year(), 2024); |
| 437 | assert_eq!(date2.month(), 2); |
| 438 | assert_eq!(date2.day(), 1); |
| 439 | |
| 440 | // Test adding months with day adjustment |
| 441 | let date3 = res!(date1.plus(0, 1, 0)); // Jan 31 + 1 month = Feb 29 (leap year) |
| 442 | assert_eq!(date3.year(), 2024); |
| 443 | assert_eq!(date3.month(), 2); |
| 444 | assert_eq!(date3.day(), 29); |
| 445 | |
| 446 | // Test subtracting |
| 447 | let date4 = res!(gregorian.date(2024, 3, 1, zone.clone())); |
| 448 | let date5 = res!(date4.minus(0, 0, 1)); |
| 449 | assert_eq!(date5.year(), 2024); |
| 450 | assert_eq!(date5.month(), 2); |
| 451 | assert_eq!(date5.day(), 29); // Leap year |
| 452 | |
| 453 | println!("✅ Date arithmetic operations work correctly"); |
| 454 | Ok(()) |
| 455 | })); |
| 456 | |
| 457 | res!(test_it(filter, &["date_comparison", "all", "calendar", "comprehensive"], || { |
| 458 | let zone = CalClockZone::utc(); |
| 459 | let gregorian = Calendar::Gregorian; |
| 460 | |
| 461 | let date1 = res!(gregorian.date(2024, 1, 15, zone.clone())); |
| 462 | let date2 = res!(gregorian.date(2024, 1, 16, zone.clone())); |
| 463 | let date3 = res!(gregorian.date(2024, 1, 15, zone.clone())); |
| 464 | |
| 465 | assert!(date1.is_before(&date2)); |
| 466 | assert!(!date2.is_before(&date1)); |
| 467 | assert!(!date1.is_before(&date3)); |
| 468 | |
| 469 | assert!(date2.is_after(&date1)); |
| 470 | assert!(!date1.is_after(&date2)); |
| 471 | assert!(!date1.is_after(&date3)); |
| 472 | |
| 473 | assert_eq!(date1, date3); |
| 474 | assert_ne!(date1, date2); |
| 475 | |
| 476 | println!("✅ Date comparison operations work correctly"); |
| 477 | Ok(()) |
| 478 | })); |
| 479 | |
| 480 | res!(test_it(filter, &["day_of_year", "all", "calendar", "comprehensive"], || { |
| 481 | let zone = CalClockZone::utc(); |
| 482 | let gregorian = Calendar::Gregorian; |
| 483 | |
| 484 | let date1 = res!(gregorian.date(2024, 1, 1, zone.clone())); |
| 485 | assert_eq!(res!(date1.day_of_year()), 1); |
| 486 | |
| 487 | let date2 = res!(gregorian.date(2024, 12, 31, zone.clone())); |
| 488 | assert_eq!(res!(date2.day_of_year()), 366); // Leap year |
| 489 | |
| 490 | let date3 = res!(gregorian.date(2023, 12, 31, zone.clone())); |
| 491 | assert_eq!(res!(date3.day_of_year()), 365); // Non-leap year |
| 492 | |
| 493 | let date4 = res!(gregorian.date(2024, 3, 1, zone.clone())); |
| 494 | assert_eq!(res!(date4.day_of_year()), 61); // 31 (Jan) + 29 (Feb) + 1 |
| 495 | |
| 496 | println!("✅ Day of year calculations work correctly"); |
| 497 | Ok(()) |
| 498 | })); |
| 499 | |
| 500 | Ok(()) |
| 501 | } |