use jcore::civil::ISOWeekDate as JISOWeekDate;
use crate::{
civil::{Date, DateTime, Weekday},
error::Error,
fmt::temporal::{DEFAULT_DATETIME_PARSER, DEFAULT_DATETIME_PRINTER},
Zoned,
};
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct ISOWeekDate {
pub(crate) inner: JISOWeekDate,
}
impl ISOWeekDate {
pub const MIN: ISOWeekDate = ISOWeekDate { inner: JISOWeekDate::MIN };
pub const MAX: ISOWeekDate = ISOWeekDate { inner: JISOWeekDate::MAX };
pub const ZERO: ISOWeekDate = ISOWeekDate { inner: JISOWeekDate::ZERO };
#[inline]
pub fn new(
year: i16,
week: i8,
weekday: Weekday,
) -> Result<ISOWeekDate, Error> {
JISOWeekDate::new(year, week, weekday.to_jcore())
.map(ISOWeekDate::from_jcore)
.map_err(Error::jcore_range)
}
#[inline]
pub fn from_date(date: Date) -> ISOWeekDate {
date.iso_week_date()
}
#[inline]
pub fn year(self) -> i16 {
self.inner.year()
}
#[inline]
pub fn week(self) -> i8 {
self.inner.week()
}
#[inline]
pub fn weekday(self) -> Weekday {
Weekday::from_jcore(self.inner.weekday())
}
#[inline]
pub fn first_of_week(self) -> Result<ISOWeekDate, Error> {
self.inner
.first_of_week()
.map(ISOWeekDate::from_jcore)
.map_err(Error::jcore_range)
}
#[inline]
pub fn last_of_week(self) -> Result<ISOWeekDate, Error> {
self.inner
.last_of_week()
.map(ISOWeekDate::from_jcore)
.map_err(Error::jcore_range)
}
#[inline]
pub fn first_of_year(self) -> Result<ISOWeekDate, Error> {
self.inner
.first_of_year()
.map(ISOWeekDate::from_jcore)
.map_err(Error::jcore_range)
}
#[inline]
pub fn last_of_year(self) -> Result<ISOWeekDate, Error> {
self.inner
.last_of_year()
.map(ISOWeekDate::from_jcore)
.map_err(Error::jcore_range)
}
#[inline]
pub fn days_in_year(self) -> i16 {
self.inner.days_in_year()
}
#[inline]
pub fn weeks_in_year(self) -> i8 {
self.inner.weeks_in_year()
}
#[inline]
pub fn in_long_year(self) -> bool {
self.inner.in_long_year()
}
#[inline]
pub fn tomorrow(self) -> Result<ISOWeekDate, Error> {
self.inner
.tomorrow()
.map(ISOWeekDate::from_jcore)
.map_err(Error::jcore_range)
}
#[inline]
pub fn yesterday(self) -> Result<ISOWeekDate, Error> {
self.inner
.yesterday()
.map(ISOWeekDate::from_jcore)
.map_err(Error::jcore_range)
}
#[inline]
pub fn date(self) -> Date {
Date::from_iso_week_date(self)
}
#[inline]
pub(crate) const fn from_jcore(week_date: JISOWeekDate) -> ISOWeekDate {
ISOWeekDate { inner: week_date }
}
#[inline]
pub(crate) const fn to_jcore(self) -> JISOWeekDate {
self.inner
}
}
impl Default for ISOWeekDate {
fn default() -> ISOWeekDate {
ISOWeekDate::ZERO
}
}
impl core::fmt::Debug for ISOWeekDate {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
core::fmt::Display::fmt(self, f)
}
}
impl core::fmt::Display for ISOWeekDate {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
use crate::fmt::StdFmtWrite;
DEFAULT_DATETIME_PRINTER
.print_iso_week_date(self, StdFmtWrite(f))
.map_err(|_| core::fmt::Error)
}
}
impl core::str::FromStr for ISOWeekDate {
type Err = Error;
fn from_str(string: &str) -> Result<ISOWeekDate, Error> {
DEFAULT_DATETIME_PARSER.parse_iso_week_date(string)
}
}
impl Ord for ISOWeekDate {
#[inline]
fn cmp(&self, other: &ISOWeekDate) -> core::cmp::Ordering {
(self.year(), self.week(), self.weekday().to_monday_one_offset()).cmp(
&(
other.year(),
other.week(),
other.weekday().to_monday_one_offset(),
),
)
}
}
impl PartialOrd for ISOWeekDate {
#[inline]
fn partial_cmp(&self, other: &ISOWeekDate) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl From<Date> for ISOWeekDate {
#[inline]
fn from(date: Date) -> ISOWeekDate {
ISOWeekDate::from_date(date)
}
}
impl From<DateTime> for ISOWeekDate {
#[inline]
fn from(dt: DateTime) -> ISOWeekDate {
ISOWeekDate::from(dt.date())
}
}
impl From<Zoned> for ISOWeekDate {
#[inline]
fn from(zdt: Zoned) -> ISOWeekDate {
ISOWeekDate::from(zdt.date())
}
}
impl<'a> From<&'a Zoned> for ISOWeekDate {
#[inline]
fn from(zdt: &'a Zoned) -> ISOWeekDate {
ISOWeekDate::from(zdt.date())
}
}
#[cfg(feature = "defmt")]
impl defmt::Format for ISOWeekDate {
fn format(&self, f: defmt::Formatter) {
use crate::fmt::DefmtWrite;
defmt::unwrap!(
DEFAULT_DATETIME_PRINTER.print_iso_week_date(self, DefmtWrite(f))
);
}
}
#[cfg(feature = "serde")]
impl serde_core::Serialize for ISOWeekDate {
#[inline]
fn serialize<S: serde_core::Serializer>(
&self,
serializer: S,
) -> Result<S::Ok, S::Error> {
serializer.collect_str(self)
}
}
#[cfg(feature = "serde")]
impl<'de> serde_core::Deserialize<'de> for ISOWeekDate {
#[inline]
fn deserialize<D: serde_core::Deserializer<'de>>(
deserializer: D,
) -> Result<ISOWeekDate, D::Error> {
use serde_core::de;
struct ISOWeekDateVisitor;
impl<'de> de::Visitor<'de> for ISOWeekDateVisitor {
type Value = ISOWeekDate;
fn expecting(
&self,
f: &mut core::fmt::Formatter,
) -> core::fmt::Result {
f.write_str("an ISO 8601 week date string")
}
#[inline]
fn visit_bytes<E: de::Error>(
self,
value: &[u8],
) -> Result<ISOWeekDate, E> {
DEFAULT_DATETIME_PARSER
.parse_iso_week_date(value)
.map_err(de::Error::custom)
}
#[inline]
fn visit_str<E: de::Error>(
self,
value: &str,
) -> Result<ISOWeekDate, E> {
self.visit_bytes(value.as_bytes())
}
}
deserializer.deserialize_str(ISOWeekDateVisitor)
}
}