use std::convert::TryFrom;
use time::Date;
use crate::{
datetime::DateTime,
error::{Error, Result},
};
pub struct DateTimeBuilder<Y = NoYear, M = NoMonth, D = NoDay> {
pub(crate) year: Y,
pub(crate) month: M,
pub(crate) day: D,
pub(crate) hour: Option<u8>,
pub(crate) minute: Option<u8>,
pub(crate) second: Option<u8>,
pub(crate) millisecond: Option<u16>,
}
impl Default for DateTimeBuilder {
fn default() -> Self {
Self {
year: NoYear,
month: NoMonth,
day: NoDay,
hour: None,
minute: None,
second: None,
millisecond: None,
}
}
}
pub struct Year(i32);
pub struct NoYear;
pub struct Month(u8);
pub struct NoMonth;
pub struct Day(u8);
pub struct NoDay;
impl<M, D> DateTimeBuilder<NoYear, M, D> {
pub fn year(self, y: i32) -> DateTimeBuilder<Year, M, D> {
let Self {
year: _,
month,
day,
hour,
minute,
second,
millisecond,
} = self;
DateTimeBuilder {
year: Year(y),
month,
day,
hour,
minute,
second,
millisecond,
}
}
}
impl<Y, D> DateTimeBuilder<Y, NoMonth, D> {
pub fn month(self, m: u8) -> DateTimeBuilder<Y, Month, D> {
let Self {
year,
month: _,
day,
hour,
minute,
second,
millisecond,
} = self;
DateTimeBuilder {
year,
month: Month(m),
day,
hour,
minute,
second,
millisecond,
}
}
}
impl<Y, M> DateTimeBuilder<Y, M, NoDay> {
pub fn day(self, d: u8) -> DateTimeBuilder<Y, M, Day> {
let Self {
year,
month,
day: _,
hour,
minute,
second,
millisecond,
} = self;
DateTimeBuilder {
year,
month,
day: Day(d),
hour,
minute,
second,
millisecond,
}
}
}
impl<Y, M, D> DateTimeBuilder<Y, M, D> {
pub fn hour(mut self, hour: u8) -> DateTimeBuilder<Y, M, D> {
self.hour = Some(hour);
self
}
pub fn minute(mut self, minute: u8) -> DateTimeBuilder<Y, M, D> {
self.minute = Some(minute);
self
}
pub fn second(mut self, second: u8) -> DateTimeBuilder<Y, M, D> {
self.second = Some(second);
self
}
pub fn millisecond(mut self, millisecond: u16) -> DateTimeBuilder<Y, M, D> {
self.millisecond = Some(millisecond);
self
}
}
impl DateTimeBuilder<Year, Month, Day> {
pub fn build(self) -> Result<DateTime> {
let month = time::Month::try_from(self.month.0).map_err(Error::datetime)?;
let dt = Date::from_calendar_date(self.year.0, month, self.day.0)
.map_err(Error::datetime)?
.with_hms_milli(
self.hour.unwrap_or(0),
self.minute.unwrap_or(0),
self.second.unwrap_or(0),
self.millisecond.unwrap_or(0),
)
.map_err(Error::datetime)?;
Ok(DateTime::from_time_private(dt.assume_utc()))
}
}