Skip to main content

mlb_api/requests/game/
timestamps.rs

1//! A [`SimplifiedTimestamp`] list for all plays and events in a game.
2
3use std::{fmt::Display, str::FromStr};
4
5use bon::Builder;
6use chrono::{DateTime, NaiveDate, NaiveDateTime, ParseError, Utc};
7use derive_more::{From, Into};
8use serde::Deserialize;
9use serde::de::Error;
10use serde_with::DisplayFromStr;
11
12use crate::game::GameId;
13use crate::request::RequestURL;
14
15pub type GameTimestampsResponse = Vec<SimplifiedTimestamp>;
16
17/// Represents a UTC datetime in a very simple format, ex: `20251231_235959`
18#[derive(Debug, PartialEq, Eq, Clone, From, Into)]
19pub struct SimplifiedTimestamp(DateTime<Utc>);
20
21impl FromStr for SimplifiedTimestamp {
22    type Err = ParseError;
23
24    fn from_str(s: &str) -> Result<Self, Self::Err> {
25        Ok(Self(NaiveDateTime::parse_from_str(s, "%Y%m%d_%H%M%S")?.and_utc()))
26    }
27}
28
29impl Display for SimplifiedTimestamp {
30    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        write!(f, "{}", self.0.format("%Y%d%m_%H%M%S"))
32    }
33}
34
35impl<'de> Deserialize<'de> for SimplifiedTimestamp {
36    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
37    where
38        D: serde::Deserializer<'de>
39    {
40        Self::from_str(&String::deserialize(deserializer)?).map_err(D::Error::custom)
41    }
42}
43
44impl SimplifiedTimestamp {
45    #[must_use]
46    pub fn now() -> Self {
47        Self(Utc::now())
48    }
49}
50
51#[derive(Builder)]
52#[builder(derive(Into))]
53pub struct GameTimestampsRequest {
54    #[builder(into)]
55    id: GameId,
56}
57
58impl Display for GameTimestampsRequest {
59    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60        write!(f, "http://statsapi.mlb.com/api/v1.1/game/{}/feed/live/timestamps", self.id)
61    }
62}
63
64impl RequestURL for GameTimestampsRequest {
65    type Response = GameTimestampsResponse;
66}
67
68impl<S: game_timestamps_request_builder::State + game_timestamps_request_builder::IsComplete> crate::request::RequestURLBuilderExt for GameTimestampsRequestBuilder<S> {
69    type Built = GameTimestampsRequest;
70}
71
72#[cfg(test)]
73mod tests {
74    use crate::game::GameTimestampsRequest;
75    use crate::request::RequestURLBuilderExt;
76
77    #[tokio::test]
78    async fn ws_gm7_2025_timestamps() {
79        let _ =  GameTimestampsRequest::builder().id(813_024).build_and_get().await.unwrap();
80    }
81}
82