#[cfg(test)]
mod tests {
use super::*;
use std::ops::{Add, Sub};
use timekit::{
adjust_second_with_timezone, calculate_date_since_epoch, compute_total_seconds,
constants::*, days_in_month, is_leap_year, now, DateTime, TimeDelta, TimeZone,
};
#[test]
fn test_is_leap_year() {
assert_eq!(is_leap_year(2020), true);
assert_eq!(is_leap_year(2024), true);
assert_eq!(is_leap_year(1900), false);
assert_eq!(is_leap_year(2000), true);
assert_eq!(is_leap_year(2019), false);
assert_eq!(is_leap_year(2021), false);
}
#[test]
fn test_days_in_month() {
assert_eq!(days_in_month(1, 2023), 31);
assert_eq!(days_in_month(3, 2023), 31);
assert_eq!(days_in_month(5, 2023), 31);
assert_eq!(days_in_month(7, 2023), 31);
assert_eq!(days_in_month(8, 2023), 31);
assert_eq!(days_in_month(10, 2023), 31);
assert_eq!(days_in_month(12, 2023), 31);
assert_eq!(days_in_month(4, 2023), 30);
assert_eq!(days_in_month(6, 2023), 30);
assert_eq!(days_in_month(9, 2023), 30);
assert_eq!(days_in_month(11, 2023), 30);
assert_eq!(days_in_month(2, 2024), 29);
assert_eq!(days_in_month(2, 2023), 28);
assert_eq!(days_in_month(13, 2023), 0);
assert_eq!(days_in_month(0, 2023), 0);
}
#[test]
fn test_datetime_new_valid() {
let datetime = DateTime::new(2023, 1, 1, 0, 0, 0, TimeZone::UTC);
assert!(datetime.is_ok());
let datetime = DateTime::new(2024, 2, 29, 23, 59, 59, TimeZone::UTC); assert!(datetime.is_ok());
let datetime = DateTime::new(2023, 12, 31, 23, 59, 59, TimeZone::UTC);
assert!(datetime.is_ok());
}
#[test]
fn test_datetime_new_invalid() {
let datetime = DateTime::new(2023, 0, 1, 0, 0, 0, TimeZone::UTC);
assert!(datetime.is_err());
let datetime = DateTime::new(2023, 13, 1, 0, 0, 0, TimeZone::UTC);
assert!(datetime.is_err());
let datetime = DateTime::new(2023, 2, 29, 0, 0, 0, TimeZone::UTC); assert!(datetime.is_err());
let datetime = DateTime::new(2023, 1, 1, 24, 0, 0, TimeZone::UTC);
assert!(datetime.is_err());
let datetime = DateTime::new(2023, 1, 1, 0, 60, 0, TimeZone::UTC);
assert!(datetime.is_err());
let datetime = DateTime::new(2023, 1, 1, 0, 0, 60, TimeZone::UTC);
assert!(datetime.is_err());
}
#[test]
fn test_now_utc() {
let current_time = now(TimeZone::UTC).unwrap();
assert!(current_time.year >= 1970);
assert!(current_time.month >= 1 && current_time.month <= 12);
assert!(current_time.day >= 1 && current_time.day <= 31);
assert!(current_time.hour <= 23);
assert!(current_time.minute <= 59);
assert!(current_time.second <= 59);
}
#[test]
fn test_now_kst() {
let current_time = now(TimeZone::KST).unwrap();
assert!(current_time.year >= 1970);
assert!(current_time.month >= 1 && current_time.month <= 12);
assert!(current_time.day >= 1 && current_time.day <= 31);
assert!(current_time.hour <= 23);
assert!(current_time.minute <= 59);
assert!(current_time.second <= 59);
}
#[test]
fn test_strftime() {
let datetime = DateTime::new(2023, 8, 3, 5, 20, 59, TimeZone::UTC).unwrap();
let formatted = datetime.strftime("%Y-%m-%d %H:%M:%S");
assert_eq!(formatted, "2023-08-03 05:20:59");
}
#[test]
fn test_unix_seconds_conversion() {
let datetime = DateTime::new(2023, 1, 1, 0, 0, 0, TimeZone::UTC).unwrap();
let unix_seconds = datetime.to_unix_seconds();
let converted_datetime = DateTime::from_unix_seconds(unix_seconds, TimeZone::UTC).unwrap();
assert_eq!(datetime, converted_datetime);
let datetime_kst = DateTime::new(2023, 1, 1, 9, 0, 0, TimeZone::KST).unwrap();
let unix_seconds_kst = datetime_kst.to_unix_seconds();
let converted_datetime_kst =
DateTime::from_unix_seconds(unix_seconds_kst, TimeZone::KST).unwrap();
assert_eq!(datetime_kst, converted_datetime_kst);
assert_eq!(unix_seconds, unix_seconds_kst);
}
#[test]
fn test_add_timedelta() {
let datetime = DateTime::new(2023, 12, 31, 23, 59, 59, TimeZone::UTC).unwrap();
let delta = TimeDelta {
days: 1,
seconds: 1,
..Default::default()
};
let new_datetime = datetime.add_timedelta(delta).unwrap();
let expected_datetime = DateTime::new(2024, 1, 2, 0, 0, 0, TimeZone::UTC).unwrap();
assert_eq!(new_datetime, expected_datetime);
}
#[test]
fn test_sub_timedelta() {
let datetime = DateTime::new(2024, 1, 1, 0, 0, 0, TimeZone::UTC).unwrap();
let delta = TimeDelta {
days: 1,
..Default::default()
};
let new_datetime = datetime.sub_timedelta(delta).unwrap();
let expected_datetime = DateTime::new(2023, 12, 31, 0, 0, 0, TimeZone::UTC).unwrap();
assert_eq!(new_datetime, expected_datetime);
}
#[test]
fn test_add_operator() {
let datetime = DateTime::new(2023, 1, 1, 0, 0, 0, TimeZone::UTC).unwrap();
let delta = TimeDelta {
days: 30,
..Default::default()
};
let new_datetime = datetime + delta;
let expected_datetime = DateTime::new(2023, 1, 31, 0, 0, 0, TimeZone::UTC).unwrap();
assert_eq!(new_datetime.unwrap(), expected_datetime);
}
#[test]
fn test_sub_operator() {
let datetime = DateTime::new(2023, 1, 31, 0, 0, 0, TimeZone::UTC).unwrap();
let delta = TimeDelta {
days: 30,
..Default::default()
};
let new_datetime = datetime - delta;
let expected_datetime = DateTime::new(2023, 1, 1, 0, 0, 0, TimeZone::UTC).unwrap();
assert_eq!(new_datetime.unwrap(), expected_datetime);
}
#[test]
fn test_edge_case_transitions() {
let datetime = DateTime::new(2024, 2, 28, 23, 59, 59, TimeZone::UTC).unwrap();
let delta = TimeDelta {
seconds: 1,
..Default::default()
};
let new_datetime = datetime.add_timedelta(delta).unwrap();
let expected_datetime = DateTime::new(2024, 2, 29, 0, 0, 0, TimeZone::UTC).unwrap();
assert_eq!(new_datetime, expected_datetime);
let datetime = DateTime::new(2023, 2, 28, 23, 59, 59, TimeZone::UTC).unwrap();
let new_datetime = datetime.add_timedelta(delta).unwrap();
let expected_datetime = DateTime::new(2023, 3, 1, 0, 0, 0, TimeZone::UTC).unwrap();
assert_eq!(new_datetime, expected_datetime);
let datetime = DateTime::new(2023, 12, 31, 23, 59, 59, TimeZone::UTC).unwrap();
let new_datetime = datetime.add_timedelta(delta).unwrap();
let expected_datetime = DateTime::new(2024, 1, 1, 0, 0, 0, TimeZone::UTC).unwrap();
assert_eq!(new_datetime, expected_datetime);
}
#[test]
fn test_timezone_offsets() {
let datetime_utc = DateTime::new(2023, 8, 1, 12, 0, 0, TimeZone::UTC).unwrap();
let datetime_kst = DateTime::new(2023, 8, 1, 21, 0, 0, TimeZone::KST).unwrap();
assert_eq!(
datetime_utc.to_unix_seconds(),
datetime_kst.to_unix_seconds()
);
let datetime_est = DateTime::new(2023, 8, 1, 7, 0, 0, TimeZone::EST).unwrap();
assert_eq!(
datetime_utc.to_unix_seconds(),
datetime_est.to_unix_seconds()
);
}
#[test]
fn test_timedelta_display() {
let delta = TimeDelta {
weeks: 1,
days: 2,
hours: 3,
minutes: 4,
seconds: 5,
};
let delta_str = format!("{}", delta);
assert_eq!(delta_str, "1 week, 2 days, 3 hours, 4 minutes, 5 seconds");
let delta = TimeDelta {
weeks: 0,
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
};
let delta_str = format!("{}", delta);
assert_eq!(delta_str, "0 seconds");
}
#[test]
fn test_timedelta_default() {
let delta = TimeDelta::default();
assert_eq!(delta.weeks, 0);
assert_eq!(delta.days, 0);
assert_eq!(delta.hours, 0);
assert_eq!(delta.minutes, 0);
assert_eq!(delta.seconds, 0);
}
#[test]
fn test_subtract_past_epoch() {
let datetime = DateTime::new(1970, 1, 1, 0, 0, 0, TimeZone::UTC).unwrap();
let delta = TimeDelta {
days: 1,
..Default::default()
};
let result = datetime.sub_timedelta(delta);
assert!(result.is_err());
assert_eq!(
result.unwrap_err(),
"Resulting DateTime is before Unix epoch (1970-01-01 00:00:00 UTC)"
);
}
#[test]
fn test_add_negative_timedelta() {
let datetime = DateTime::new(2023, 1, 2, 0, 0, 0, TimeZone::UTC).unwrap();
let delta = TimeDelta {
days: -1,
..Default::default()
};
let new_datetime = datetime.add_timedelta(delta).unwrap();
let expected_datetime = DateTime::new(2023, 1, 1, 0, 0, 0, TimeZone::UTC).unwrap();
assert_eq!(new_datetime, expected_datetime);
}
#[test]
fn test_timezone_offset_in_seconds() {
assert_eq!(TimeZone::UTC.offset_in_seconds(), 0);
assert_eq!(TimeZone::KST.offset_in_seconds(), 9 * 3600);
assert_eq!(TimeZone::EST.offset_in_seconds(), -5 * 3600);
assert_eq!(TimeZone::IST.offset_in_seconds(), 5 * 3600 + 1800); }
#[test]
fn test_compute_total_seconds() {
let total_seconds = compute_total_seconds(1, 1, 1, 1, 1);
let expected_seconds = SECONDS_IN_WEEK as i64
+ SECONDS_IN_DAY as i64
+ SECONDS_IN_HOUR as i64
+ SECONDS_IN_MINUTE as i64
+ 1;
assert_eq!(total_seconds, expected_seconds);
}
#[test]
fn test_adjust_second_with_timezone() {
let total_seconds = 1000;
let adjusted_seconds = adjust_second_with_timezone(total_seconds, TimeZone::KST);
assert_eq!(adjusted_seconds, total_seconds + (9 * 3600) as u64);
}
#[test]
fn test_calculate_date_since_epoch() {
let adjusted_seconds = 0;
let datetime = calculate_date_since_epoch(adjusted_seconds, TimeZone::UTC).unwrap();
let expected_datetime = DateTime::new(1970, 1, 1, 0, 0, 0, TimeZone::UTC).unwrap();
assert_eq!(datetime, expected_datetime);
}
#[test]
fn test_timezone_offsets_correctness() {
assert_eq!(TimeZone::UTC.offset_in_seconds(), 0);
assert_eq!(TimeZone::KST.offset_in_seconds(), 32400);
assert_eq!(TimeZone::EST.offset_in_seconds(), -18000);
assert_eq!(TimeZone::PST.offset_in_seconds(), -28800);
assert_eq!(TimeZone::IST.offset_in_seconds(), 19800);
}
#[test]
fn test_from_unix_seconds_debug() {
let unix_seconds = 1690891200; let datetime_utc = DateTime::from_unix_seconds(unix_seconds, TimeZone::UTC).unwrap();
let datetime_kst = DateTime::from_unix_seconds(unix_seconds, TimeZone::KST).unwrap();
println!("UTC DateTime: {:?}", datetime_utc);
println!("KST DateTime: {:?}", datetime_kst);
assert_eq!(datetime_utc.to_unix_seconds(), unix_seconds);
assert_eq!(datetime_kst.to_unix_seconds(), unix_seconds);
}
#[test]
fn test_all_timezone_offsets() {
let unix_seconds = 1690891200;
let timezones = vec![
TimeZone::UTC,
TimeZone::KST,
TimeZone::EST,
TimeZone::PST,
TimeZone::JST,
TimeZone::IST,
TimeZone::CET,
TimeZone::AST,
TimeZone::CST,
TimeZone::MST,
TimeZone::AKST,
TimeZone::HST,
TimeZone::BST,
TimeZone::WET,
TimeZone::EET,
TimeZone::SAST,
TimeZone::EAT,
TimeZone::AEST,
TimeZone::ACST,
TimeZone::AWST,
TimeZone::CSTAsia,
TimeZone::SGT,
TimeZone::HKT,
];
for timezone in &timezones {
let datetime = DateTime::from_unix_seconds(unix_seconds, *timezone).unwrap();
let recalculated_unix = datetime.to_unix_seconds();
println!(
"Timezone: {:?}, DateTime: {:?}, Recalculated Unix: {}, Expected Unix: {}",
timezone, datetime, recalculated_unix, unix_seconds
);
assert_eq!(
recalculated_unix, unix_seconds,
"Timezone {:?} failed",
timezone
);
}
}
#[test]
fn test_datetime_new_correctness_debug() {
let datetime_utc = DateTime::new(2023, 8, 1, 12, 0, 0, TimeZone::UTC).unwrap();
let datetime_kst = DateTime::new(2023, 8, 1, 21, 0, 0, TimeZone::KST).unwrap();
let datetime_est = DateTime::new(2023, 8, 1, 7, 0, 0, TimeZone::EST).unwrap();
println!("UTC: {:?}", datetime_utc);
println!("KST: {:?}", datetime_kst);
println!("EST: {:?}", datetime_est);
println!(
"UTC to Unix Seconds: {}, KST to Unix Seconds: {}, EST to Unix Seconds: {}",
datetime_utc.to_unix_seconds(),
datetime_kst.to_unix_seconds(),
datetime_est.to_unix_seconds()
);
assert_eq!(datetime_utc.to_unix_seconds(), 1690891200);
assert_eq!(datetime_kst.to_unix_seconds(), 1690891200);
assert_eq!(datetime_est.to_unix_seconds(), 1690891200);
}
}