///|
/// The week containing a `NaiveDate`, under a configurable first day of
/// the week (see `NaiveDate::week`). Distinct from `IsoWeek`, which is
/// always Monday-based and tied to the ISO 8601 week-numbering year.
///
/// Two `NaiveWeek`s are equal (and compare) by the calendar week they
/// denote, i.e. by their first day alone — the anchor date and `start`
/// weekday used to construct them don't affect equality.
///
/// A week at either end of `NaiveDate`'s representable range can extend
/// past it. Such a week can still be constructed, compared and hashed;
/// `first_day`, `last_day` and `days` abort if they would leave the range,
/// and `checked_first_day`, `checked_last_day` and `checked_days` return
/// `None` instead.
pub struct NaiveWeek {
priv date : NaiveDate
priv start : Weekday
}
///|
priv struct NaiveWeekDebugView {
first_day : Int64
} derive(@debug.Debug)
///|
pub impl @debug.Debug for NaiveWeek with fn to_repr(self) {
@debug.Debug::to_repr(NaiveWeekDebugView::{
first_day: self.first_epoch_days(),
})
}
///|
fn NaiveWeek::first_epoch_days(self : NaiveWeek) -> Int64 {
let back = (
self.date.weekday().num_days_from_monday() -
self.start.num_days_from_monday() +
7
) %
7
self.date.epoch_days().to_int64() - back.to_int64()
}
///|
pub impl Eq for NaiveWeek with fn equal(self, other) {
self.first_epoch_days() == other.first_epoch_days()
}
///|
pub extend NaiveWeek with Eq::{equal}
///|
pub extend NaiveWeek with Eq::{not_equal}
///|
pub impl Compare for NaiveWeek with fn compare(self, other) {
self.first_epoch_days().compare(other.first_epoch_days())
}
///|
pub extend NaiveWeek with Compare::{compare, op_lt, op_gt, op_le, op_ge}
///|
pub impl Hash for NaiveWeek with fn hash_combine(self, hasher) {
Hash::hash_combine(self.first_epoch_days(), hasher)
}
///|
pub extend NaiveWeek with Hash::{hash, hash_combine}
///|
pub extend NaiveWeek with @debug.Debug::{to_repr}
///|
/// The first day of the week (the `start` weekday, on or before the date
/// this week was constructed from).
///
/// Aborts if that day falls before `NaiveDate`'s representable range; use
/// `checked_first_day` to get `None` instead.
pub fn NaiveWeek::first_day(self : NaiveWeek) -> NaiveDate {
expect_in_range(self.checked_first_day(), "NaiveWeek::first_day")
}
///|
/// The first day of the week, or `None` if it falls before `NaiveDate`'s
/// representable range.
pub fn NaiveWeek::checked_first_day(self : NaiveWeek) -> NaiveDate? {
NaiveDate::from_epoch_days64(self.first_epoch_days())
}
///|
/// The last day of the week, six days after the first.
///
/// Aborts if that day falls after `NaiveDate`'s representable range; use
/// `checked_last_day` to get `None` instead.
pub fn NaiveWeek::last_day(self : NaiveWeek) -> NaiveDate {
expect_in_range(self.checked_last_day(), "NaiveWeek::last_day")
}
///|
/// The last day of the week, six days after the first, or `None` if it
/// falls after `NaiveDate`'s representable range.
pub fn NaiveWeek::checked_last_day(self : NaiveWeek) -> NaiveDate? {
NaiveDate::from_epoch_days64(self.first_epoch_days() + 6L)
}
///|
/// All seven days of the week, from the first day to the last.
///
/// Aborts if any of them falls outside `NaiveDate`'s representable range;
/// use `checked_days` to get `None` instead.
pub fn NaiveWeek::days(self : NaiveWeek) -> Array[NaiveDate] {
expect_in_range(self.checked_days(), "NaiveWeek::days")
}
///|
/// All seven days of the week, from the first day to the last, or `None`
/// if any of them falls outside `NaiveDate`'s representable range.
pub fn NaiveWeek::checked_days(self : NaiveWeek) -> Array[NaiveDate]? {
let first = self.first_epoch_days()
let result = []
for i = 0L; i < 7L; i = i + 1L {
match NaiveDate::from_epoch_days64(first + i) {
Some(day) => result.push(day)
None => return None
}
}
Some(result)
}