use core::fmt::{self, Debug, Formatter};
use crate::calendar::Iso;
use crate::{
AsDate, AsMoment, AsTime, Calendar, Date, Moment, Month, Offset, PlainTime, TimeZone, Year,
};
pub struct DateTime<C: Calendar = Iso> {
calendar: C,
moment: Moment,
tz: TimeZone,
}
impl<C: Calendar> DateTime<C> {
pub const fn from_moment(calendar: C, moment: Moment) -> Self {
Self {
calendar,
moment,
tz: TimeZone::UTC,
}
}
pub const fn from_moment_at_offset(calendar: C, moment: Moment, offset: Offset) -> Self {
Self {
calendar,
moment,
tz: TimeZone::fixed(offset),
}
}
}
impl<C: Calendar> DateTime<C> {
pub(crate) fn components(&self) -> (Date<C>, PlainTime, Offset) {
let offset = self.tz.offset_at_moment(self.moment);
let (mut secs, nsec) = self.moment.to_unix();
secs += offset.as_total_seconds() as i64;
let date = Date::from_unix_timestamp(self.calendar, secs);
let time = PlainTime::from_unix_timestamp(secs, nsec);
(date, time, offset)
}
#[must_use]
pub const fn calendar(&self) -> C {
self.calendar
}
#[must_use]
#[inline]
pub fn year(&self) -> Year<C> {
self.as_date().year()
}
#[must_use]
#[inline]
pub fn month(&self) -> Month<C> {
self.as_date().month()
}
#[must_use]
#[inline]
pub fn day(&self) -> u8 {
self.as_date().day()
}
#[must_use]
#[inline]
pub fn day_of_year(&self) -> u16 {
self.as_date().day_of_year()
}
#[must_use]
#[inline]
pub fn hour(&self) -> u8 {
self.as_time().hour()
}
#[must_use]
#[inline]
pub fn minute(&self) -> u8 {
self.as_time().minute()
}
#[must_use]
#[inline]
pub fn second(&self) -> u8 {
self.as_time().second()
}
#[must_use]
#[inline]
pub fn millisecond(&self) -> u16 {
self.as_time().millisecond()
}
#[must_use]
#[inline]
pub fn microsecond(&self) -> u32 {
self.as_time().microsecond()
}
#[must_use]
#[inline]
pub fn nanosecond(&self) -> u32 {
self.as_time().nanosecond()
}
}
impl<C: Calendar> DateTime<C> {
#[must_use]
pub fn at(&self, tz: &TimeZone) -> Self {
Self {
tz: tz.clone(),
moment: self.moment,
calendar: self.calendar,
}
}
}
impl<C: Calendar> Debug for DateTime<C> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.pad(&self.format_rfc3339())
}
}
impl<C: Calendar> From<DateTime<C>> for Moment {
fn from(dt: DateTime<C>) -> Self {
dt.as_moment()
}
}
impl<C: Calendar> AsMoment for DateTime<C> {
fn as_moment(&self) -> Moment {
self.moment
}
}
impl<C: Calendar> AsDate<C> for DateTime<C> {
fn as_date(&self) -> Date<C> {
let (secs, _) = self.as_timestamp();
Date::from_unix_timestamp(self.calendar, secs)
}
}
impl<C: Calendar> AsTime for DateTime<C> {
fn as_time(&self) -> PlainTime {
let (secs, nsec) = self.as_timestamp();
PlainTime::from_unix_timestamp(secs, nsec)
}
fn as_timestamp(&self) -> (i64, u32) {
let offset = self.tz.offset_at_moment(self.moment);
let (mut secs, nsec) = self.moment.to_unix();
secs += offset.as_total_seconds() as i64;
(secs, nsec)
}
}