Struct ISOWeekDate

struct ISOWeekDate { ... }

A type representing an ISO 8601 week date.

The ISO 8601 week date scheme devises a calendar where days are identified by their year, week number and weekday. All years have either precisely 52 or 53 weeks.

The first week of an ISO 8601 year corresponds to the week containing the first Thursday of the year. For this reason, an ISO 8601 week year can be mismatched with the day's corresponding Gregorian year. For example, the ISO 8601 week date for 1995-01-01 is 1994-W52-7 (with 7 corresponding to Sunday).

ISO 8601 also considers Monday to be the start of the week, and uses a 1-based numbering system. That is, Monday corresponds to 1 while Sunday corresponds to 7 and is the last day of the week. Weekdays are encapsulated by the Weekday type, which provides routines for easily converting between different schemes (such as weeks where Sunday is the beginning).

Use case

Some domains use this method of timekeeping. Otherwise, unless you specifically want a week oriented calendar, it's likely that you'll never need to care about this type.

Default value

For convenience, this type implements the Default trait. Its default value is the first day of the zeroth year. i.e., 0000-W1-1.

Example: sample dates

This example shows a couple ISO 8601 week dates and their corresponding Gregorian equivalents:

use jiff::civil::{ISOWeekDate, Weekday, date};

let d = date(2019, 12, 30);
let weekdate = ISOWeekDate::new(2020, 1, Weekday::Monday).unwrap();
assert_eq!(d.iso_week_date(), weekdate);

let d = date(2024, 3, 9);
let weekdate = ISOWeekDate::new(2024, 10, Weekday::Saturday).unwrap();
assert_eq!(d.iso_week_date(), weekdate);

Example: overlapping leap and long years

A "long" ISO 8601 week year is a year with 53 weeks. That is, it is a year that includes a leap week. This example shows all years in the 20th century that are both Gregorian leap years and long years.

use jiff::civil::date;

let mut overlapping = vec![];
for year in 1900..=1999 {
    let date = date(year, 1, 1);
    if date.in_leap_year() && date.iso_week_date().in_long_year() {
        overlapping.push(year);
    }
}
assert_eq!(overlapping, vec![
    1904, 1908, 1920, 1932, 1936, 1948, 1960, 1964, 1976, 1988, 1992,
]);

Example: printing all weeks in a year

The ISO 8601 week calendar can be useful when you want to categorize things into buckets of weeks where all weeks are exactly 7 days, and you don't care as much about the precise Gregorian year. Here's an example that prints all of the ISO 8601 weeks in one ISO 8601 week year:

use jiff::{civil::{ISOWeekDate, Weekday}, ToSpan};

let target_year = 2024;
let iso_week_date = ISOWeekDate::new(target_year, 1, Weekday::Monday)?;
// Create a series of dates via the Gregorian calendar. But since a
// Gregorian week and an ISO 8601 week calendar week are both 7 days,
// this works fine.
let weeks = iso_week_date
    .date()
    .series(1.week())
    .map(|d| d.iso_week_date())
    .take_while(|wd| wd.year() == target_year);
for start_of_week in weeks {
    let end_of_week = start_of_week.last_of_week()?;
    println!(
        "ISO week {}: {} - {}",
        start_of_week.week(),
        start_of_week.date(),
        end_of_week.date()
    );
}
# Ok::<(), Box<dyn std::error::Error>>(())

Implementations

impl ISOWeekDate

fn new(year: i16, week: i8, weekday: Weekday) -> Result<ISOWeekDate, Error>

Create a new ISO week date from it constituent parts.

If the given values are out of range (based on what is representable as a Date), then this returns an error. This will also return an error if a leap week is given (week number 53) for a year that does not contain a leap week.

Example

This example shows some the boundary conditions involving minimum and maximum dates:

use jiff::civil::{ISOWeekDate, Weekday, date};

// The year 1949 does not contain a leap week.
assert!(ISOWeekDate::new(1949, 53, Weekday::Monday).is_err());

// Examples of dates at or exceeding the maximum.
let max = ISOWeekDate::new(9999, 52, Weekday::Friday).unwrap();
assert_eq!(max, ISOWeekDate::MAX);
assert_eq!(max.date(), date(9999, 12, 31));
assert!(ISOWeekDate::new(9999, 52, Weekday::Saturday).is_err());
assert!(ISOWeekDate::new(9999, 53, Weekday::Monday).is_err());

// Examples of dates at or exceeding the minimum.
let min = ISOWeekDate::new(-9999, 1, Weekday::Monday).unwrap();
assert_eq!(min, ISOWeekDate::MIN);
assert_eq!(min.date(), date(-9999, 1, 1));
assert!(ISOWeekDate::new(-10000, 52, Weekday::Sunday).is_err());
fn from_date(date: Date) -> ISOWeekDate

Converts a Gregorian date to an ISO week date.

The minimum and maximum allowed values of an ISO week date are set based on the minimum and maximum values of a Date. Therefore, converting to and from Date values is non-lossy and infallible.

This routine is equivalent to Date::iso_week_date. This routine is also available via a From<Date> trait implementation for ISOWeekDate.

Example

use jiff::civil::{ISOWeekDate, Weekday, date};

let weekdate = ISOWeekDate::from_date(date(1948, 2, 10));
assert_eq!(
    weekdate,
    ISOWeekDate::new(1948, 7, Weekday::Tuesday).unwrap(),
);
fn year(self: Self) -> i16

Returns the year component of this ISO 8601 week date.

The value returned is guaranteed to be in the range -9999..=9999.

Example

use jiff::civil::date;

let weekdate = date(2019, 12, 30).iso_week_date();
assert_eq!(weekdate.year(), 2020);
fn week(self: Self) -> i8

Returns the week component of this ISO 8601 week date.

The value returned is guaranteed to be in the range 1..=53. A value of 53 can only occur for "long" years. That is, years with a leap week. This occurs precisely in cases for which ISOWeekDate::in_long_year returns true.

Example

use jiff::civil::date;

let weekdate = date(2019, 12, 30).iso_week_date();
assert_eq!(weekdate.year(), 2020);
assert_eq!(weekdate.week(), 1);

let weekdate = date(1948, 12, 31).iso_week_date();
assert_eq!(weekdate.year(), 1948);
assert_eq!(weekdate.week(), 53);
fn weekday(self: Self) -> Weekday

Returns the day component of this ISO 8601 week date.

One can use methods on Weekday such as Weekday::to_monday_one_offset and Weekday::to_sunday_zero_offset to convert the weekday to a number.

Example

use jiff::civil::{date, Weekday};

let weekdate = date(1948, 12, 31).iso_week_date();
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);
fn first_of_week(self: Self) -> Result<ISOWeekDate, Error>

Returns the ISO 8601 week date corresponding to the first day in the week of this week date. The date returned is guaranteed to have a weekday of Weekday::Monday.

Errors

Since -9999-01-01 falls on a Monday, it follows that the minimum support Gregorian date is exactly equivalent to the minimum supported ISO 8601 week date. This means that this routine can never actually fail, but only insomuch as the minimums line up. For that reason, and for consistency with ISOWeekDate::last_of_week, the API is fallible.

Example

use jiff::civil::{ISOWeekDate, Weekday, date};

let wd = ISOWeekDate::new(2025, 5, Weekday::Wednesday).unwrap();
assert_eq!(wd.date(), date(2025, 1, 29));
assert_eq!(
    wd.first_of_week()?,
    ISOWeekDate::new(2025, 5, Weekday::Monday).unwrap(),
);

// Works even for the minimum date.
assert_eq!(
    ISOWeekDate::MIN.first_of_week()?,
    ISOWeekDate::new(-9999, 1, Weekday::Monday).unwrap(),
);

# Ok::<(), Box<dyn std::error::Error>>(())
fn last_of_week(self: Self) -> Result<ISOWeekDate, Error>

Returns the ISO 8601 week date corresponding to the last day in the week of this week date. The date returned is guaranteed to have a weekday of Weekday::Sunday.

Errors

This can return an error if the last day of the week exceeds Jiff's maximum Gregorian date of 9999-12-31. It turns out this can happen since 9999-12-31 falls on a Friday.

Example

use jiff::civil::{ISOWeekDate, Weekday, date};

let wd = ISOWeekDate::new(2025, 5, Weekday::Wednesday).unwrap();
assert_eq!(wd.date(), date(2025, 1, 29));
assert_eq!(
    wd.last_of_week()?,
    ISOWeekDate::new(2025, 5, Weekday::Sunday).unwrap(),
);

// Unlike `first_of_week`, this routine can actually fail on real
// values, although, only when close to the maximum supported date.
assert_eq!(
    ISOWeekDate::MAX.last_of_week().unwrap_err().to_string(),
    "parameter 'weekday' with value 7 is not \
     in the required range of 1..=5",
);

# Ok::<(), Box<dyn std::error::Error>>(())
fn first_of_year(self: Self) -> Result<ISOWeekDate, Error>

Returns the ISO 8601 week date corresponding to the first day in the year of this week date. The date returned is guaranteed to have a weekday of Weekday::Monday.

Errors

Since -9999-01-01 falls on a Monday, it follows that the minimum support Gregorian date is exactly equivalent to the minimum supported ISO 8601 week date. This means that this routine can never actually fail, but only insomuch as the minimums line up. For that reason, and for consistency with ISOWeekDate::last_of_year, the API is fallible.

Example

use jiff::civil::{ISOWeekDate, Weekday, date};

let wd = ISOWeekDate::new(2025, 5, Weekday::Wednesday).unwrap();
assert_eq!(wd.date(), date(2025, 1, 29));
assert_eq!(
    wd.first_of_year()?,
    ISOWeekDate::new(2025, 1, Weekday::Monday).unwrap(),
);

// Works even for the minimum date.
assert_eq!(
    ISOWeekDate::MIN.first_of_year()?,
    ISOWeekDate::new(-9999, 1, Weekday::Monday).unwrap(),
);

# Ok::<(), Box<dyn std::error::Error>>(())
fn last_of_year(self: Self) -> Result<ISOWeekDate, Error>

Returns the ISO 8601 week date corresponding to the last day in the year of this week date. The date returned is guaranteed to have a weekday of Weekday::Sunday.

Errors

This can return an error if the last day of the year exceeds Jiff's maximum Gregorian date of 9999-12-31. It turns out this can happen since 9999-12-31 falls on a Friday.

Example

use jiff::civil::{ISOWeekDate, Weekday, date};

let wd = ISOWeekDate::new(2025, 5, Weekday::Wednesday).unwrap();
assert_eq!(wd.date(), date(2025, 1, 29));
assert_eq!(
    wd.last_of_year()?,
    ISOWeekDate::new(2025, 52, Weekday::Sunday).unwrap(),
);

// Works correctly for "long" years.
let wd = ISOWeekDate::new(2026, 5, Weekday::Wednesday).unwrap();
assert_eq!(wd.date(), date(2026, 1, 28));
assert_eq!(
    wd.last_of_year()?,
    ISOWeekDate::new(2026, 53, Weekday::Sunday).unwrap(),
);

// Unlike `first_of_year`, this routine can actually fail on real
// values, although, only when close to the maximum supported date.
assert_eq!(
    ISOWeekDate::MAX.last_of_year().unwrap_err().to_string(),
    "parameter 'weekday' with value 7 is not \
     in the required range of 1..=5",
);

# Ok::<(), Box<dyn std::error::Error>>(())
fn days_in_year(self: Self) -> i16

Returns the total number of days in the year of this ISO 8601 week date.

It is guaranteed that the value returned is either 364 or 371. The latter case occurs precisely when ISOWeekDate::in_long_year returns true.

Example

use jiff::civil::{ISOWeekDate, Weekday};

let weekdate = ISOWeekDate::new(2025, 7, Weekday::Monday).unwrap();
assert_eq!(weekdate.days_in_year(), 364);
let weekdate = ISOWeekDate::new(2026, 7, Weekday::Monday).unwrap();
assert_eq!(weekdate.days_in_year(), 371);
fn weeks_in_year(self: Self) -> i8

Returns the total number of weeks in the year of this ISO 8601 week date.

It is guaranteed that the value returned is either 52 or 53. The latter case occurs precisely when ISOWeekDate::in_long_year returns true.

Example

use jiff::civil::{ISOWeekDate, Weekday};

let weekdate = ISOWeekDate::new(2025, 7, Weekday::Monday).unwrap();
assert_eq!(weekdate.weeks_in_year(), 52);
let weekdate = ISOWeekDate::new(2026, 7, Weekday::Monday).unwrap();
assert_eq!(weekdate.weeks_in_year(), 53);
fn in_long_year(self: Self) -> bool

Returns true if and only if the year of this week date is a "long" year.

A long year is one that contains precisely 53 weeks. All other years contain precisely 52 weeks.

Example

use jiff::civil::{ISOWeekDate, Weekday};

let weekdate = ISOWeekDate::new(1948, 7, Weekday::Monday).unwrap();
assert!(weekdate.in_long_year());
let weekdate = ISOWeekDate::new(1949, 7, Weekday::Monday).unwrap();
assert!(!weekdate.in_long_year());
fn tomorrow(self: Self) -> Result<ISOWeekDate, Error>

Returns the ISO 8601 date immediately following this one.

Errors

This returns an error when this date is the maximum value.

Example

use jiff::civil::{ISOWeekDate, Weekday};

let wd = ISOWeekDate::new(2025, 5, Weekday::Wednesday).unwrap();
assert_eq!(
    wd.tomorrow()?,
    ISOWeekDate::new(2025, 5, Weekday::Thursday).unwrap(),
);

// The max doesn't have a tomorrow.
assert!(ISOWeekDate::MAX.tomorrow().is_err());

# Ok::<(), Box<dyn std::error::Error>>(())
fn yesterday(self: Self) -> Result<ISOWeekDate, Error>

Returns the ISO 8601 week date immediately preceding this one.

Errors

This returns an error when this date is the minimum value.

Example

use jiff::civil::{ISOWeekDate, Weekday};

let wd = ISOWeekDate::new(2025, 5, Weekday::Wednesday).unwrap();
assert_eq!(
    wd.yesterday()?,
    ISOWeekDate::new(2025, 5, Weekday::Tuesday).unwrap(),
);

// The min doesn't have a yesterday.
assert!(ISOWeekDate::MIN.yesterday().is_err());

# Ok::<(), Box<dyn std::error::Error>>(())
fn date(self: Self) -> Date

Converts this ISO week date to a Gregorian Date.

The minimum and maximum allowed values of an ISO week date are set based on the minimum and maximum values of a Date. Therefore, converting to and from Date values is non-lossy and infallible.

This routine is equivalent to Date::from_iso_week_date.

Example

use jiff::civil::{ISOWeekDate, Weekday, date};

let weekdate = ISOWeekDate::new(1948, 7, Weekday::Tuesday).unwrap();
assert_eq!(weekdate.date(), date(1948, 2, 10));

impl Clone for ISOWeekDate

fn clone(self: &Self) -> ISOWeekDate

impl Copy for ISOWeekDate

impl Debug for ISOWeekDate

fn fmt(self: &Self, f: &mut Formatter<'_>) -> Result

impl Default for ISOWeekDate

fn default() -> ISOWeekDate

impl Eq for ISOWeekDate

impl Freeze for ISOWeekDate

impl From for ISOWeekDate

fn from(dt: DateTime) -> ISOWeekDate

impl From for ISOWeekDate

fn from(date: Date) -> ISOWeekDate

impl From for ISOWeekDate

fn from(zdt: Zoned) -> ISOWeekDate

impl Hash for ISOWeekDate

fn hash<__H: $crate::hash::Hasher>(self: &Self, state: &mut __H)

impl Ord for ISOWeekDate

fn cmp(self: &Self, other: &ISOWeekDate) -> Ordering

impl PartialEq for ISOWeekDate

fn eq(self: &Self, other: &ISOWeekDate) -> bool

impl PartialOrd for ISOWeekDate

fn partial_cmp(self: &Self, other: &ISOWeekDate) -> Option<Ordering>

impl RefUnwindSafe for ISOWeekDate

impl Send for ISOWeekDate

impl Sync for ISOWeekDate

impl Unpin for ISOWeekDate

impl UnsafeUnpin for ISOWeekDate

impl UnwindSafe for ISOWeekDate

impl<'a> From for ISOWeekDate

fn from(zdt: &'a Zoned) -> ISOWeekDate

impl<T> Any for ISOWeekDate

fn type_id(self: &Self) -> TypeId

impl<T> Borrow for ISOWeekDate

fn borrow(self: &Self) -> &T

impl<T> BorrowMut for ISOWeekDate

fn borrow_mut(self: &mut Self) -> &mut T

impl<T> CloneToUninit for ISOWeekDate

unsafe fn clone_to_uninit(self: &Self, dest: *mut u8)

impl<T> From for ISOWeekDate

fn from(t: T) -> T

Returns the argument unchanged.

impl<T> ToOwned for ISOWeekDate

fn to_owned(self: &Self) -> T
fn clone_into(self: &Self, target: &mut T)

impl<T, U> Into for ISOWeekDate

fn into(self: Self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of [From]<T> for U chooses to do.

impl<T, U> TryFrom for ISOWeekDate

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

impl<T, U> TryInto for ISOWeekDate

fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error>