use crate::date::{date_from_days, days_from_epoch, Date};
use crate::duration::TimeDelta;
use crate::time::Time;
use std::fmt;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct DateTime {
pub date: Date,
pub time: Time,
}
impl DateTime {
pub fn new(date: Date, time: Time) -> Self {
DateTime { date, time }
}
pub fn from_ymd_hms(
year: i32,
month: u8,
day: u8,
hour: u8,
minute: u8,
second: u8,
) -> Self {
DateTime {
date: Date::new(year, month, day),
time: Time::from_hms(hour, minute, second),
}
}
pub fn from_ymd_hms_milli(
year: i32,
month: u8,
day: u8,
hour: u8,
minute: u8,
second: u8,
millisecond: u16,
) -> Self {
DateTime {
date: Date::new(year, month, day),
time: Time::new(hour, minute, second, millisecond),
}
}
pub fn date(&self) -> &Date {
&self.date
}
pub fn time(&self) -> &Time {
&self.time
}
pub fn unix_timestamp(&self) -> i64 {
unix_timestamp(*self)
}
pub fn from_unix(secs: i64) -> Self {
from_unix_timestamp(secs)
}
pub fn unix_timestamp_millis(&self) -> i64 {
unix_timestamp(*self) * 1000 + self.time.millisecond as i64
}
pub fn from_unix_millis(ms: i64) -> Self {
let secs = ms / 1000;
let millis = (ms % 1000) as u16;
let mut dt = from_unix_timestamp(secs);
dt.time.millisecond = millis;
dt
}
}
fn unix_epoch_days() -> i64 {
days_from_epoch(Date::new(1970, 1, 1))
}
fn unix_timestamp(dt: DateTime) -> i64 {
let days = days_from_epoch(dt.date) - unix_epoch_days();
days * 86400 + dt.time.total_seconds() as i64
}
fn from_unix_timestamp(secs: i64) -> DateTime {
let days = unix_epoch_days() + secs / 86400;
let remaining_secs = secs % 86400;
let remaining_secs = if remaining_secs < 0 {
86400 + remaining_secs
} else {
remaining_secs
};
let date = date_from_days(days);
let time = Time::new(
(remaining_secs / 3600) as u8 % 24,
((remaining_secs % 3600) / 60) as u8,
(remaining_secs % 60) as u8,
0,
);
DateTime { date, time }
}
impl fmt::Display for DateTime {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{:04}-{:02}-{:02} {:02}:{:02}:{:02}",
self.date.year,
self.date.month,
self.date.day,
self.time.hour,
self.time.minute,
self.time.second
)
}
}
impl std::ops::Add<TimeDelta> for DateTime {
type Output = DateTime;
fn add(self, delta: TimeDelta) -> DateTime {
let total_secs = unix_timestamp(self) + delta.total_seconds() as i64;
from_unix_timestamp(total_secs)
}
}
impl std::ops::Sub<TimeDelta> for DateTime {
type Output = DateTime;
fn sub(self, delta: TimeDelta) -> DateTime {
let total_secs = unix_timestamp(self) - delta.total_seconds() as i64;
from_unix_timestamp(total_secs)
}
}
impl std::ops::Sub<DateTime> for DateTime {
type Output = TimeDelta;
fn sub(self, rhs: DateTime) -> TimeDelta {
let diff = unix_timestamp(self) - unix_timestamp(rhs);
TimeDelta::new(diff, 0)
}
}