use alloc::{format, string::String};
pub fn days_from_civil(year: i32, month: u32, day: u32) -> i64 {
let year = year - i32::from(month <= 2);
let era = if year >= 0 { year } else { year - 399 } / 400;
let year_of_era = (year - era * 400) as i64;
let month = month as i64;
let day_of_year = (153 * (month + if month > 2 { -3 } else { 9 }) + 2) / 5 + day as i64 - 1;
let day_of_era = year_of_era * 365 + year_of_era / 4 - year_of_era / 100 + day_of_year;
era as i64 * 146_097 + day_of_era - 719_468
}
pub fn civil_from_days(days: i64) -> (i32, u32, u32) {
let days = days + 719_468;
let era = if days >= 0 { days } else { days - 146_096 } / 146_097;
let day_of_era = days - era * 146_097;
let year_of_era =
(day_of_era - day_of_era / 1460 + day_of_era / 36_524 - day_of_era / 146_096) / 365;
let year = year_of_era + era * 400;
let day_of_year = day_of_era - (365 * year_of_era + year_of_era / 4 - year_of_era / 100);
let month_prime = (5 * day_of_year + 2) / 153;
let day = (day_of_year - (153 * month_prime + 2) / 5 + 1) as u32;
let month = (month_prime + if month_prime < 10 { 3 } else { -9 }) as u32;
(year as i32 + i32::from(month <= 2), month, day)
}
pub fn unix(year: i32, month: u32, day: u32, hour: u32, minute: u32, second: u32) -> i64 {
days_from_civil(year, month, day) * 86_400
+ hour as i64 * 3_600
+ minute as i64 * 60
+ second as i64
}
pub fn rfc3339(timestamp: i64) -> String {
let days = timestamp.div_euclid(86_400);
let seconds = timestamp.rem_euclid(86_400);
let (year, month, day) = civil_from_days(days);
format!(
"{year:04}-{month:02}-{day:02}T{:02}:{:02}:{:02}Z",
seconds / 3_600,
seconds % 3_600 / 60,
seconds % 60,
)
}
pub fn weekday(days: i64) -> u32 {
(days + 4).rem_euclid(7) as u32
}
pub fn days_in_month(year: i32, month: u32) -> u32 {
match month {
1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
4 | 6 | 9 | 11 => 30,
2 if year.rem_euclid(4) == 0
&& (year.rem_euclid(100) != 0 || year.rem_euclid(400) == 0) =>
{
29
}
2 => 28,
_ => 0,
}
}
pub fn digits(bytes: &[u8], at: usize, n: usize) -> Option<u32> {
let slice = bytes.get(at..at + n)?;
if !slice.iter().all(u8::is_ascii_digit) {
return None;
}
let mut value = 0;
for byte in slice {
value = value * 10 + u32::from(byte - b'0');
}
Some(value)
}