mod cmp;
mod consts;
mod convert;
mod fmt;
use time::Month;
use crate::{Date, Time, error::DateTimeRangeError};
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct DateTime {
date: Date,
time: Time,
}
impl DateTime {
#[must_use]
pub const fn new(date: Date, time: Time) -> Self {
Self { date, time }
}
pub fn from_date_time(date: time::Date, time: time::Time) -> Result<Self, DateTimeRangeError> {
let (date, time) = (date.try_into()?, time.into());
Ok(Self::new(date, time))
}
#[must_use]
pub fn is_valid(self) -> bool {
self.date().is_valid() && self.time().is_valid()
}
#[must_use]
pub const fn date(self) -> Date {
self.date
}
#[must_use]
pub const fn time(self) -> Time {
self.time
}
#[must_use]
pub const fn year(self) -> u16 {
self.date().year()
}
#[must_use]
pub fn month(self) -> Month {
self.date().month()
}
#[must_use]
pub fn day(self) -> u8 {
self.date().day()
}
#[must_use]
pub fn hour(self) -> u8 {
self.time().hour()
}
#[must_use]
pub fn minute(self) -> u8 {
self.time().minute()
}
#[must_use]
pub fn second(self) -> u8 {
self.time().second()
}
}
impl Default for DateTime {
fn default() -> Self {
Self::MIN
}
}
#[cfg(test)]
mod tests {
#[cfg(feature = "std")]
use std::{
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
};
use time::macros::{date, time};
use super::*;
use crate::error::DateTimeRangeErrorKind;
#[test]
fn clone() {
assert_eq!(DateTime::MIN.clone(), DateTime::MIN);
}
#[test]
fn copy() {
let a = DateTime::MIN;
let b = a;
assert_eq!(a, b);
}
#[cfg(feature = "std")]
#[test]
fn hash() {
assert_ne!(
{
let mut hasher = DefaultHasher::new();
DateTime::MIN.hash(&mut hasher);
hasher.finish()
},
{
let mut hasher = DefaultHasher::new();
DateTime::MAX.hash(&mut hasher);
hasher.finish()
}
);
}
#[test]
fn new() {
assert_eq!(DateTime::new(Date::MIN, Time::MIN), DateTime::MIN);
assert_eq!(DateTime::new(Date::MAX, Time::MAX), DateTime::MAX);
}
#[test]
const fn new_is_const_fn() {
const _: DateTime = DateTime::new(Date::MIN, Time::MIN);
}
#[test]
fn from_date_time_before_dos_date_time_epoch() {
assert_eq!(
DateTime::from_date_time(date!(1979-12-31), time!(23:59:58)).unwrap_err(),
DateTimeRangeErrorKind::Negative.into()
);
assert_eq!(
DateTime::from_date_time(date!(1979-12-31), time!(23:59:59)).unwrap_err(),
DateTimeRangeErrorKind::Negative.into()
);
}
#[test]
fn from_date_time() {
assert_eq!(
DateTime::from_date_time(date!(1980-01-01), time::Time::MIDNIGHT).unwrap(),
DateTime::MIN
);
assert_eq!(
DateTime::from_date_time(date!(1980-01-01), time!(00:00:01)).unwrap(),
DateTime::MIN
);
assert_eq!(
DateTime::from_date_time(date!(2002-11-26), time!(19:25:00)).unwrap(),
DateTime::new(
Date::new(0b0010_1101_0111_1010).unwrap(),
Time::new(0b1001_1011_0010_0000).unwrap()
)
);
assert_eq!(
DateTime::from_date_time(date!(2018-11-17), time!(10:38:30)).unwrap(),
DateTime::new(
Date::new(0b0100_1101_0111_0001).unwrap(),
Time::new(0b0101_0100_1100_1111).unwrap()
)
);
assert_eq!(
DateTime::from_date_time(date!(2107-12-31), time!(23:59:58)).unwrap(),
DateTime::MAX
);
assert_eq!(
DateTime::from_date_time(date!(2107-12-31), time!(23:59:59)).unwrap(),
DateTime::MAX
);
}
#[test]
fn from_date_time_with_too_big_date_time() {
assert_eq!(
DateTime::from_date_time(date!(2108-01-01), time::Time::MIDNIGHT).unwrap_err(),
DateTimeRangeErrorKind::Overflow.into()
);
}
#[test]
fn is_valid() {
assert!(DateTime::MIN.is_valid());
assert!(
DateTime::new(
Date::new(0b0010_1101_0111_1010).unwrap(),
Time::new(0b1001_1011_0010_0000).unwrap()
)
.is_valid()
);
assert!(
DateTime::new(
Date::new(0b0100_1101_0111_0001).unwrap(),
Time::new(0b0101_0100_1100_1111).unwrap()
)
.is_valid()
);
assert!(DateTime::MAX.is_valid());
}
#[test]
fn is_valid_with_invalid_date() {
assert!(
!DateTime::new(
unsafe { Date::new_unchecked(0b0000_0000_0010_0000) },
Time::MIN
)
.is_valid()
);
assert!(
!DateTime::new(
unsafe { Date::new_unchecked(0b0000_0000_0101_1110) },
Time::MIN
)
.is_valid()
);
assert!(
!DateTime::new(
unsafe { Date::new_unchecked(0b0000_0000_0000_0001) },
Time::MIN
)
.is_valid()
);
assert!(
!DateTime::new(
unsafe { Date::new_unchecked(0b0000_0001_1010_0001) },
Time::MIN
)
.is_valid()
);
}
#[test]
fn is_valid_with_invalid_time() {
assert!(
!DateTime::new(Date::MIN, unsafe {
Time::new_unchecked(0b0000_0000_0001_1110)
})
.is_valid()
);
assert!(
!DateTime::new(Date::MIN, unsafe {
Time::new_unchecked(0b0000_0111_1000_0000)
})
.is_valid()
);
assert!(
!DateTime::new(Date::MIN, unsafe {
Time::new_unchecked(0b1100_0000_0000_0000)
})
.is_valid()
);
}
#[test]
fn is_valid_with_invalid_date_time() {
assert!(
!DateTime::new(unsafe { Date::new_unchecked(u16::MAX) }, unsafe {
Time::new_unchecked(u16::MAX)
})
.is_valid()
);
}
#[test]
fn date() {
assert_eq!(DateTime::MIN.date(), Date::MIN);
assert_eq!(
DateTime::new(
Date::new(0b0010_1101_0111_1010).unwrap(),
Time::new(0b1001_1011_0010_0000).unwrap()
)
.date(),
Date::new(0b0010_1101_0111_1010).unwrap()
);
assert_eq!(
DateTime::new(
Date::new(0b0100_1101_0111_0001).unwrap(),
Time::new(0b0101_0100_1100_1111).unwrap()
)
.date(),
Date::new(0b0100_1101_0111_0001).unwrap()
);
assert_eq!(DateTime::MAX.date(), Date::MAX);
}
#[test]
const fn date_is_const_fn() {
const _: Date = DateTime::MIN.date();
}
#[test]
fn time() {
assert_eq!(DateTime::MIN.time(), Time::MIN);
assert_eq!(
DateTime::new(
Date::new(0b0010_1101_0111_1010).unwrap(),
Time::new(0b1001_1011_0010_0000).unwrap()
)
.time(),
Time::new(0b1001_1011_0010_0000).unwrap()
);
assert_eq!(
DateTime::new(
Date::new(0b0100_1101_0111_0001).unwrap(),
Time::new(0b0101_0100_1100_1111).unwrap()
)
.time(),
Time::new(0b0101_0100_1100_1111).unwrap()
);
assert_eq!(DateTime::MAX.time(), Time::MAX);
}
#[test]
const fn time_is_const_fn() {
const _: Time = DateTime::MIN.time();
}
#[test]
fn year() {
assert_eq!(DateTime::MIN.year(), 1980);
assert_eq!(
DateTime::new(
Date::new(0b0010_1101_0111_1010).unwrap(),
Time::new(0b1001_1011_0010_0000).unwrap()
)
.year(),
2002
);
assert_eq!(
DateTime::new(
Date::new(0b0100_1101_0111_0001).unwrap(),
Time::new(0b0101_0100_1100_1111).unwrap()
)
.year(),
2018
);
assert_eq!(DateTime::MAX.year(), 2107);
}
#[test]
const fn year_is_const_fn() {
const _: u16 = DateTime::MIN.year();
}
#[test]
fn month() {
assert_eq!(DateTime::MIN.month(), Month::January);
assert_eq!(
DateTime::new(
Date::new(0b0010_1101_0111_1010).unwrap(),
Time::new(0b1001_1011_0010_0000).unwrap()
)
.month(),
Month::November
);
assert_eq!(
DateTime::new(
Date::new(0b0100_1101_0111_0001).unwrap(),
Time::new(0b0101_0100_1100_1111).unwrap()
)
.month(),
Month::November
);
assert_eq!(DateTime::MAX.month(), Month::December);
}
#[test]
fn day() {
assert_eq!(DateTime::MIN.day(), 1);
assert_eq!(
DateTime::new(
Date::new(0b0010_1101_0111_1010).unwrap(),
Time::new(0b1001_1011_0010_0000).unwrap()
)
.day(),
26
);
assert_eq!(
DateTime::new(
Date::new(0b0100_1101_0111_0001).unwrap(),
Time::new(0b0101_0100_1100_1111).unwrap()
)
.day(),
17
);
assert_eq!(DateTime::MAX.day(), 31);
}
#[test]
fn hour() {
assert_eq!(DateTime::MIN.hour(), u8::MIN);
assert_eq!(
DateTime::new(
Date::new(0b0010_1101_0111_1010).unwrap(),
Time::new(0b1001_1011_0010_0000).unwrap()
)
.hour(),
19
);
assert_eq!(
DateTime::new(
Date::new(0b0100_1101_0111_0001).unwrap(),
Time::new(0b0101_0100_1100_1111).unwrap()
)
.hour(),
10
);
assert_eq!(DateTime::MAX.hour(), 23);
}
#[test]
fn minute() {
assert_eq!(DateTime::MIN.minute(), u8::MIN);
assert_eq!(
DateTime::new(
Date::new(0b0010_1101_0111_1010).unwrap(),
Time::new(0b1001_1011_0010_0000).unwrap()
)
.minute(),
25
);
assert_eq!(
DateTime::new(
Date::new(0b0100_1101_0111_0001).unwrap(),
Time::new(0b0101_0100_1100_1111).unwrap()
)
.minute(),
38
);
assert_eq!(DateTime::MAX.minute(), 59);
}
#[test]
fn second() {
assert_eq!(DateTime::MIN.second(), u8::MIN);
assert_eq!(
DateTime::new(
Date::new(0b0010_1101_0111_1010).unwrap(),
Time::new(0b1001_1011_0010_0000).unwrap()
)
.second(),
u8::MIN
);
assert_eq!(
DateTime::new(
Date::new(0b0100_1101_0111_0001).unwrap(),
Time::new(0b0101_0100_1100_1111).unwrap()
)
.second(),
30
);
assert_eq!(DateTime::MAX.second(), 58);
}
#[test]
fn default() {
assert_eq!(DateTime::default(), DateTime::MIN);
}
}