use crate::field_types::{Date, Time};
use crate::{Buffer, FieldType};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Timestamp {
date: Date,
time: Time,
}
impl Timestamp {
pub fn new(date: Date, time: Time) -> Self {
Self { date, time }
}
pub fn parse(data: &[u8]) -> Option<Self> {
if data.len() < 12 || data[8] != b'-' {
return None;
}
let date = Date::deserialize(&data[0..8]).ok()?;
let time = Time::deserialize(&data[9..]).ok()?;
Some(Self::new(date, time))
}
pub fn utc_now() -> Self {
use chrono::{Datelike, Timelike};
let utc: chrono::DateTime<chrono::Utc> = chrono::Utc::now();
let date = Date::new(utc.year() as u32, utc.month(), utc.day());
let time = Time::from_hmsm(
utc.hour(),
utc.minute(),
utc.second(),
utc.nanosecond() / 1_000_000,
)
.unwrap();
Self::new(date.unwrap(), time)
}
pub fn date(&self) -> Date {
self.date
}
pub fn time(&self) -> Time {
self.time
}
#[cfg(feature = "utils-chrono")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "utils-chrono")))]
pub fn to_chrono_utc(&self) -> Option<chrono::DateTime<chrono::Utc>> {
let naive = self.to_chrono_naive()?;
Some(chrono::DateTime::from_utc(naive, chrono::Utc))
}
#[cfg(feature = "utils-chrono")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "utils-chrono")))]
pub fn to_chrono_naive(&self) -> Option<chrono::NaiveDateTime> {
let date = self.date().to_chrono_naive()?;
let time = self.time().to_chrono_naive()?;
Some(chrono::NaiveDateTime::new(date, time))
}
}
impl<'a> FieldType<'a> for Timestamp {
type Error = &'static str;
type SerializeSettings = ();
fn serialize_with<B>(&self, buffer: &mut B, _settings: ()) -> usize
where
B: Buffer,
{
self.date().serialize(buffer) + b"-".serialize(buffer) + self.time().serialize(buffer)
}
fn deserialize(data: &'a [u8]) -> Result<Self, Self::Error> {
Self::parse(data).ok_or("Invalid timestamp format")
}
}
#[cfg(test)]
mod test {
use super::*;
use quickcheck::{Arbitrary, Gen};
use quickcheck_macros::quickcheck;
impl Arbitrary for Timestamp {
fn arbitrary(g: &mut Gen) -> Self {
let date = Date::arbitrary(g).to_string();
let time = Time::arbitrary(g).to_string();
let s = format!("{}-{}", date, time);
Self::deserialize(s.as_bytes()).unwrap()
}
}
#[quickcheck]
fn verify_serialization_behavior(timestamp: Timestamp) -> bool {
crate::field_types::test_utility_verify_serialization_behavior(timestamp)
}
}