use chrono::{Datelike, NaiveDate, Weekday};
use whatwg_infra::collect_codepoints;
#[inline]
pub(crate) fn is_valid_month(month: &u32) -> bool {
(1..=12).contains(month)
}
#[inline]
pub(crate) fn is_valid_hour(hour: &u32) -> bool {
(0..=23).contains(hour)
}
#[inline]
pub(crate) fn is_valid_min_or_sec(val: &u32) -> bool {
(0..60).contains(val)
}
#[inline]
pub(crate) fn collect_ascii_digits(s: &str, position: &mut usize) -> String {
collect_codepoints(s, position, |c| c.is_ascii_digit())
}
pub const fn max_days_in_month_year(month: u32, year: u32) -> Option<u32> {
match month {
1 | 3 | 5 | 7 | 8 | 10 | 12 => Some(31),
4 | 6 | 9 | 11 => Some(30),
2 => {
if year % 400 == 0 || (year % 4 == 0 && year % 100 != 0) {
Some(29)
} else {
Some(28)
}
}
_ => None,
}
}
pub fn week_number_of_year(year: i32) -> Option<u32> {
let naive_date = NaiveDate::from_ymd_opt(year, 1u32, 1u32).unwrap();
let weekday = naive_date.weekday();
match weekday {
Weekday::Thu => Some(53u32),
Weekday::Wed => {
if year % 400 == 0 || (year % 4 == 0 && year % 100 != 0) {
Some(53u32)
} else {
Some(52u32)
}
}
_ => Some(52u32),
}
}
#[cfg(test)]
mod tests {
use super::{max_days_in_month_year, week_number_of_year};
#[test]
fn test_max_days_in_month_28_days() {
assert_eq!(max_days_in_month_year(2, 2021), Some(28));
assert_eq!(max_days_in_month_year(2, 2022), Some(28));
assert_eq!(max_days_in_month_year(2, 2023), Some(28));
}
#[test]
fn test_max_days_in_month_29_days() {
assert_eq!(max_days_in_month_year(2, 2020), Some(29));
assert_eq!(max_days_in_month_year(2, 2024), Some(29));
assert_eq!(max_days_in_month_year(2, 2028), Some(29));
assert_eq!(max_days_in_month_year(2, 2400), Some(29));
}
#[test]
fn test_max_days_in_month_30_days() {
assert_eq!(max_days_in_month_year(4, 2021), Some(30));
assert_eq!(max_days_in_month_year(6, 2021), Some(30));
assert_eq!(max_days_in_month_year(9, 2021), Some(30));
assert_eq!(max_days_in_month_year(11, 2021), Some(30));
}
#[test]
fn test_max_days_in_month_31_days() {
assert_eq!(max_days_in_month_year(1, 2021), Some(31));
assert_eq!(max_days_in_month_year(3, 2019), Some(31));
assert_eq!(max_days_in_month_year(5, 2000), Some(31));
assert_eq!(max_days_in_month_year(7, 3097), Some(31));
assert_eq!(max_days_in_month_year(8, 1985), Some(31));
assert_eq!(max_days_in_month_year(10, 1426), Some(31));
assert_eq!(max_days_in_month_year(12, 1953), Some(31));
}
#[test]
fn test_max_days_in_month_nothing() {
assert_eq!(max_days_in_month_year(13, 2022), None);
}
#[test]
fn test_week_number_of_year_is_52() {
assert_eq!(week_number_of_year(2012), Some(52));
assert_eq!(week_number_of_year(2017), Some(52));
assert_eq!(week_number_of_year(2018), Some(52));
assert_eq!(week_number_of_year(2019), Some(52));
assert_eq!(week_number_of_year(2021), Some(52));
assert_eq!(week_number_of_year(2022), Some(52));
assert_eq!(week_number_of_year(2023), Some(52));
}
#[test]
fn test_week_number_of_year_is_53() {
assert_eq!(week_number_of_year(1801), Some(53));
assert_eq!(week_number_of_year(2004), Some(53));
assert_eq!(week_number_of_year(2009), Some(53));
assert_eq!(week_number_of_year(2015), Some(53));
assert_eq!(week_number_of_year(2020), Some(53));
}
#[test]
fn test_week_number_of_year_starts_on_wednesday_and_not_leap_year_is_52() {
assert_eq!(week_number_of_year(2014), Some(52));
assert_eq!(week_number_of_year(2025), Some(52));
}
}