Refactor date serde

This commit is contained in:
Dominik Werder
2023-06-19 15:18:30 +02:00
parent 0daa66a800
commit 1b3267c1a1
13 changed files with 236 additions and 79 deletions
+113 -11
View File
@@ -47,6 +47,10 @@ pub const CONNECTION_STATUS_DIV: u64 = timeunits::DAY;
pub const TS_MSP_GRID_UNIT: u64 = timeunits::SEC * 10;
pub const TS_MSP_GRID_SPACING: u64 = 6 * 2;
pub const DATETIME_FMT_3MS: &str = "%Y-%m-%dT%H:%M:%S.%3fZ";
pub const DATETIME_FMT_6MS: &str = "%Y-%m-%dT%H:%M:%S.%6fZ";
pub const DATETIME_FMT_9MS: &str = "%Y-%m-%dT%H:%M:%S.%9fZ";
const TEST_BACKEND: &str = "testbackend-00";
pub fn is_false<T>(x: T) -> bool
@@ -439,6 +443,7 @@ mod serde_port {
where
D: serde::Deserializer<'de>,
{
// We expect to use json or yaml only.
de.deserialize_any(Vis)
}
@@ -1157,7 +1162,64 @@ where
pub ix: [T; 2],
}
#[derive(Clone, Deserialize, PartialEq, PartialOrd)]
#[derive(Clone, PartialEq, PartialOrd)]
pub struct DtNano(u64);
impl DtNano {
pub fn from_ns(ns: u64) -> Self {
Self(ns)
}
pub fn ns(&self) -> u64 {
self.0
}
}
mod dt_nano_serde {
use super::DtNano;
use de::Visitor;
use serde::de;
use serde::Deserialize;
use serde::Serialize;
use std::fmt;
impl Serialize for DtNano {
fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
ser.serialize_u64(self.ns())
}
}
struct Vis1;
impl<'de> Visitor<'de> for Vis1 {
type Value = DtNano;
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "an integer of nanoseconds")
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(DtNano::from_ns(v))
}
}
impl<'de> Deserialize<'de> for DtNano {
fn deserialize<D>(de: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
de.deserialize_u64(Vis1)
}
}
}
#[derive(Clone, PartialEq, PartialOrd)]
pub struct TsNano(pub u64);
mod ts_nano_ser {
@@ -1165,23 +1227,54 @@ mod ts_nano_ser {
use crate::timeunits::SEC;
use chrono::TimeZone;
use chrono::Utc;
use de::Visitor;
use serde::de;
use serde::Deserialize;
use serde::Serialize;
use std::fmt;
impl Serialize for TsNano {
fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let ts = Utc.timestamp_opt((self.0 / SEC) as i64, (self.0 % SEC) as u32);
let value = format!("{}", ts.earliest().unwrap());
ser.serialize_newtype_struct("TsNano", &value)
if false {
let ts = Utc.timestamp_opt((self.0 / SEC) as i64, (self.0 % SEC) as u32);
let value = format!("{}", ts.earliest().unwrap());
ser.serialize_newtype_struct("TsNano", &value)
} else {
ser.serialize_u64(self.ns())
}
}
}
struct Vis1;
impl<'de> Visitor<'de> for Vis1 {
type Value = TsNano;
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "integer nanoseconds since unix epoch")
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(TsNano::from_ns(v))
}
}
impl<'de> Deserialize<'de> for TsNano {
fn deserialize<D>(de: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
de.deserialize_u64(Vis1)
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd)]
pub struct PulseId(u64);
impl TsNano {
pub fn from_ns(ns: u64) -> Self {
Self(ns)
@@ -1204,11 +1297,17 @@ impl fmt::Debug for TsNano {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let ts = Utc.timestamp_opt((self.0 / SEC) as i64, (self.0 % SEC) as u32);
f.debug_struct("TsNano")
.field("ts", &ts.earliest().unwrap_or(Default::default()))
.field(
"ts",
&ts.earliest().unwrap_or(Default::default()).format(DATETIME_FMT_3MS),
)
.finish()
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd)]
pub struct PulseId(u64);
impl PulseId {
pub fn from_id(id: u64) -> Self {
Self(id)
@@ -2389,16 +2488,19 @@ impl FromUrl for ChannelConfigQuery {
impl AppendToUrl for ChannelConfigQuery {
fn append_to_url(&self, url: &mut Url) {
let date_fmt = "%Y-%m-%dT%H:%M:%S.%3fZ";
self.channel.append_to_url(url);
let mut g = url.query_pairs_mut();
g.append_pair(
"begDate",
&Utc.timestamp_nanos(self.range.beg as i64).format(date_fmt).to_string(),
&Utc.timestamp_nanos(self.range.beg as i64)
.format(DATETIME_FMT_3MS)
.to_string(),
);
g.append_pair(
"endDate",
&Utc.timestamp_nanos(self.range.end as i64).format(date_fmt).to_string(),
&Utc.timestamp_nanos(self.range.end as i64)
.format(DATETIME_FMT_3MS)
.to_string(),
);
if self.expand {
g.append_pair("expand", "true");
+8 -4
View File
@@ -16,6 +16,7 @@ use crate::PulseRange;
use crate::SeriesRange;
use crate::SfDbChannel;
use crate::ToNanos;
use crate::DATETIME_FMT_6MS;
use chrono::DateTime;
use chrono::TimeZone;
use chrono::Utc;
@@ -118,7 +119,7 @@ impl FromUrl for TimeRangeQuery {
impl AppendToUrl for TimeRangeQuery {
fn append_to_url(&self, url: &mut Url) {
let date_fmt = "%Y-%m-%dT%H:%M:%S.%6fZ";
let date_fmt = DATETIME_FMT_6MS;
let mut g = url.query_pairs_mut();
g.append_pair(
"begDate",
@@ -314,16 +315,19 @@ impl FromUrl for ChannelStateEventsQuery {
impl AppendToUrl for ChannelStateEventsQuery {
fn append_to_url(&self, url: &mut Url) {
let date_fmt = "%Y-%m-%dT%H:%M:%S.%6fZ";
self.channel.append_to_url(url);
let mut g = url.query_pairs_mut();
g.append_pair(
"begDate",
&Utc.timestamp_nanos(self.range.beg as i64).format(date_fmt).to_string(),
&Utc.timestamp_nanos(self.range.beg as i64)
.format(DATETIME_FMT_6MS)
.to_string(),
);
g.append_pair(
"endDate",
&Utc.timestamp_nanos(self.range.end as i64).format(date_fmt).to_string(),
&Utc.timestamp_nanos(self.range.end as i64)
.format(DATETIME_FMT_6MS)
.to_string(),
);
}
}
+52 -4
View File
@@ -1,14 +1,16 @@
use chrono::{DateTime, FixedOffset};
use chrono::DateTime;
use chrono::FixedOffset;
use err::Error;
use serde::{de::Visitor, Deserialize, Serialize};
use serde::de::Visitor;
use serde::Deserialize;
use serde::Serialize;
use std::fmt;
use std::ops;
use std::time::Duration;
#[derive(Clone, Debug, PartialEq)]
pub struct Datetime(DateTime<FixedOffset>);
impl Datetime {}
impl From<DateTime<FixedOffset>> for Datetime {
fn from(x: DateTime<FixedOffset>) -> Self {
Datetime(x)
@@ -84,3 +86,49 @@ impl<'de> Deserialize<'de> for Datetime {
deserializer.deserialize_str(Vis1)
}
}
#[test]
fn ser_00() {
use chrono::TimeZone;
let x = FixedOffset::east_opt(0)
.unwrap()
.with_ymd_and_hms(2023, 2, 3, 15, 12, 40)
.earliest()
.unwrap();
let x = Datetime(x);
let s = serde_json::to_string(&x).unwrap();
assert_eq!(s, r#""2023-02-03T15:12:40Z""#);
}
#[test]
fn ser_01() {
use chrono::TimeZone;
let x = FixedOffset::east_opt(0)
.unwrap()
.with_ymd_and_hms(2023, 2, 3, 15, 12, 40)
.earliest()
.unwrap()
.checked_add_signed(chrono::Duration::milliseconds(876))
.unwrap();
let x = Datetime(x);
let s = serde_json::to_string(&x).unwrap();
assert_eq!(s, r#""2023-02-03T15:12:40.876Z""#);
}
#[test]
fn ser_02() {
use chrono::TimeZone;
let x = FixedOffset::east_opt(0)
.unwrap()
.with_ymd_and_hms(2023, 2, 3, 15, 12, 40)
.earliest()
.unwrap()
.checked_add_signed(chrono::Duration::nanoseconds(543432120))
.unwrap();
let x = Datetime(x);
let s = serde_json::to_string(&x).unwrap();
assert_eq!(s, r#""2023-02-03T15:12:40.543432Z""#);
}