use chrono::{DateTime, TimeZone};
use chrono_tz::OffsetComponents;
use rmcp::schemars;
use serde::{Deserialize, Deserializer, Serialize};
use crate::core::utils::{DATETIME_FORMAT, DAY_FORMAT};
fn deserialize_trimmed_string<'de, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Ok(s.trim().to_string())
}
#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct TimeResult {
pub timezone: String,
pub datetime: String,
pub day_of_week: String,
pub is_dst: bool,
}
impl TimeResult {
pub fn from_datetime<Tz>(dt: &DateTime<Tz>, timezone_name: &str) -> TimeResult
where
Tz: TimeZone,
Tz::Offset: OffsetComponents + std::fmt::Display,
{
let is_dst = dt.offset().dst_offset().num_seconds() != 0;
TimeResult {
timezone: timezone_name.to_string(),
datetime: dt.format(DATETIME_FORMAT).to_string(),
day_of_week: dt.format(DAY_FORMAT).to_string(),
is_dst,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct TimeConversionResult {
pub source: TimeResult,
pub target: TimeResult,
pub time_difference: String,
}
#[derive(Debug, Deserialize, schemars::JsonSchema)]
pub struct GetCurrentTimeRequest {
#[serde(deserialize_with = "deserialize_trimmed_string")]
pub timezone: String,
}
#[derive(Debug, Deserialize, schemars::JsonSchema)]
pub struct ConvertTimeRequest {
#[serde(deserialize_with = "deserialize_trimmed_string")]
pub source_timezone: String,
#[serde(deserialize_with = "deserialize_trimmed_string")]
pub time: String,
#[serde(deserialize_with = "deserialize_trimmed_string")]
pub target_timezone: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_time_result_serialization() {
let time_result = TimeResult {
timezone: "UTC".to_string(),
datetime: "2025-01-01T12:00:00+00:00".to_string(),
day_of_week: "Monday".to_string(),
is_dst: false,
};
let json = serde_json::to_string(&time_result).unwrap();
assert!(json.contains("UTC"));
assert!(json.contains("Monday"));
}
#[test]
fn test_timezone_trimming() {
let json = r#"{"timezone": " Africa/Cairo "}"#;
let request: GetCurrentTimeRequest = serde_json::from_str(json).unwrap();
assert_eq!(request.timezone, "Africa/Cairo");
let json = r#"{
"source_timezone": " America/New_York ",
"time": " 14:30 ",
"target_timezone": " Europe/London "
}"#;
let request: ConvertTimeRequest = serde_json::from_str(json).unwrap();
assert_eq!(request.source_timezone, "America/New_York");
assert_eq!(request.time, "14:30");
assert_eq!(request.target_timezone, "Europe/London");
}
}