pub fn validate_instant(year: i32, month: u32, day: u32, hour: u32, minute: u32, tz: f64) -> Result<(), String> {
if !(1900..=2100).contains(&year) {
return Err("year 仅支持 1900–2100".into());
}
if !(1..=12).contains(&month) {
return Err("month 须 1–12".into());
}
let last = days_in_month(year, month);
if !(1..=last).contains(&day) {
return Err(format!("{year} 年 {month} 月只有 {last} 天"));
}
if hour > 23 || minute > 59 {
return Err("hour/minute 越界".into());
}
if !(-12.0..=14.0).contains(&tz) {
return Err("tz 须在 −12 到 +14 之间".into());
}
Ok(())
}
pub fn validate_query(q: &crate::Query) -> Result<(), String> {
validate_instant(q.year, q.month, q.day, q.hour, q.minute, q.tz)?;
validate_coords(q.latitude, q.longitude)
}
#[must_use]
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 % 4 == 0 && (year % 100 != 0 || year % 400 == 0) => 29,
2 => 28,
_ => 0,
}
}
pub fn validate_coords(latitude: Option<f64>, longitude: Option<f64>) -> Result<(), String> {
if let Some(lat) = latitude
&& !(-90.0..=90.0).contains(&lat)
{
return Err("latitude 须在 −90 到 90 之间".into());
}
if let Some(lon) = longitude
&& !(-180.0..=180.0).contains(&lon)
{
return Err("longitude 须在 −180 到 180 之间".into());
}
Ok(())
}