use crate::Error;
use crate::date::Date;
use crate::types::time::Time;
use rbs::Value;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::cmp;
use std::fmt::{Debug, Display, Formatter};
use std::ops::{Add, Sub};
use std::str::FromStr;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct DateTime(pub fastdate::DateTime);
impl Display for DateTime {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Serialize for DateTime {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_newtype_struct("DateTime", &self.0)
}
}
impl Debug for DateTime {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "DateTime({})", self.0)
}
}
impl<'de> Deserialize<'de> for DateTime {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error;
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
#[serde(rename = "DateTime")]
pub struct DateTimeValue(pub Value);
let v = DateTimeValue::deserialize(deserializer)?;
match v.0 {
Value::I32(u) => Ok(Self(fastdate::DateTime::from_timestamp_millis(u as i64))),
Value::U32(u) => Ok(Self(fastdate::DateTime::from_timestamp_millis(u as i64))),
Value::I64(u) => Ok(Self(fastdate::DateTime::from_timestamp_millis(u))),
Value::U64(u) => Ok(Self(fastdate::DateTime::from_timestamp_millis(u as i64))),
Value::String(s) => Ok({
Self(
fastdate::DateTime::from_str(&s)
.map_err(|e| D::Error::custom(e.to_string()))?,
)
}),
_ => {
return Err(D::Error::custom(&format!(
"unsupported type DateTime({})",
v.0
)));
}
}
}
}
impl DateTime {
pub fn now() -> Self {
Self(fastdate::DateTime::now())
}
pub fn utc() -> Self {
Self(fastdate::DateTime::utc())
}
pub fn set_offset(self, offset_sec: i32) -> DateTime {
Self(self.0.set_offset(offset_sec))
}
pub fn add(self, d: Duration) -> Self {
Self(self.0.add(d))
}
pub fn sub(self, d: Duration) -> Self {
Self(self.0.sub(d))
}
pub fn add_sub_sec(self, sec: i64) -> Self {
Self(self.0.add_sub_sec(sec))
}
pub fn before(&self, other: &DateTime) -> bool {
self.0.before(&other.0)
}
pub fn after(&self, other: &DateTime) -> bool {
self.0.after(&other.0)
}
pub fn unix_timestamp(&self) -> i64 {
self.0.unix_timestamp()
}
pub fn unix_timestamp_micros(&self) -> i64 {
self.0.unix_timestamp_micros()
}
pub fn unix_timestamp_millis(&self) -> i64 {
self.0.unix_timestamp_millis()
}
pub fn unix_timestamp_nano(&self) -> i128 {
self.0.unix_timestamp_nano()
}
pub fn from_timestamp(sec: i64) -> Self {
DateTime(fastdate::DateTime::from_timestamp(sec))
}
pub fn from_timestamp_micros(micros: i64) -> DateTime {
DateTime(fastdate::DateTime::from_timestamp_micros(micros))
}
pub fn from_timestamp_millis(ms: i64) -> Self {
DateTime(fastdate::DateTime::from_timestamp_millis(ms))
}
pub fn from_timestamp_nano(nano: i128) -> Self {
DateTime(fastdate::DateTime::from_timestamp_nano(nano))
}
pub fn format(&self, fmt: &str) -> String {
self.0.format(fmt)
}
pub fn parse(format: &str, arg: &str) -> Result<DateTime, Error> {
Ok(Self(
fastdate::DateTime::parse(format, arg).map_err(|e| Error::from(e.to_string()))?,
))
}
pub fn week_day(&self) -> u8 {
self.0.week_day()
}
pub fn nano(&self) -> u32 {
self.0.nano()
}
pub fn ms(&self) -> u16 {
self.0.ms()
}
pub fn micro(&self) -> u32 {
self.0.micro()
}
pub fn sec(&self) -> u8 {
self.0.sec()
}
pub fn minute(&self) -> u8 {
self.0.minute()
}
pub fn hour(&self) -> u8 {
self.0.hour()
}
pub fn day(&self) -> u8 {
self.0.day()
}
pub fn mon(&self) -> u8 {
self.0.mon()
}
pub fn year(&self) -> i32 {
self.0.year()
}
pub fn offset(&self) -> i32 {
self.0.offset()
}
pub fn from_system_time(s: SystemTime, offset: i32) -> Self {
Self(fastdate::DateTime::from_system_time(s, offset))
}
pub fn display_stand(&self) -> String {
self.0.display_stand()
}
pub fn display(&self, zone: bool) -> String {
self.0.display(zone)
}
pub fn do_display(&self, buf: &mut [u8; 38], add_zone: bool) -> usize {
self.0.do_display(buf, add_zone)
}
pub fn set_nano(self, nano: u32) -> Self {
Self(self.0.set_nano(nano))
}
}
impl Add<Duration> for DateTime {
type Output = DateTime;
fn add(self, rhs: Duration) -> Self::Output {
DateTime(self.0.add(rhs))
}
}
impl Sub<Duration> for DateTime {
type Output = DateTime;
fn sub(self, rhs: Duration) -> Self::Output {
DateTime(self.0.sub(rhs))
}
}
impl Add<&Duration> for DateTime {
type Output = DateTime;
fn add(self, rhs: &Duration) -> Self::Output {
Self(self.0.add(rhs.clone()))
}
}
impl Sub<&Duration> for DateTime {
type Output = DateTime;
fn sub(self, rhs: &Duration) -> Self::Output {
Self(self.0.sub(rhs.clone()))
}
}
impl Sub<DateTime> for DateTime {
type Output = Duration;
fn sub(self, rhs: DateTime) -> Self::Output {
let nano = self.unix_timestamp_nano() - rhs.unix_timestamp_nano();
Duration::from_nanos(nano as u64)
}
}
impl From<SystemTime> for DateTime {
fn from(v: SystemTime) -> DateTime {
DateTime::from_system_time(v, 0)
}
}
impl From<DateTime> for SystemTime {
fn from(v: DateTime) -> SystemTime {
let nano = v.unix_timestamp_nano();
if nano >= 0 {
UNIX_EPOCH + Duration::from_nanos(nano as u64)
} else {
UNIX_EPOCH - Duration::from_nanos(nano as u64)
}
}
}
impl From<Date> for DateTime {
fn from(arg: Date) -> Self {
Self(fastdate::DateTime::from(arg.0))
}
}
impl From<Time> for DateTime {
fn from(arg: Time) -> Self {
Self(fastdate::DateTime::from(arg.0))
}
}
impl From<(Date, Time)> for DateTime {
fn from(arg: (Date, Time)) -> Self {
Self(fastdate::DateTime::from((arg.0.0, arg.1.0)))
}
}
impl From<(Date, Time, i32)> for DateTime {
fn from(arg: (Date, Time, i32)) -> Self {
Self(fastdate::DateTime::from((arg.0.0, arg.1.0, arg.2)))
}
}
impl FromStr for DateTime {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(DateTime(
fastdate::DateTime::from_str(s)
.map_err(|e| crate::error::Error::from(e.to_string()))?,
))
}
}
impl From<DateTime> for Value {
fn from(arg: DateTime) -> Self {
Value::Ext("DateTime", Box::new(Value::String(arg.0.to_string())))
}
}
impl Ord for DateTime {
fn cmp(&self, other: &DateTime) -> cmp::Ordering {
self.0.cmp(&other.0)
}
}
impl PartialOrd for DateTime {
fn partial_cmp(&self, other: &DateTime) -> Option<cmp::Ordering> {
self.0.partial_cmp(&other.0)
}
}
impl From<DateTime> for fastdate::DateTime {
fn from(value: DateTime) -> Self {
value.0
}
}
impl Default for DateTime {
fn default() -> Self {
DateTime(fastdate::DateTime::from_timestamp(0))
}
}
#[cfg(test)]
mod test {
use crate::datetime::DateTime;
use std::str::FromStr;
#[test]
fn test_ser_de() {
let dt = DateTime::now();
let v = serde_json::to_value(&dt).unwrap();
println!("{}", v);
let new_dt: DateTime = serde_json::from_value(v).unwrap();
assert_eq!(new_dt, dt);
}
#[test]
fn test_de() {
let dt = DateTime::from_str("2023-10-21T00:15:00.9233333+08:00").unwrap();
println!("dt={}", dt);
let v = serde_json::to_value(&dt).unwrap();
let new_dt: DateTime = serde_json::from_value(v).unwrap();
assert_eq!(new_dt, dt);
}
#[test]
fn test_de2() {
let dt = vec![DateTime::from_str("2023-10-21T00:15:00.9233333+08:00").unwrap()];
let v = serde_json::to_value(&dt).unwrap();
println!("dt={:?}", dt);
let new_dt: Vec<DateTime> = serde_json::from_value(v).unwrap();
assert_eq!(new_dt, dt);
}
#[test]
fn test_de3() {
let dt = vec![DateTime::from_str("2023-10-21T00:15:00.9233333+08:00").unwrap()];
let v = rbs::value!(&dt);
let new_dt: Vec<DateTime> = rbs::from_value(v).unwrap();
assert_eq!(new_dt, dt);
}
#[test]
fn test_de4() {
let dt = DateTime::from_str("2023-10-21T00:15:00.9233333+08:00").unwrap();
let v = rbs::value!(&dt.unix_timestamp_millis());
let new_dt: DateTime = rbs::from_value(v).unwrap();
assert_eq!(
new_dt,
DateTime::from_str("2023-10-20T16:15:00.923Z").unwrap()
);
}
#[test]
fn test_de5() {
let dt = DateTime::from_str("2023-10-21T00:15:00.9233333+08:00").unwrap();
let v = serde_json::to_value(&dt.unix_timestamp_millis()).unwrap();
let new_dt: DateTime = serde_json::from_value(v).unwrap();
assert_eq!(
new_dt,
DateTime::from_str("2023-10-20T16:15:00.923Z").unwrap()
);
}
#[test]
fn test_default() {
let dt = DateTime::default();
println!("{}", dt);
assert_eq!(dt.to_string(), "1970-01-01T00:00:00Z");
}
#[test]
fn test_format() {
let dt = DateTime::default();
let s = dt.format("YYYY-MM-DD/hh/mm/ss");
println!("{}", s);
assert_eq!(s, "1970-01-01/00/00/00");
}
}