New type: `chrono::naive::IsoWeek`.
This removes `Datelike::isoweekdate` in favor of `Datelike::iso_week`. The original `isoweekdate` was not named in accordance with the style guide and also used to return the day of the week which is already provided by `Datelike::weekday`. The new design should be more reasonable. Note that we initially do not implement any public constructor for `IsoWeek`. That is, the only legitimate way to get a new `IsoWeek` is from `Datelike::iso_week`. This sidesteps the issue of boundary values (for example the year number in the maximal date will overflow in the week date) while giving the same power as the original API. Partially accounts for #139. We may add additional week types as necessary---this is the beginning.
This commit is contained in:
parent
42a7c8e589
commit
9768b289f0
|
@ -10,7 +10,7 @@ use oldtime::Duration as OldDuration;
|
||||||
|
|
||||||
use {Weekday, Datelike};
|
use {Weekday, Datelike};
|
||||||
use offset::{TimeZone, UTC};
|
use offset::{TimeZone, UTC};
|
||||||
use naive::{self, NaiveDate, NaiveTime};
|
use naive::{self, NaiveDate, NaiveTime, IsoWeek};
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use format::{Item, DelayedFormat, StrftimeItems};
|
use format::{Item, DelayedFormat, StrftimeItems};
|
||||||
|
|
||||||
|
@ -278,7 +278,7 @@ impl<Tz: TimeZone> Datelike for Date<Tz> {
|
||||||
#[inline] fn ordinal(&self) -> u32 { self.naive_local().ordinal() }
|
#[inline] fn ordinal(&self) -> u32 { self.naive_local().ordinal() }
|
||||||
#[inline] fn ordinal0(&self) -> u32 { self.naive_local().ordinal0() }
|
#[inline] fn ordinal0(&self) -> u32 { self.naive_local().ordinal0() }
|
||||||
#[inline] fn weekday(&self) -> Weekday { self.naive_local().weekday() }
|
#[inline] fn weekday(&self) -> Weekday { self.naive_local().weekday() }
|
||||||
#[inline] fn isoweekdate(&self) -> (i32, u32, Weekday) { self.naive_local().isoweekdate() }
|
#[inline] fn iso_week(&self) -> IsoWeek { self.naive_local().iso_week() }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_year(&self, year: i32) -> Option<Date<Tz>> {
|
fn with_year(&self, year: i32) -> Option<Date<Tz>> {
|
||||||
|
|
|
@ -12,7 +12,7 @@ use oldtime::Duration as OldDuration;
|
||||||
|
|
||||||
use {Weekday, Timelike, Datelike};
|
use {Weekday, Timelike, Datelike};
|
||||||
use offset::{TimeZone, Offset, UTC, Local, FixedOffset};
|
use offset::{TimeZone, Offset, UTC, Local, FixedOffset};
|
||||||
use naive::{NaiveTime, NaiveDateTime};
|
use naive::{NaiveTime, NaiveDateTime, IsoWeek};
|
||||||
use Date;
|
use Date;
|
||||||
use format::{Item, Numeric, Pad, Fixed};
|
use format::{Item, Numeric, Pad, Fixed};
|
||||||
use format::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItems};
|
use format::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItems};
|
||||||
|
@ -258,7 +258,7 @@ impl<Tz: TimeZone> Datelike for DateTime<Tz> {
|
||||||
#[inline] fn ordinal(&self) -> u32 { self.naive_local().ordinal() }
|
#[inline] fn ordinal(&self) -> u32 { self.naive_local().ordinal() }
|
||||||
#[inline] fn ordinal0(&self) -> u32 { self.naive_local().ordinal0() }
|
#[inline] fn ordinal0(&self) -> u32 { self.naive_local().ordinal0() }
|
||||||
#[inline] fn weekday(&self) -> Weekday { self.naive_local().weekday() }
|
#[inline] fn weekday(&self) -> Weekday { self.naive_local().weekday() }
|
||||||
#[inline] fn isoweekdate(&self) -> (i32, u32, Weekday) { self.naive_local().isoweekdate() }
|
#[inline] fn iso_week(&self) -> IsoWeek { self.naive_local().iso_week() }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_year(&self, year: i32) -> Option<DateTime<Tz>> {
|
fn with_year(&self, year: i32) -> Option<DateTime<Tz>> {
|
||||||
|
|
|
@ -353,14 +353,14 @@ pub fn format<'a, I>(w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Opt
|
||||||
Year => (4, date.map(|d| d.year() as i64)),
|
Year => (4, date.map(|d| d.year() as i64)),
|
||||||
YearDiv100 => (2, date.map(|d| div_floor(d.year() as i64, 100))),
|
YearDiv100 => (2, date.map(|d| div_floor(d.year() as i64, 100))),
|
||||||
YearMod100 => (2, date.map(|d| mod_floor(d.year() as i64, 100))),
|
YearMod100 => (2, date.map(|d| mod_floor(d.year() as i64, 100))),
|
||||||
IsoYear => (4, date.map(|d| d.isoweekdate().0 as i64)),
|
IsoYear => (4, date.map(|d| d.iso_week().year() as i64)),
|
||||||
IsoYearDiv100 => (2, date.map(|d| div_floor(d.isoweekdate().0 as i64, 100))),
|
IsoYearDiv100 => (2, date.map(|d| div_floor(d.iso_week().year() as i64, 100))),
|
||||||
IsoYearMod100 => (2, date.map(|d| mod_floor(d.isoweekdate().0 as i64, 100))),
|
IsoYearMod100 => (2, date.map(|d| mod_floor(d.iso_week().year() as i64, 100))),
|
||||||
Month => (2, date.map(|d| d.month() as i64)),
|
Month => (2, date.map(|d| d.month() as i64)),
|
||||||
Day => (2, date.map(|d| d.day() as i64)),
|
Day => (2, date.map(|d| d.day() as i64)),
|
||||||
WeekFromSun => (2, date.map(|d| week_from_sun(d) as i64)),
|
WeekFromSun => (2, date.map(|d| week_from_sun(d) as i64)),
|
||||||
WeekFromMon => (2, date.map(|d| week_from_mon(d) as i64)),
|
WeekFromMon => (2, date.map(|d| week_from_mon(d) as i64)),
|
||||||
IsoWeek => (2, date.map(|d| d.isoweekdate().1 as i64)),
|
IsoWeek => (2, date.map(|d| d.iso_week().week() as i64)),
|
||||||
NumDaysFromSun => (1, date.map(|d| d.weekday().num_days_from_sunday() as i64)),
|
NumDaysFromSun => (1, date.map(|d| d.weekday().num_days_from_sunday() as i64)),
|
||||||
WeekdayFromMon => (1, date.map(|d| d.weekday().number_from_monday() as i64)),
|
WeekdayFromMon => (1, date.map(|d| d.weekday().number_from_monday() as i64)),
|
||||||
Ordinal => (3, date.map(|d| d.ordinal() as i64)),
|
Ordinal => (3, date.map(|d| d.ordinal() as i64)),
|
||||||
|
|
|
@ -332,7 +332,10 @@ impl Parsed {
|
||||||
|
|
||||||
// verify the ISO week date.
|
// verify the ISO week date.
|
||||||
let verify_isoweekdate = |date: NaiveDate| {
|
let verify_isoweekdate = |date: NaiveDate| {
|
||||||
let (isoyear, isoweek, weekday) = date.isoweekdate();
|
let week = date.iso_week();
|
||||||
|
let isoyear = week.year();
|
||||||
|
let isoweek = week.week();
|
||||||
|
let weekday = date.weekday();
|
||||||
let (isoyear_div_100, isoyear_mod_100) = if isoyear >= 0 {
|
let (isoyear_div_100, isoyear_mod_100) = if isoyear >= 0 {
|
||||||
let (q, r) = div_rem(isoyear, 100);
|
let (q, r) = div_rem(isoyear, 100);
|
||||||
(Some(q), Some(r))
|
(Some(q), Some(r))
|
||||||
|
|
37
src/lib.rs
37
src/lib.rs
|
@ -362,10 +362,10 @@ extern crate serde as serdelib;
|
||||||
pub use oldtime::Duration;
|
pub use oldtime::Duration;
|
||||||
|
|
||||||
#[doc(no_inline)] pub use offset::{TimeZone, Offset, LocalResult, UTC, FixedOffset, Local};
|
#[doc(no_inline)] pub use offset::{TimeZone, Offset, LocalResult, UTC, FixedOffset, Local};
|
||||||
#[doc(no_inline)] pub use naive::{NaiveDate, NaiveTime, NaiveDateTime};
|
#[doc(no_inline)] pub use naive::{NaiveDate, IsoWeek, NaiveTime, NaiveDateTime};
|
||||||
pub use date_::{Date, MIN_DATE, MAX_DATE};
|
pub use date::{Date, MIN_DATE, MAX_DATE};
|
||||||
pub use datetime_::DateTime;
|
pub use datetime::DateTime;
|
||||||
#[cfg(feature = "rustc-serialize")] pub use datetime_::TsSeconds;
|
#[cfg(feature = "rustc-serialize")] pub use datetime::TsSeconds;
|
||||||
pub use format::{ParseError, ParseResult};
|
pub use format::{ParseError, ParseResult};
|
||||||
|
|
||||||
/// A convenience module appropriate for glob imports (`use chrono::prelude::*;`).
|
/// A convenience module appropriate for glob imports (`use chrono::prelude::*;`).
|
||||||
|
@ -393,24 +393,24 @@ pub mod naive {
|
||||||
//! but can be also used for the simpler date and time handling.
|
//! but can be also used for the simpler date and time handling.
|
||||||
|
|
||||||
mod internals;
|
mod internals;
|
||||||
|
mod date;
|
||||||
|
mod isoweek;
|
||||||
|
mod time;
|
||||||
|
mod datetime;
|
||||||
|
|
||||||
// avoid using them directly even in the crate itself
|
pub use self::date::{NaiveDate, MIN_DATE, MAX_DATE};
|
||||||
#[path = "date.rs"] mod date_;
|
pub use self::isoweek::IsoWeek;
|
||||||
#[path = "time.rs"] mod time_;
|
pub use self::time::NaiveTime;
|
||||||
#[path = "datetime.rs"] mod datetime_;
|
pub use self::datetime::{NaiveDateTime, TsSeconds};
|
||||||
|
|
||||||
pub use self::date_::{NaiveDate, MIN_DATE, MAX_DATE};
|
|
||||||
pub use self::time_::NaiveTime;
|
|
||||||
pub use self::datetime_::{NaiveDateTime, TsSeconds};
|
|
||||||
|
|
||||||
/// Tools to help serializing/deserializing naive types.
|
/// Tools to help serializing/deserializing naive types.
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
pub mod serde {
|
pub mod serde {
|
||||||
pub use super::datetime_::serde::*;
|
pub use super::datetime::serde::*;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[path = "date.rs"] mod date_;
|
mod date;
|
||||||
#[path = "datetime.rs"] mod datetime_;
|
mod datetime;
|
||||||
pub mod format;
|
pub mod format;
|
||||||
|
|
||||||
/// Ser/de helpers
|
/// Ser/de helpers
|
||||||
|
@ -419,7 +419,7 @@ pub mod format;
|
||||||
/// annotation](https://serde.rs/attributes.html#field-attributes).
|
/// annotation](https://serde.rs/attributes.html#field-attributes).
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
pub mod serde {
|
pub mod serde {
|
||||||
pub use super::datetime_::serde::*;
|
pub use super::datetime::serde::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The day of week.
|
/// The day of week.
|
||||||
|
@ -761,9 +761,8 @@ pub trait Datelike: Sized {
|
||||||
/// Returns the day of week.
|
/// Returns the day of week.
|
||||||
fn weekday(&self) -> Weekday;
|
fn weekday(&self) -> Weekday;
|
||||||
|
|
||||||
/// Returns the ISO week date: an adjusted year, week number and day of week.
|
/// Returns the ISO week.
|
||||||
/// The adjusted year may differ from that of the calendar date.
|
fn iso_week(&self) -> IsoWeek;
|
||||||
fn isoweekdate(&self) -> (i32, u32, Weekday);
|
|
||||||
|
|
||||||
/// Makes a new value with the year number changed.
|
/// Makes a new value with the year number changed.
|
||||||
///
|
///
|
||||||
|
|
|
@ -10,10 +10,11 @@ use oldtime::Duration as OldDuration;
|
||||||
|
|
||||||
use {Weekday, Datelike};
|
use {Weekday, Datelike};
|
||||||
use div::div_mod_floor;
|
use div::div_mod_floor;
|
||||||
use naive::{NaiveTime, NaiveDateTime};
|
use naive::{NaiveTime, NaiveDateTime, IsoWeek};
|
||||||
use format::{Item, Numeric, Pad};
|
use format::{Item, Numeric, Pad};
|
||||||
use format::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItems};
|
use format::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItems};
|
||||||
|
|
||||||
|
use super::isoweek;
|
||||||
use super::internals::{self, DateImpl, Of, Mdf, YearFlags};
|
use super::internals::{self, DateImpl, Of, Mdf, YearFlags};
|
||||||
|
|
||||||
const MAX_YEAR: i32 = internals::MAX_YEAR;
|
const MAX_YEAR: i32 = internals::MAX_YEAR;
|
||||||
|
@ -81,7 +82,8 @@ const MAX_BITS: usize = 44;
|
||||||
/// For example, January 3, 2016 (Sunday) was on the last (53rd) week of 2015.
|
/// For example, January 3, 2016 (Sunday) was on the last (53rd) week of 2015.
|
||||||
///
|
///
|
||||||
/// Chrono's date types default to the ISO 8601 [calendar date](#calendar-date),
|
/// Chrono's date types default to the ISO 8601 [calendar date](#calendar-date),
|
||||||
/// but the [`Datelike::isoweekdate`](../trait.Datelike.html#tymethod.isoweekdate) method
|
/// but [`Datelike::iso_week`](../trait.Datelike.html#tymethod.iso_week) and
|
||||||
|
/// [`Datelike::weekday`](../trait.Datelike.html#tymethod.weekday) methods
|
||||||
/// can be used to get the corresponding week date.
|
/// can be used to get the corresponding week date.
|
||||||
///
|
///
|
||||||
/// # Ordinal Date
|
/// # Ordinal Date
|
||||||
|
@ -151,7 +153,9 @@ impl NaiveDate {
|
||||||
/// assert_eq!(d.month(), 3);
|
/// assert_eq!(d.month(), 3);
|
||||||
/// assert_eq!(d.day(), 14);
|
/// assert_eq!(d.day(), 14);
|
||||||
/// assert_eq!(d.ordinal(), 73); // day of year
|
/// assert_eq!(d.ordinal(), 73); // day of year
|
||||||
/// assert_eq!(d.isoweekdate(), (2015, 11, Weekday::Sat)); // ISO week and weekday
|
/// assert_eq!(d.iso_week().year(), 2015);
|
||||||
|
/// assert_eq!(d.iso_week().week(), 11);
|
||||||
|
/// assert_eq!(d.weekday(), Weekday::Sat);
|
||||||
/// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE
|
/// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE
|
||||||
/// ~~~~
|
/// ~~~~
|
||||||
pub fn from_ymd(year: i32, month: u32, day: u32) -> NaiveDate {
|
pub fn from_ymd(year: i32, month: u32, day: u32) -> NaiveDate {
|
||||||
|
@ -197,7 +201,9 @@ impl NaiveDate {
|
||||||
/// assert_eq!(d.year(), 2015);
|
/// assert_eq!(d.year(), 2015);
|
||||||
/// assert_eq!(d.month(), 3);
|
/// assert_eq!(d.month(), 3);
|
||||||
/// assert_eq!(d.day(), 14);
|
/// assert_eq!(d.day(), 14);
|
||||||
/// assert_eq!(d.isoweekdate(), (2015, 11, Weekday::Sat)); // ISO week and weekday
|
/// assert_eq!(d.iso_week().year(), 2015);
|
||||||
|
/// assert_eq!(d.iso_week().week(), 11);
|
||||||
|
/// assert_eq!(d.weekday(), Weekday::Sat);
|
||||||
/// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE
|
/// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE
|
||||||
/// ~~~~
|
/// ~~~~
|
||||||
pub fn from_yo(year: i32, ordinal: u32) -> NaiveDate {
|
pub fn from_yo(year: i32, ordinal: u32) -> NaiveDate {
|
||||||
|
@ -241,7 +247,9 @@ impl NaiveDate {
|
||||||
/// use chrono::{NaiveDate, Datelike, Weekday};
|
/// use chrono::{NaiveDate, Datelike, Weekday};
|
||||||
///
|
///
|
||||||
/// let d = NaiveDate::from_isoywd(2015, 11, Weekday::Sat);
|
/// let d = NaiveDate::from_isoywd(2015, 11, Weekday::Sat);
|
||||||
/// assert_eq!(d.isoweekdate(), (2015, 11, Weekday::Sat));
|
/// assert_eq!(d.iso_week().year(), 2015);
|
||||||
|
/// assert_eq!(d.iso_week().week(), 11);
|
||||||
|
/// assert_eq!(d.weekday(), Weekday::Sat);
|
||||||
/// assert_eq!(d.year(), 2015);
|
/// assert_eq!(d.year(), 2015);
|
||||||
/// assert_eq!(d.month(), 3);
|
/// assert_eq!(d.month(), 3);
|
||||||
/// assert_eq!(d.day(), 14);
|
/// assert_eq!(d.day(), 14);
|
||||||
|
@ -338,7 +346,9 @@ impl NaiveDate {
|
||||||
/// assert_eq!(d.month(), 3);
|
/// assert_eq!(d.month(), 3);
|
||||||
/// assert_eq!(d.day(), 14);
|
/// assert_eq!(d.day(), 14);
|
||||||
/// assert_eq!(d.ordinal(), 73); // day of year
|
/// assert_eq!(d.ordinal(), 73); // day of year
|
||||||
/// assert_eq!(d.isoweekdate(), (2015, 11, Weekday::Sat)); // ISO week and weekday
|
/// assert_eq!(d.iso_week().year(), 2015);
|
||||||
|
/// assert_eq!(d.iso_week().week(), 11);
|
||||||
|
/// assert_eq!(d.weekday(), Weekday::Sat);
|
||||||
/// ~~~~
|
/// ~~~~
|
||||||
///
|
///
|
||||||
/// While not directly supported by Chrono,
|
/// While not directly supported by Chrono,
|
||||||
|
@ -1128,21 +1138,9 @@ impl Datelike for NaiveDate {
|
||||||
self.of().weekday()
|
self.of().weekday()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn isoweekdate(&self) -> (i32, u32, Weekday) {
|
#[inline]
|
||||||
let of = self.of();
|
fn iso_week(&self) -> IsoWeek {
|
||||||
let year = self.year();
|
isoweek::iso_week_from_yof(self.year(), self.of())
|
||||||
let (rawweek, weekday) = of.isoweekdate_raw();
|
|
||||||
if rawweek < 1 { // previous year
|
|
||||||
let prevlastweek = YearFlags::from_year(year - 1).nisoweeks();
|
|
||||||
(year - 1, prevlastweek, weekday)
|
|
||||||
} else {
|
|
||||||
let lastweek = of.flags().nisoweeks();
|
|
||||||
if rawweek > lastweek { // next year
|
|
||||||
(year + 1, 1, weekday)
|
|
||||||
} else {
|
|
||||||
(year, rawweek, weekday)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a new `NaiveDate` with the year number changed.
|
/// Makes a new `NaiveDate` with the year number changed.
|
||||||
|
@ -1720,7 +1718,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date_from_isoywd_and_isoweekdate() {
|
fn test_date_from_isoywd_and_iso_week() {
|
||||||
for year in 2000..2401 {
|
for year in 2000..2401 {
|
||||||
for week in 1..54 {
|
for week in 1..54 {
|
||||||
for &weekday in [Weekday::Mon, Weekday::Tue, Weekday::Wed, Weekday::Thu,
|
for &weekday in [Weekday::Mon, Weekday::Tue, Weekday::Wed, Weekday::Thu,
|
||||||
|
@ -1729,10 +1727,9 @@ mod tests {
|
||||||
if d.is_some() {
|
if d.is_some() {
|
||||||
let d = d.unwrap();
|
let d = d.unwrap();
|
||||||
assert_eq!(d.weekday(), weekday);
|
assert_eq!(d.weekday(), weekday);
|
||||||
let (year_, week_, weekday_) = d.isoweekdate();
|
let w = d.iso_week();
|
||||||
assert_eq!(year_, year);
|
assert_eq!(w.year(), year);
|
||||||
assert_eq!(week_, week);
|
assert_eq!(w.week(), week);
|
||||||
assert_eq!(weekday_, weekday);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1744,8 +1741,8 @@ mod tests {
|
||||||
let d = NaiveDate::from_ymd_opt(year, month, day);
|
let d = NaiveDate::from_ymd_opt(year, month, day);
|
||||||
if d.is_some() {
|
if d.is_some() {
|
||||||
let d = d.unwrap();
|
let d = d.unwrap();
|
||||||
let (year_, week_, weekday_) = d.isoweekdate();
|
let w = d.iso_week();
|
||||||
let d_ = NaiveDate::from_isoywd(year_, week_, weekday_);
|
let d_ = NaiveDate::from_isoywd(w.year(), w.week(), d.weekday());
|
||||||
assert_eq!(d, d_);
|
assert_eq!(d, d_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use oldtime::Duration as OldDuration;
|
||||||
|
|
||||||
use {Weekday, Timelike, Datelike};
|
use {Weekday, Timelike, Datelike};
|
||||||
use div::div_mod_floor;
|
use div::div_mod_floor;
|
||||||
use naive::{NaiveTime, NaiveDate};
|
use naive::{NaiveTime, NaiveDate, IsoWeek};
|
||||||
use format::{Item, Numeric, Pad, Fixed};
|
use format::{Item, Numeric, Pad, Fixed};
|
||||||
use format::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItems};
|
use format::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItems};
|
||||||
|
|
||||||
|
@ -781,8 +781,8 @@ impl Datelike for NaiveDateTime {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn isoweekdate(&self) -> (i32, u32, Weekday) {
|
fn iso_week(&self) -> IsoWeek {
|
||||||
self.date.isoweekdate()
|
self.date.iso_week()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a new `NaiveDateTime` with the year number changed.
|
/// Makes a new `NaiveDateTime` with the year number changed.
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
// This is a part of Chrono.
|
||||||
|
// See README.md and LICENSE.txt for details.
|
||||||
|
|
||||||
|
//! ISO 8601 week.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use super::internals::{DateImpl, Of, YearFlags};
|
||||||
|
|
||||||
|
/// ISO 8601 week.
|
||||||
|
///
|
||||||
|
/// This type, combined with [`Weekday`](../enum.Weekday.html),
|
||||||
|
/// constitues the ISO 8601 [week date](./struct.NaiveDate.html#week-date).
|
||||||
|
/// One can retrieve this type from the existing [`Datelike`](../trait.Datelike.html) types
|
||||||
|
/// via the [`Datelike::iso_week`](../trait.Datelike.html#tymethod.iso_week) method.
|
||||||
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
|
||||||
|
pub struct IsoWeek {
|
||||||
|
// note that this allows for larger year range than `NaiveDate`.
|
||||||
|
// this is crucial because we have an edge case for the first and last week supported,
|
||||||
|
// which year number might not match the calendar year number.
|
||||||
|
ywf: DateImpl, // (year << 10) | (week << 4) | flag
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the corresponding `IsoWeek` from the year and the `Of` internal value.
|
||||||
|
//
|
||||||
|
// internal use only. we don't expose the public constructor for `IsoWeek` for now,
|
||||||
|
// because the year range for the week date and the calendar date do not match and
|
||||||
|
// it is confusing to have a date that is out of range in one and not in another.
|
||||||
|
// currently we sidestep this issue by making `IsoWeek` fully dependent of `Datelike`.
|
||||||
|
pub fn iso_week_from_yof(year: i32, of: Of) -> IsoWeek {
|
||||||
|
let (rawweek, _) = of.isoweekdate_raw();
|
||||||
|
let (year, week) = if rawweek < 1 { // previous year
|
||||||
|
let prevlastweek = YearFlags::from_year(year - 1).nisoweeks();
|
||||||
|
(year - 1, prevlastweek)
|
||||||
|
} else {
|
||||||
|
let lastweek = of.flags().nisoweeks();
|
||||||
|
if rawweek > lastweek { // next year
|
||||||
|
(year + 1, 1)
|
||||||
|
} else {
|
||||||
|
(year, rawweek)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
IsoWeek { ywf: (year << 10) | (week << 4) as DateImpl | of.flags().0 as DateImpl }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IsoWeek {
|
||||||
|
/// Returns the year number for this ISO week.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ~~~~
|
||||||
|
/// use chrono::{NaiveDate, Datelike, Weekday};
|
||||||
|
///
|
||||||
|
/// let d = NaiveDate::from_isoywd(2015, 1, Weekday::Mon);
|
||||||
|
/// assert_eq!(d.iso_week().year(), 2015);
|
||||||
|
/// ~~~~
|
||||||
|
///
|
||||||
|
/// This year number might not match the calendar year number.
|
||||||
|
/// Continuing the example...
|
||||||
|
///
|
||||||
|
/// ~~~~
|
||||||
|
/// # use chrono::{NaiveDate, Datelike, Weekday};
|
||||||
|
/// # let d = NaiveDate::from_isoywd(2015, 1, Weekday::Mon);
|
||||||
|
/// assert_eq!(d.year(), 2014);
|
||||||
|
/// assert_eq!(d, NaiveDate::from_ymd(2014, 12, 29));
|
||||||
|
/// ~~~~
|
||||||
|
#[inline]
|
||||||
|
pub fn year(&self) -> i32 {
|
||||||
|
self.ywf >> 10
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the ISO week number starting from 1.
|
||||||
|
///
|
||||||
|
/// The return value ranges from 1 to 53. (The last week of year differs by years.)
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ~~~~
|
||||||
|
/// use chrono::{NaiveDate, Datelike, Weekday};
|
||||||
|
///
|
||||||
|
/// let d = NaiveDate::from_isoywd(2015, 15, Weekday::Mon);
|
||||||
|
/// assert_eq!(d.iso_week().week(), 15);
|
||||||
|
/// ~~~~
|
||||||
|
#[inline]
|
||||||
|
pub fn week(&self) -> u32 {
|
||||||
|
((self.ywf >> 4) & 0x3f) as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the ISO week number starting from 0.
|
||||||
|
///
|
||||||
|
/// The return value ranges from 0 to 52. (The last week of year differs by years.)
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ~~~~
|
||||||
|
/// use chrono::{NaiveDate, Datelike, Weekday};
|
||||||
|
///
|
||||||
|
/// let d = NaiveDate::from_isoywd(2015, 15, Weekday::Mon);
|
||||||
|
/// assert_eq!(d.iso_week().week0(), 14);
|
||||||
|
/// ~~~~
|
||||||
|
#[inline]
|
||||||
|
pub fn week0(&self) -> u32 {
|
||||||
|
((self.ywf >> 4) & 0x3f) as u32 - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The `Debug` output of the ISO week `w` is same to
|
||||||
|
/// [`d.format("%G-W%V")`](../format/strftime/index.html)
|
||||||
|
/// where `d` is any `NaiveDate` value in that week.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ~~~~
|
||||||
|
/// use chrono::{NaiveDate, Datelike};
|
||||||
|
///
|
||||||
|
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(2015, 9, 5).iso_week()), "2015-W36");
|
||||||
|
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd( 0, 1, 3).iso_week()), "0000-W01");
|
||||||
|
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(9999, 12, 31).iso_week()), "9999-W52");
|
||||||
|
/// ~~~~
|
||||||
|
///
|
||||||
|
/// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE.
|
||||||
|
///
|
||||||
|
/// ~~~~
|
||||||
|
/// # use chrono::{NaiveDate, Datelike};
|
||||||
|
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd( 0, 1, 2).iso_week()), "-0001-W52");
|
||||||
|
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(10000, 12, 31).iso_week()), "+10000-W52");
|
||||||
|
/// ~~~~
|
||||||
|
impl fmt::Debug for IsoWeek {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let year = self.year();
|
||||||
|
let week = self.week();
|
||||||
|
if 0 <= year && year <= 9999 {
|
||||||
|
write!(f, "{:04}-W{:02}", year, week)
|
||||||
|
} else {
|
||||||
|
// ISO 8601 requires the explicit sign for out-of-range years
|
||||||
|
write!(f, "{:+05}-W{:02}", year, week)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use naive::{internals, MIN_DATE, MAX_DATE};
|
||||||
|
use Datelike;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_iso_week_extremes() {
|
||||||
|
let minweek = MIN_DATE.iso_week();
|
||||||
|
let maxweek = MAX_DATE.iso_week();
|
||||||
|
|
||||||
|
assert_eq!(minweek.year(), internals::MIN_YEAR);
|
||||||
|
assert_eq!(minweek.week(), 1);
|
||||||
|
assert_eq!(minweek.week0(), 0);
|
||||||
|
assert_eq!(format!("{:?}", minweek), MIN_DATE.format("%G-W%V").to_string());
|
||||||
|
|
||||||
|
assert_eq!(maxweek.year(), internals::MAX_YEAR + 1);
|
||||||
|
assert_eq!(maxweek.week(), 1);
|
||||||
|
assert_eq!(maxweek.week0(), 0);
|
||||||
|
assert_eq!(format!("{:?}", maxweek), MAX_DATE.format("%G-W%V").to_string());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue