iota_graphql_rpc/types/
date_time.rs1use std::str::FromStr;
6
7use async_graphql::*;
8use chrono::{
9 ParseError as ChronoParseError,
10 prelude::{DateTime as ChronoDateTime, TimeZone, Utc as ChronoUtc},
11};
12
13use crate::error::Error;
14
15#[derive(Clone, Debug, Eq, PartialEq)]
18pub(crate) struct DateTime(ChronoDateTime<ChronoUtc>);
19
20impl DateTime {
21 pub fn from_ms(timestamp_ms: i64) -> Result<Self, Error> {
22 ChronoUtc
23 .timestamp_millis_opt(timestamp_ms)
24 .single()
25 .ok_or_else(|| Error::Internal("Cannot convert timestamp into DateTime".to_string()))
26 .map(Self)
27 }
28}
29
30#[Scalar(use_type_description = true)]
33impl ScalarType for DateTime {
34 fn parse(value: Value) -> InputValueResult<Self> {
35 match value {
36 Value::String(s) => DateTime::from_str(&s)
37 .map_err(|e| InputValueError::custom(format!("Error parsing DateTime: {}", e))),
38 _ => Err(InputValueError::expected_type(value)),
39 }
40 }
41
42 fn to_value(&self) -> Value {
43 Value::String(format!("{:?}", self.0))
45 }
46}
47
48impl Description for DateTime {
49 fn description() -> &'static str {
50 "ISO-8601 Date and Time: RFC3339 in UTC with format: YYYY-MM-DDTHH:MM:SS.mmmZ. Note that the milliseconds part is optional, and it may be omitted if its value is 0."
51 }
52}
53
54impl FromStr for DateTime {
55 type Err = ChronoParseError;
56
57 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
58 Ok(DateTime(s.parse::<ChronoDateTime<ChronoUtc>>()?))
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn test_parse() {
68 let dt: &str = "2023-08-19T15:37:24.761850Z";
69 let date_time = DateTime::from_str(dt).unwrap();
70 let Value::String(s) = async_graphql::ScalarType::to_value(&date_time) else {
71 panic!("Invalid date time scalar");
72 };
73 assert_eq!(dt, s);
74
75 let dt: &str = "2023-08-19T15:37:24.700Z";
76 let date_time = DateTime::from_str(dt).unwrap();
77 let Value::String(s) = async_graphql::ScalarType::to_value(&date_time) else {
78 panic!("Invalid date time scalar");
79 };
80 assert_eq!(dt, s);
81
82 let dt: &str = "2023-08-";
83 assert!(DateTime::from_str(dt).is_err());
84 }
85}