use std::{fmt, str::FromStr};
static PARSE_FORMAT: &str = "%FT%T%.f%Z";
static FORMAT: &str = "%FT%T%.f";
pub struct Date(chrono::NaiveDate);
impl Date {
pub fn from_ymd(year: i32, month: u32, day: u32) -> Date {
Date(chrono::NaiveDate::from_ymd(year, month, day))
}
pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> DateTime {
DateTime(self.0.and_hms(hour, min, sec))
}
pub fn and_hms_milli(&self, hour: u32, min: u32, sec: u32, millis: u32) -> DateTime {
DateTime(self.0.and_hms_milli(hour, min, sec, millis))
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize)]
pub struct DateTime(pub chrono::NaiveDateTime);
impl DateTime {
pub fn now() -> Self {
Self(chrono::Utc::now().naive_utc())
}
pub fn utc(&self) -> chrono::DateTime<chrono::Utc> {
chrono::DateTime::from_utc(self.0, chrono::Utc)
}
}
impl From<chrono::DateTime<chrono::Utc>> for DateTime {
fn from(dt: chrono::DateTime<chrono::Utc>) -> Self {
Self(dt.naive_utc())
}
}
impl From<chrono::NaiveDateTime> for DateTime {
fn from(dt: chrono::NaiveDateTime) -> Self {
Self(dt)
}
}
impl From<&chrono::NaiveDateTime> for DateTime {
fn from(dt: &chrono::NaiveDateTime) -> Self {
Self(*dt)
}
}
impl FromStr for DateTime {
type Err = chrono::ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(chrono::NaiveDateTime::parse_from_str(
s,
PARSE_FORMAT,
)?))
}
}
impl fmt::Display for DateTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0.format(FORMAT))
}
}
impl<'de> serde::Deserialize<'de> for DateTime {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
deserializer.deserialize_str(crate::common::FromStrVisitor::expecting(
"a valid OCPI datetime",
))
}
}
#[cfg(test)]
mod tests {
use chrono::{Datelike, Timelike};
use super::*;
#[test]
fn test_display() {
assert_eq!(
"2018-01-01T01:08:01.123",
Date::from_ymd(2018, 1, 1)
.and_hms_milli(1, 8, 1, 123)
.to_string()
);
}
#[test]
fn test_from_str() {
"2015-06-29T20:39:09Z".parse::<DateTime>().expect("Parsing");
"2015-06-29T20:39:09".parse::<DateTime>().expect("Parsing");
"2016-12-29T17:45:09.2Z"
.parse::<DateTime>()
.expect("Parsing");
"2016-12-29T17:45:09.2"
.parse::<DateTime>()
.expect("Parsing");
"2018-01-01T01:08:01.123Z"
.parse::<DateTime>()
.expect("Parsing");
"2018-01-01T01:08:01.123"
.parse::<DateTime>()
.expect("Parsing");
}
#[test]
fn test_deserialize() {
let res =
serde_json::from_str::<DateTime>(r#""2015-06-29T20:39:09Z""#).expect("Deserializing");
assert_eq!(res.0.year(), 2015);
assert_eq!(res.0.month(), 6);
assert_eq!(res.0.day(), 29);
assert_eq!(res.0.hour(), 20);
assert_eq!(res.0.minute(), 39);
assert_eq!(res.0.second(), 9);
let res = serde_json::from_str::<DateTime>(r#""2015-06-29T20:39:09""#).expect("Deser");
assert_eq!(res.0.year(), 2015);
assert_eq!(res.0.month(), 6);
assert_eq!(res.0.day(), 29);
assert_eq!(res.0.hour(), 20);
assert_eq!(res.0.minute(), 39);
assert_eq!(res.0.second(), 9);
let res = serde_json::from_str::<DateTime>(r#""2016-12-29T17:45:09.2Z""#).expect("Deser");
assert_eq!(res.0.year(), 2016);
assert_eq!(res.0.month(), 12);
assert_eq!(res.0.day(), 29);
assert_eq!(res.0.hour(), 17);
assert_eq!(res.0.minute(), 45);
assert_eq!(res.0.second(), 9);
assert_eq!(res.0.nanosecond(), 200000000);
let res = serde_json::from_str::<DateTime>(r#""2016-12-29T17:45:09.2""#).expect("Deser");
assert_eq!(res.0.year(), 2016);
assert_eq!(res.0.month(), 12);
assert_eq!(res.0.day(), 29);
assert_eq!(res.0.hour(), 17);
assert_eq!(res.0.minute(), 45);
assert_eq!(res.0.second(), 9);
assert_eq!(res.0.nanosecond(), 200000000);
let res = serde_json::from_str::<DateTime>(r#""2018-01-01T01:08:01.123Z""#).expect("Deser");
assert_eq!(res.0.year(), 2018);
assert_eq!(res.0.month(), 1);
assert_eq!(res.0.day(), 1);
assert_eq!(res.0.hour(), 1);
assert_eq!(res.0.minute(), 8);
assert_eq!(res.0.second(), 1);
assert_eq!(res.0.nanosecond(), 123000000);
let res = serde_json::from_str::<DateTime>(r#""2018-01-01T01:08:01.123""#).expect("Deser");
assert_eq!(res.0.year(), 2018);
assert_eq!(res.0.month(), 1);
assert_eq!(res.0.day(), 1);
assert_eq!(res.0.hour(), 1);
assert_eq!(res.0.minute(), 8);
assert_eq!(res.0.second(), 1);
assert_eq!(res.0.nanosecond(), 123000000);
}
}