astrolabe 0.5.4

Date and time library for Rust. Aims to be feature rich, lightweight and easy-to-use.
Documentation
use std::{mem, time::Duration};

use crate::{util::constants::BUG_MSG, DateTime, TimeUtilities};
use sqlx::{
    encode::IsNull,
    error::BoxDynError,
    postgres::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef},
    Decode, Encode, Postgres, Type,
};

impl Type<Postgres> for DateTime {
    fn type_info() -> PgTypeInfo {
        PgTypeInfo::with_name("timestamp")
    }
}

impl PgHasArrayType for DateTime {
    fn array_type_info() -> PgTypeInfo {
        PgTypeInfo::with_name("timestamp[]")
    }
}

impl Encode<'_, Postgres> for DateTime {
    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
        let us: i64 = self
            .clear_until_nano()
            .micros_since(&postgres_epoch_datetime())
            .try_into()
            .expect(BUG_MSG);

        Encode::<Postgres>::encode(us, buf)
    }

    fn size_hint(&self) -> usize {
        mem::size_of::<i64>()
    }
}

impl Decode<'_, Postgres> for DateTime {
    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
        let us: i64 = Decode::<Postgres>::decode(value)?;

        let datetime = if us >= 0 {
            postgres_epoch_datetime() + Duration::from_micros(us.unsigned_abs())
        } else {
            postgres_epoch_datetime() - Duration::from_micros(us.unsigned_abs())
        };

        Ok(datetime)
    }
}

fn postgres_epoch_datetime() -> DateTime {
    DateTime::from_ymd(2000, 1, 1).expect(BUG_MSG)
}