Repository: BurntSushi/jiff (language: rust)

Issue:
Fix `ISOWeekDate::weekday` doc and examples
As ISO-Week is Monday == day 1 based system, it would be nice to give correct example to readers in this context. 
So instead of `Weekday::to_sunday_zero_offset` use `Weekday::to_monday_one_offset` in doc and examples.

Add an assert test into the example code to highlight above.


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 476f8e40..cfc742a2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,19 @@
 ============
 TODO
 
+Deprecations:
+
+* [#197](https://github.com/BurntSushi/jiff/discussions/197):
+`Date::to_iso_week_date` has been deprecated in favor of `Date::iso_week_date`.
+
+Enhancements:
+
+* [#196](https://github.com/BurntSushi/jiff/discussions/196):
+Improve ISO week date documentation regarding weekday offsets.
+* [#197](https://github.com/BurntSushi/jiff/discussions/197):
+Add `Zoned::iso_week_date`, `DateTime::iso_week_date` and
+`Date::iso_week_date`.
+
 Bug fixes:
 
 * [#200](https://github.com/BurntSushi/jiff/issues/200):
diff --git a/src/civil/date.rs b/src/civil/date.rs
index 165fb8e3..b810b309 100644
--- a/src/civil/date.rs
+++ b/src/civil/date.rs
@@ -1079,44 +1079,44 @@ impl Date {
     ///
     /// # Example
     ///
-    /// This shows a number of examples demonstrating the conversion from an
-    /// ISO 8601 week date to a Gregorian date.
+    /// This shows a number of examples demonstrating the conversion from a
+    /// Gregorian date to an ISO 8601 week date:
     ///
     /// ```
     /// use jiff::civil::{Date, Weekday, date};
     ///
-    /// let weekdate = date(1995, 1, 1).to_iso_week_date();
+    /// let weekdate = date(1995, 1, 1).iso_week_date();
     /// assert_eq!(weekdate.year(), 1994);
     /// assert_eq!(weekdate.week(), 52);
     /// assert_eq!(weekdate.weekday(), Weekday::Sunday);
     ///
-    /// let weekdate = date(1996, 12, 31).to_iso_week_date();
+    /// let weekdate = date(1996, 12, 31).iso_week_date();
     /// assert_eq!(weekdate.year(), 1997);
     /// assert_eq!(weekdate.week(), 1);
     /// assert_eq!(weekdate.weekday(), Weekday::Tuesday);
     ///
-    /// let weekdate = date(2019, 12, 30).to_iso_week_date();
+    /// let weekdate = date(2019, 12, 30).iso_week_date();
     /// assert_eq!(weekdate.year(), 2020);
     /// assert_eq!(weekdate.week(), 1);
     /// assert_eq!(weekdate.weekday(), Weekday::Monday);
     ///
-    /// let weekdate = date(2024, 3, 9).to_iso_week_date();
+    /// let weekdate = date(2024, 3, 9).iso_week_date();
     /// assert_eq!(weekdate.year(), 2024);
     /// assert_eq!(weekdate.week(), 10);
     /// assert_eq!(weekdate.weekday(), Weekday::Saturday);
     ///
-    /// let weekdate = Date::MIN.to_iso_week_date();
+    /// let weekdate = Date::MIN.iso_week_date();
     /// assert_eq!(weekdate.year(), -9999);
     /// assert_eq!(weekdate.week(), 1);
     /// assert_eq!(weekdate.weekday(), Weekday::Monday);
     ///
-    /// let weekdate = Date::MAX.to_iso_week_date();
+    /// let weekdate = Date::MAX.iso_week_date();
     /// assert_eq!(weekdate.year(), 9999);
     /// assert_eq!(weekdate.week(), 52);
     /// assert_eq!(weekdate.weekday(), Weekday::Friday);
     /// ```
     #[inline]
-    pub fn to_iso_week_date(self) -> ISOWeekDate {
+    pub fn iso_week_date(self) -> ISOWeekDate {
         let days = t::NoUnits32::rfrom(self.to_unix_epoch_days());
         let year = t::NoUnits32::rfrom(self.year_ranged());
         let week_start = t::NoUnits32::vary([days, year], |[days, year]| {
@@ -2053,6 +2053,19 @@ impl Date {
     }
 }
 
+/// Deprecated APIs.
+impl Date {
+    /// A deprecated equivalent to [`Date::iso_week_date`].
+    ///
+    /// This method will be removed in `jiff 0.2`. This was done to make naming
+    /// more consistent throughout the crate.
+    #[deprecated(since = "0.1.23", note = "use Date::iso_week_date instead")]
+    #[inline]
+    pub fn to_iso_week_date(self) -> ISOWeekDate {
+        self.iso_week_date()
+    }
+}
+
 // Constants used for converting between Gregorian calendar dates and Unix
 // epoch days.
 //
@@ -3741,7 +3754,7 @@ mod tests {
                 let month = Month::new(month).unwrap();
                 for day in 20..=days_in_month(year, month).get() {
                     let date = date(year.get(), month.get(), day);
-                    let wd = date.to_iso_week_date();
+                    let wd = date.iso_week_date();
                     let got = wd.to_date();
                     assert_eq!(
                         date, got,
diff --git a/src/civil/datetime.rs b/src/civil/datetime.rs
index 8e736a19..efbea6bb 100644
--- a/src/civil/datetime.rs
+++ b/src/civil/datetime.rs
@@ -1,7 +1,9 @@
 use core::time::Duration as UnsignedDuration;
 
 use crate::{
-    civil::{datetime, Date, DateWith, Era, Time, TimeWith, Weekday},
+    civil::{
+        datetime, Date, DateWith, Era, ISOWeekDate, Time, TimeWith, Weekday,
+    },
     duration::{Duration, SDuration},
     error::{err, Error, ErrorContext},
     fmt::{
@@ -1252,6 +1254,66 @@ impl DateTime {
         self.time
     }
 
+    /// Construct an [ISO 8601 week date] from this datetime.
+    ///
+    /// The [`ISOWeekDate`] type describes itself in more detail, but in
+    /// brief, the ISO week date calendar system eschews months in favor of
+    /// weeks.
+    ///
+    /// This routine is equivalent to
+    /// [`ISOWeekDate::from_date(dt.date())`](ISOWeekDate::from_date).
+    ///
+    /// [ISO 8601 week date]: https://en.wikipedia.org/wiki/ISO_week_date
+    ///
+    /// # Example
+    ///
+    /// This shows a number of examples demonstrating the conversion from a
+    /// Gregorian date to an ISO 8601 week date:
+    ///
+    /// ```
+    /// use jiff::civil::{Date, Time, Weekday, date};
+    ///
+    /// let dt = date(1995, 1, 1).at(18, 45, 0, 0);
+    /// let weekdate = dt.iso_week_date();
+    /// assert_eq!(weekdate.year(), 1994);
+    /// assert_eq!(weekdate.week(), 52);
+    /// assert_eq!(weekdate.weekday(), Weekday::Sunday);
+    ///
+    /// let dt = date(1996, 12, 31).at(18, 45, 0, 0);
+    /// let weekdate = dt.iso_week_date();
+    /// assert_eq!(weekdate.year(), 1997);
+    /// assert_eq!(weekdate.week(), 1);
+    /// assert_eq!(weekdate.weekday(), Weekday::Tuesday);
+    ///
+    /// let dt = date(2019, 12, 30).at(18, 45, 0, 0);
+    /// let weekdate = dt.iso_week_date();
+    /// assert_eq!(weekdate.year(), 2020);
+    /// assert_eq!(weekdate.week(), 1);
+    /// assert_eq!(weekdate.weekday(), Weekday::Monday);
+    ///
+    /// let dt = date(2024, 3, 9).at(18, 45, 0, 0);
+    /// let weekdate = dt.iso_week_date();
+    /// assert_eq!(weekdate.year(), 2024);
+    /// assert_eq!(weekdate.week(), 10);
+    /// assert_eq!(weekdate.weekday(), Weekday::Saturday);
+    ///
+    /// let dt = Date::MIN.to_datetime(Time::MIN);
+    /// let weekdate = dt.iso_week_date();
+    /// assert_eq!(weekdate.year(), -9999);
+    /// assert_eq!(weekdate.week(), 1);
+    /// assert_eq!(weekdate.weekday(), Weekday::Monday);
+    ///
+    /// let dt = Date::MAX.to_datetime(Time::MAX);
+    /// let weekdate = dt.iso_week_date();
+    /// assert_eq!(weekdate.year(), 9999);
+    /// assert_eq!(weekdate.week(), 52);
+    /// assert_eq!(weekdate.weekday(), Weekday::Friday);
+    /// ```
+    #[inline]
+    pub fn iso_week_date(self) -> ISOWeekDate {
+        self.date().iso_week_date()
+    }
+
     /// Converts a civil datetime to a [`Zoned`] datetime by adding the given
     /// time zone.
     ///
diff --git a/src/civil/iso_week_date.rs b/src/civil/iso_week_date.rs
index db5559af..9506e0cc 100644
--- a/src/civil/iso_week_date.rs
+++ b/src/civil/iso_week_date.rs
@@ -1,10 +1,11 @@
 use crate::{
-    civil::{Date, Weekday},
+    civil::{Date, DateTime, Weekday},
     error::{err, Error},
     util::{
         rangeint::RInto,
         t::{self, ISOWeek, ISOYear, C},
     },
+    Zoned,
 };
 
 /// A type representing an [ISO 8601 week date].
@@ -190,7 +191,7 @@ impl ISOWeekDate {
     /// ```
     #[inline]
     pub fn from_date(date: Date) -> ISOWeekDate {
-        date.to_iso_week_date()
+        date.iso_week_date()
     }
 
     // N.B. I tried defining a `ISOWeekDate::constant` for defining ISO week
@@ -242,7 +243,10 @@ impl ISOWeekDate {
     /// Returns the day component of this ISO 8601 week date.
     ///
     /// One can use methods on `Weekday` such as
-    /// [`Weekday::to_sunday_zero_offset`] to convert the weekday to a number.
+    /// [`Weekday::to_monday_one_offset`]
+    /// and
+    /// [`Weekday::to_sunday_zero_offset`]
+    /// to convert the weekday to a number.
     ///
     /// # Example
     ///
@@ -253,6 +257,10 @@ impl ISOWeekDate {
     /// assert_eq!(weekdate.year(), 1948);
     /// assert_eq!(weekdate.week(), 53);
     /// assert_eq!(weekdate.weekday(), Weekday::Friday);
+    /// assert_eq!(weekdate.weekday().to_monday_zero_offset(), 4);
+    /// assert_eq!(weekdate.weekday().to_monday_one_offset(), 5);
+    /// assert_eq!(weekdate.weekday().to_sunday_zero_offset(), 5);
+    /// assert_eq!(weekdate.weekday().to_sunday_one_offset(), 6);
     /// ```
     #[inline]
     pub fn weekday(self) -> Weekday {
@@ -451,6 +459,27 @@ impl From<Date> for ISOWeekDate {
     }
 }
 
+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(test)]
 impl quickcheck::Arbitrary for ISOWeekDate {
     fn arbitrary(g: &mut quickcheck::Gen) -> ISOWeekDate {
diff --git a/src/zoned.rs b/src/zoned.rs
index 8f8ce28e..71513110 100644
--- a/src/zoned.rs
+++ b/src/zoned.rs
@@ -1,7 +1,10 @@
 use core::time::Duration as UnsignedDuration;
 
 use crate::{
-    civil::{Date, DateTime, DateTimeRound, DateTimeWith, Era, Time, Weekday},
+    civil::{
+        Date, DateTime, DateTimeRound, DateTimeWith, Era, ISOWeekDate, Time,
+        Weekday,
+    },
     duration::{Duration, SDuration},
     error::{err, Error, ErrorContext},
     fmt::{
@@ -1854,6 +1857,56 @@ impl Zoned {
         self.datetime().time()
     }
 
+    /// Construct a civil [ISO 8601 week date] from this zoned datetime.
+    ///
+    /// The [`ISOWeekDate`] type describes itself in more detail, but in
+    /// brief, the ISO week date calendar system eschews months in favor of
+    /// weeks.
+    ///
+    /// This routine is equivalent to
+    /// [`ISOWeekDate::from_date(zdt.date())`](ISOWeekDate::from_date).
+    ///
+    /// [ISO 8601 week date]: https://en.wikipedia.org/wiki/ISO_week_date
+    ///
+    /// # Example
+    ///
+    /// This shows a number of examples demonstrating the conversion from a
+    /// Gregorian date to an ISO 8601 week date:
+    ///
+    /// ```
+    /// use jiff::civil::{Date, Time, Weekday, date};
+    ///
+    /// let zdt = date(1995, 1, 1).at(18, 45, 0, 0).intz("US/Eastern")?;
+    /// let weekdate = zdt.iso_week_date();
+    /// assert_eq!(weekdate.year(), 1994);
+    /// assert_eq!(weekdate.week(), 52);
+    /// assert_eq!(weekdate.weekday(), Weekday::Sunday);
+    ///
+    /// let zdt = date(1996, 12, 31).at(18, 45, 0, 0).intz("US/Eastern")?;
+    /// let weekdate = zdt.iso_week_date();
+    /// assert_eq!(weekdate.year(), 1997);
+    /// assert_eq!(weekdate.week(), 1);
+    /// assert_eq!(weekdate.weekday(), Weekday::Tuesday);
+    ///
+    /// let zdt = date(2019, 12, 30).at(18, 45, 0, 0).intz("US/Eastern")?;
+    /// let weekdate = zdt.iso_week_date();
+    /// assert_eq!(weekdate.year(), 2020);
+    /// assert_eq!(weekdate.week(), 1);
+    /// assert_eq!(weekdate.weekday(), Weekday::Monday);
+    ///
+    /// let zdt = date(2024, 3, 9).at(18, 45, 0, 0).intz("US/Eastern")?;
+    /// let weekdate = zdt.iso_week_date();
+    /// assert_eq!(weekdate.year(), 2024);
+    /// assert_eq!(weekdate.week(), 10);
+    /// assert_eq!(weekdate.weekday(), Weekday::Saturday);
+    ///
+    /// # Ok::<(), Box<dyn std::error::Error>>(())
+    /// ```
+    #[inline]
+    pub fn iso_week_date(self) -> ISOWeekDate {
+        self.date().iso_week_date()
+    }
+
     /// Returns the time zone offset of this zoned datetime.
     ///
     /// # Example


Test patch: