major API surgeries.
- added a new example. - reexported all public APIs in the crate root. - made all constructors fail on the invalid arguments by default; `*_opt()` variants have been added for the original behavior. - same for `DateZ::{succ,pred}`. - fixed a missing overflow check from `TimeZ::from_hms_{milli,micro}`.
This commit is contained in:
parent
dce4ec8f45
commit
b79f6b302b
28
README.md
28
README.md
|
@ -8,6 +8,34 @@ Rust-chrono
|
||||||
|
|
||||||
Date and time handling for Rust.
|
Date and time handling for Rust.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// find out if the doomsday rule is correct!
|
||||||
|
use chrono::{MIN_YEAR, MAX_YEAR, Weekday, DateZ};
|
||||||
|
use std::iter::range_inclusive;
|
||||||
|
|
||||||
|
for y in range_inclusive(MIN_YEAR, MAX_YEAR) {
|
||||||
|
// even months
|
||||||
|
let d4 = DateZ::from_ymd(y, 4, 4);
|
||||||
|
let d6 = DateZ::from_ymd(y, 6, 6);
|
||||||
|
let d8 = DateZ::from_ymd(y, 8, 8);
|
||||||
|
let d10 = DateZ::from_ymd(y, 10, 10);
|
||||||
|
let d12 = DateZ::from_ymd(y, 12, 12);
|
||||||
|
|
||||||
|
// nine to five, seven-eleven
|
||||||
|
let d59 = DateZ::from_ymd(y, 5, 9);
|
||||||
|
let d95 = DateZ::from_ymd(y, 9, 5);
|
||||||
|
let d711 = DateZ::from_ymd(y, 7, 11);
|
||||||
|
let d117 = DateZ::from_ymd(y, 11, 7);
|
||||||
|
|
||||||
|
// "March 0"
|
||||||
|
let d30 = DateZ::from_ymd(y, 3, 1).pred();
|
||||||
|
|
||||||
|
let weekday = d30.weekday();
|
||||||
|
let other_dates = [d4, d6, d8, d10, d12, d59, d95, d711, d117];
|
||||||
|
assert!(other_dates.iter().all(|d| d.weekday() == weekday));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Design Goals
|
Design Goals
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|
273
src/date.rs
273
src/date.rs
|
@ -229,30 +229,55 @@ impl DateZ {
|
||||||
DateZ::from_of(year, mdf.to_of())
|
DateZ::from_of(year, mdf.to_of())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a new `DateZ` from year, month and day.
|
||||||
|
/// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE.
|
||||||
|
///
|
||||||
|
/// Fails on the out-of-range date, invalid month and/or day.
|
||||||
|
pub fn from_ymd(year: i32, month: u32, day: u32) -> DateZ {
|
||||||
|
DateZ::from_ymd_opt(year, month, day).expect("invalid or out-of-range date")
|
||||||
|
}
|
||||||
|
|
||||||
/// Makes a new `DateZ` from year, month and day.
|
/// Makes a new `DateZ` from year, month and day.
|
||||||
/// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE.
|
/// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE.
|
||||||
///
|
///
|
||||||
/// Returns `None` on the out-of-range date, invalid month and/or day.
|
/// Returns `None` on the out-of-range date, invalid month and/or day.
|
||||||
pub fn from_ymd(year: i32, month: u32, day: u32) -> Option<DateZ> {
|
pub fn from_ymd_opt(year: i32, month: u32, day: u32) -> Option<DateZ> {
|
||||||
let flags = YearFlags::from_year(year);
|
let flags = YearFlags::from_year(year);
|
||||||
DateZ::from_mdf(year, Mdf::new(month, day, flags))
|
DateZ::from_mdf(year, Mdf::new(month, day, flags))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a new `DateZ` from year and day of year (DOY or "ordinal").
|
||||||
|
/// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE.
|
||||||
|
///
|
||||||
|
/// Fails on the out-of-range date and/or invalid DOY.
|
||||||
|
pub fn from_yo(year: i32, ordinal: u32) -> DateZ {
|
||||||
|
DateZ::from_yo_opt(year, ordinal).expect("invalid or out-of-range date")
|
||||||
|
}
|
||||||
|
|
||||||
/// Makes a new `DateZ` from year and day of year (DOY or "ordinal").
|
/// Makes a new `DateZ` from year and day of year (DOY or "ordinal").
|
||||||
/// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE.
|
/// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE.
|
||||||
///
|
///
|
||||||
/// Returns `None` on the out-of-range date and/or invalid DOY.
|
/// Returns `None` on the out-of-range date and/or invalid DOY.
|
||||||
pub fn from_yo(year: i32, ordinal: u32) -> Option<DateZ> {
|
pub fn from_yo_opt(year: i32, ordinal: u32) -> Option<DateZ> {
|
||||||
let flags = YearFlags::from_year(year);
|
let flags = YearFlags::from_year(year);
|
||||||
DateZ::from_of(year, Of::new(ordinal, flags))
|
DateZ::from_of(year, Of::new(ordinal, flags))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a new `DateZ` from ISO week date (year and week number) and day of the week (DOW).
|
||||||
|
/// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE.
|
||||||
|
/// The resulting `DateZ` may have a different year from the input year.
|
||||||
|
///
|
||||||
|
/// Fails on the out-of-range date and/or invalid week number.
|
||||||
|
pub fn from_isoywd(year: i32, week: u32, weekday: Weekday) -> DateZ {
|
||||||
|
DateZ::from_isoywd_opt(year, week, weekday).expect("invalid or out-of-range date")
|
||||||
|
}
|
||||||
|
|
||||||
/// Makes a new `DateZ` from ISO week date (year and week number) and day of the week (DOW).
|
/// Makes a new `DateZ` from ISO week date (year and week number) and day of the week (DOW).
|
||||||
/// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE.
|
/// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE.
|
||||||
/// The resulting `DateZ` may have a different year from the input year.
|
/// The resulting `DateZ` may have a different year from the input year.
|
||||||
///
|
///
|
||||||
/// Returns `None` on the out-of-range date and/or invalid week number.
|
/// Returns `None` on the out-of-range date and/or invalid week number.
|
||||||
pub fn from_isoywd(year: i32, week: u32, weekday: Weekday) -> Option<DateZ> {
|
pub fn from_isoywd_opt(year: i32, week: u32, weekday: Weekday) -> Option<DateZ> {
|
||||||
let flags = YearFlags::from_year(year);
|
let flags = YearFlags::from_year(year);
|
||||||
let nweeks = flags.nisoweeks();
|
let nweeks = flags.nisoweeks();
|
||||||
if 1 <= week && week <= nweeks {
|
if 1 <= week && week <= nweeks {
|
||||||
|
@ -310,14 +335,36 @@ impl DateZ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a new `DateZ` for the next date.
|
||||||
|
///
|
||||||
|
/// Fails when `self` is the last representable date.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn succ(&self) -> Option<DateZ> {
|
pub fn succ(&self) -> DateZ {
|
||||||
self.with_of(self.of().succ()).or_else(|| DateZ::from_ymd(self.year() + 1, 1, 1))
|
self.succ_opt().expect("out of bound")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a new `DateZ` for the next date.
|
||||||
|
///
|
||||||
|
/// Returns `None` when `self` is the last representable date.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn pred(&self) -> Option<DateZ> {
|
pub fn succ_opt(&self) -> Option<DateZ> {
|
||||||
self.with_of(self.of().pred()).or_else(|| DateZ::from_ymd(self.year() - 1, 12, 31))
|
self.with_of(self.of().succ()).or_else(|| DateZ::from_ymd_opt(self.year() + 1, 1, 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes a new `DateZ` for the prior date.
|
||||||
|
///
|
||||||
|
/// Fails when `self` is the first representable date.
|
||||||
|
#[inline]
|
||||||
|
pub fn pred(&self) -> DateZ {
|
||||||
|
self.pred_opt().expect("out of bound")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes a new `DateZ` for the prior date.
|
||||||
|
///
|
||||||
|
/// Returns `None` when `self` is the first representable date.
|
||||||
|
#[inline]
|
||||||
|
pub fn pred_opt(&self) -> Option<DateZ> {
|
||||||
|
self.with_of(self.of().pred()).or_else(|| DateZ::from_ymd_opt(self.year() - 1, 12, 31))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,69 +497,69 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date_from_ymd() {
|
fn test_date_from_ymd() {
|
||||||
assert!(DateZ::from_ymd(2012, 0, 1).is_none());
|
assert!(DateZ::from_ymd_opt(2012, 0, 1).is_none());
|
||||||
assert!(DateZ::from_ymd(2012, 1, 1).is_some());
|
assert!(DateZ::from_ymd_opt(2012, 1, 1).is_some());
|
||||||
assert!(DateZ::from_ymd(2012, 2, 29).is_some());
|
assert!(DateZ::from_ymd_opt(2012, 2, 29).is_some());
|
||||||
assert!(DateZ::from_ymd(2014, 2, 29).is_none());
|
assert!(DateZ::from_ymd_opt(2014, 2, 29).is_none());
|
||||||
assert!(DateZ::from_ymd(2014, 3, 0).is_none());
|
assert!(DateZ::from_ymd_opt(2014, 3, 0).is_none());
|
||||||
assert!(DateZ::from_ymd(2014, 3, 1).is_some());
|
assert!(DateZ::from_ymd_opt(2014, 3, 1).is_some());
|
||||||
assert!(DateZ::from_ymd(2014, 3, 31).is_some());
|
assert!(DateZ::from_ymd_opt(2014, 3, 31).is_some());
|
||||||
assert!(DateZ::from_ymd(2014, 3, 32).is_none());
|
assert!(DateZ::from_ymd_opt(2014, 3, 32).is_none());
|
||||||
assert!(DateZ::from_ymd(2014, 12, 31).is_some());
|
assert!(DateZ::from_ymd_opt(2014, 12, 31).is_some());
|
||||||
assert!(DateZ::from_ymd(2014, 13, 1).is_none());
|
assert!(DateZ::from_ymd_opt(2014, 13, 1).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date_from_yo() {
|
fn test_date_from_yo() {
|
||||||
assert!(DateZ::from_yo(2012, 0).is_none());
|
assert_eq!(DateZ::from_yo_opt(2012, 0), None);
|
||||||
assert_eq!(DateZ::from_yo(2012, 1), DateZ::from_ymd(2012, 1, 1));
|
assert_eq!(DateZ::from_yo_opt(2012, 1), Some(DateZ::from_ymd(2012, 1, 1)));
|
||||||
assert_eq!(DateZ::from_yo(2012, 2), DateZ::from_ymd(2012, 1, 2));
|
assert_eq!(DateZ::from_yo_opt(2012, 2), Some(DateZ::from_ymd(2012, 1, 2)));
|
||||||
assert_eq!(DateZ::from_yo(2012, 32), DateZ::from_ymd(2012, 2, 1));
|
assert_eq!(DateZ::from_yo_opt(2012, 32), Some(DateZ::from_ymd(2012, 2, 1)));
|
||||||
assert_eq!(DateZ::from_yo(2012, 60), DateZ::from_ymd(2012, 2, 29));
|
assert_eq!(DateZ::from_yo_opt(2012, 60), Some(DateZ::from_ymd(2012, 2, 29)));
|
||||||
assert_eq!(DateZ::from_yo(2012, 61), DateZ::from_ymd(2012, 3, 1));
|
assert_eq!(DateZ::from_yo_opt(2012, 61), Some(DateZ::from_ymd(2012, 3, 1)));
|
||||||
assert_eq!(DateZ::from_yo(2012, 100), DateZ::from_ymd(2012, 4, 9));
|
assert_eq!(DateZ::from_yo_opt(2012, 100), Some(DateZ::from_ymd(2012, 4, 9)));
|
||||||
assert_eq!(DateZ::from_yo(2012, 200), DateZ::from_ymd(2012, 7, 18));
|
assert_eq!(DateZ::from_yo_opt(2012, 200), Some(DateZ::from_ymd(2012, 7, 18)));
|
||||||
assert_eq!(DateZ::from_yo(2012, 300), DateZ::from_ymd(2012, 10, 26));
|
assert_eq!(DateZ::from_yo_opt(2012, 300), Some(DateZ::from_ymd(2012, 10, 26)));
|
||||||
assert_eq!(DateZ::from_yo(2012, 366), DateZ::from_ymd(2012, 12, 31));
|
assert_eq!(DateZ::from_yo_opt(2012, 366), Some(DateZ::from_ymd(2012, 12, 31)));
|
||||||
assert!(DateZ::from_yo(2012, 367).is_none());
|
assert_eq!(DateZ::from_yo_opt(2012, 367), None);
|
||||||
|
|
||||||
assert!(DateZ::from_yo(2014, 0).is_none());
|
assert_eq!(DateZ::from_yo_opt(2014, 0), None);
|
||||||
assert_eq!(DateZ::from_yo(2014, 1), DateZ::from_ymd(2014, 1, 1));
|
assert_eq!(DateZ::from_yo_opt(2014, 1), Some(DateZ::from_ymd(2014, 1, 1)));
|
||||||
assert_eq!(DateZ::from_yo(2014, 2), DateZ::from_ymd(2014, 1, 2));
|
assert_eq!(DateZ::from_yo_opt(2014, 2), Some(DateZ::from_ymd(2014, 1, 2)));
|
||||||
assert_eq!(DateZ::from_yo(2014, 32), DateZ::from_ymd(2014, 2, 1));
|
assert_eq!(DateZ::from_yo_opt(2014, 32), Some(DateZ::from_ymd(2014, 2, 1)));
|
||||||
assert_eq!(DateZ::from_yo(2014, 59), DateZ::from_ymd(2014, 2, 28));
|
assert_eq!(DateZ::from_yo_opt(2014, 59), Some(DateZ::from_ymd(2014, 2, 28)));
|
||||||
assert_eq!(DateZ::from_yo(2014, 60), DateZ::from_ymd(2014, 3, 1));
|
assert_eq!(DateZ::from_yo_opt(2014, 60), Some(DateZ::from_ymd(2014, 3, 1)));
|
||||||
assert_eq!(DateZ::from_yo(2014, 100), DateZ::from_ymd(2014, 4, 10));
|
assert_eq!(DateZ::from_yo_opt(2014, 100), Some(DateZ::from_ymd(2014, 4, 10)));
|
||||||
assert_eq!(DateZ::from_yo(2014, 200), DateZ::from_ymd(2014, 7, 19));
|
assert_eq!(DateZ::from_yo_opt(2014, 200), Some(DateZ::from_ymd(2014, 7, 19)));
|
||||||
assert_eq!(DateZ::from_yo(2014, 300), DateZ::from_ymd(2014, 10, 27));
|
assert_eq!(DateZ::from_yo_opt(2014, 300), Some(DateZ::from_ymd(2014, 10, 27)));
|
||||||
assert_eq!(DateZ::from_yo(2014, 365), DateZ::from_ymd(2014, 12, 31));
|
assert_eq!(DateZ::from_yo_opt(2014, 365), Some(DateZ::from_ymd(2014, 12, 31)));
|
||||||
assert!(DateZ::from_yo(2014, 366).is_none());
|
assert_eq!(DateZ::from_yo_opt(2014, 366), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date_from_isoywd() {
|
fn test_date_from_isoywd() {
|
||||||
assert!(DateZ::from_isoywd(2004, 0, Sun).is_none());
|
assert_eq!(DateZ::from_isoywd_opt(2004, 0, Sun), None);
|
||||||
assert_eq!(DateZ::from_isoywd(2004, 1, Mon), DateZ::from_ymd(2003, 12, 29));
|
assert_eq!(DateZ::from_isoywd_opt(2004, 1, Mon), Some(DateZ::from_ymd(2003, 12, 29)));
|
||||||
assert_eq!(DateZ::from_isoywd(2004, 1, Sun), DateZ::from_ymd(2004, 1, 4));
|
assert_eq!(DateZ::from_isoywd_opt(2004, 1, Sun), Some(DateZ::from_ymd(2004, 1, 4)));
|
||||||
assert_eq!(DateZ::from_isoywd(2004, 2, Mon), DateZ::from_ymd(2004, 1, 5));
|
assert_eq!(DateZ::from_isoywd_opt(2004, 2, Mon), Some(DateZ::from_ymd(2004, 1, 5)));
|
||||||
assert_eq!(DateZ::from_isoywd(2004, 2, Sun), DateZ::from_ymd(2004, 1, 11));
|
assert_eq!(DateZ::from_isoywd_opt(2004, 2, Sun), Some(DateZ::from_ymd(2004, 1, 11)));
|
||||||
assert_eq!(DateZ::from_isoywd(2004, 52, Mon), DateZ::from_ymd(2004, 12, 20));
|
assert_eq!(DateZ::from_isoywd_opt(2004, 52, Mon), Some(DateZ::from_ymd(2004, 12, 20)));
|
||||||
assert_eq!(DateZ::from_isoywd(2004, 52, Sun), DateZ::from_ymd(2004, 12, 26));
|
assert_eq!(DateZ::from_isoywd_opt(2004, 52, Sun), Some(DateZ::from_ymd(2004, 12, 26)));
|
||||||
assert_eq!(DateZ::from_isoywd(2004, 53, Mon), DateZ::from_ymd(2004, 12, 27));
|
assert_eq!(DateZ::from_isoywd_opt(2004, 53, Mon), Some(DateZ::from_ymd(2004, 12, 27)));
|
||||||
assert_eq!(DateZ::from_isoywd(2004, 53, Sun), DateZ::from_ymd(2005, 1, 2));
|
assert_eq!(DateZ::from_isoywd_opt(2004, 53, Sun), Some(DateZ::from_ymd(2005, 1, 2)));
|
||||||
assert!(DateZ::from_isoywd(2004, 54, Mon).is_none());
|
assert_eq!(DateZ::from_isoywd_opt(2004, 54, Mon), None);
|
||||||
|
|
||||||
assert!(DateZ::from_isoywd(2011, 0, Sun).is_none());
|
assert_eq!(DateZ::from_isoywd_opt(2011, 0, Sun), None);
|
||||||
assert_eq!(DateZ::from_isoywd(2011, 1, Mon), DateZ::from_ymd(2011, 1, 3));
|
assert_eq!(DateZ::from_isoywd_opt(2011, 1, Mon), Some(DateZ::from_ymd(2011, 1, 3)));
|
||||||
assert_eq!(DateZ::from_isoywd(2011, 1, Sun), DateZ::from_ymd(2011, 1, 9));
|
assert_eq!(DateZ::from_isoywd_opt(2011, 1, Sun), Some(DateZ::from_ymd(2011, 1, 9)));
|
||||||
assert_eq!(DateZ::from_isoywd(2011, 2, Mon), DateZ::from_ymd(2011, 1, 10));
|
assert_eq!(DateZ::from_isoywd_opt(2011, 2, Mon), Some(DateZ::from_ymd(2011, 1, 10)));
|
||||||
assert_eq!(DateZ::from_isoywd(2011, 2, Sun), DateZ::from_ymd(2011, 1, 16));
|
assert_eq!(DateZ::from_isoywd_opt(2011, 2, Sun), Some(DateZ::from_ymd(2011, 1, 16)));
|
||||||
|
|
||||||
assert_eq!(DateZ::from_isoywd(2018, 51, Mon), DateZ::from_ymd(2018, 12, 17));
|
assert_eq!(DateZ::from_isoywd_opt(2018, 51, Mon), Some(DateZ::from_ymd(2018, 12, 17)));
|
||||||
assert_eq!(DateZ::from_isoywd(2018, 51, Sun), DateZ::from_ymd(2018, 12, 23));
|
assert_eq!(DateZ::from_isoywd_opt(2018, 51, Sun), Some(DateZ::from_ymd(2018, 12, 23)));
|
||||||
assert_eq!(DateZ::from_isoywd(2018, 52, Mon), DateZ::from_ymd(2018, 12, 24));
|
assert_eq!(DateZ::from_isoywd_opt(2018, 52, Mon), Some(DateZ::from_ymd(2018, 12, 24)));
|
||||||
assert_eq!(DateZ::from_isoywd(2018, 52, Sun), DateZ::from_ymd(2018, 12, 30));
|
assert_eq!(DateZ::from_isoywd_opt(2018, 52, Sun), Some(DateZ::from_ymd(2018, 12, 30)));
|
||||||
assert!(DateZ::from_isoywd(2018, 53, Mon).is_none());
|
assert_eq!(DateZ::from_isoywd_opt(2018, 53, Mon), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -520,7 +567,7 @@ mod tests {
|
||||||
for year in range_inclusive(2000i32, 2400) {
|
for year in range_inclusive(2000i32, 2400) {
|
||||||
for week in range_inclusive(1u32, 53) {
|
for week in range_inclusive(1u32, 53) {
|
||||||
for &weekday in [Mon, Tue, Wed, Thu, Fri, Sat, Sun].iter() {
|
for &weekday in [Mon, Tue, Wed, Thu, Fri, Sat, Sun].iter() {
|
||||||
let d = DateZ::from_isoywd(year, week, weekday);
|
let d = DateZ::from_isoywd_opt(year, week, weekday);
|
||||||
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);
|
||||||
|
@ -536,11 +583,11 @@ mod tests {
|
||||||
for year in range_inclusive(2000i32, 2400) {
|
for year in range_inclusive(2000i32, 2400) {
|
||||||
for month in range_inclusive(1u32, 12) {
|
for month in range_inclusive(1u32, 12) {
|
||||||
for day in range_inclusive(1u32, 31) {
|
for day in range_inclusive(1u32, 31) {
|
||||||
let d = DateZ::from_ymd(year, month, day);
|
let d = DateZ::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 (year_, week_, weekday_) = d.isoweekdate();
|
||||||
let d_ = DateZ::from_isoywd(year_, week_, weekday_).unwrap();
|
let d_ = DateZ::from_isoywd(year_, week_, weekday_);
|
||||||
assert_eq!(d, d_);
|
assert_eq!(d, d_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -552,18 +599,16 @@ mod tests {
|
||||||
fn test_date_fields() {
|
fn test_date_fields() {
|
||||||
fn check(year: i32, month: u32, day: u32, ordinal: u32) {
|
fn check(year: i32, month: u32, day: u32, ordinal: u32) {
|
||||||
let d1 = DateZ::from_ymd(year, month, day);
|
let d1 = DateZ::from_ymd(year, month, day);
|
||||||
assert!(d1.is_some());
|
assert_eq!(d1.year(), year);
|
||||||
assert_eq!(d1.unwrap().year(), year);
|
assert_eq!(d1.month(), month);
|
||||||
assert_eq!(d1.unwrap().month(), month);
|
assert_eq!(d1.day(), day);
|
||||||
assert_eq!(d1.unwrap().day(), day);
|
assert_eq!(d1.ordinal(), ordinal);
|
||||||
assert_eq!(d1.unwrap().ordinal(), ordinal);
|
|
||||||
|
|
||||||
let d2 = DateZ::from_yo(year, ordinal);
|
let d2 = DateZ::from_yo(year, ordinal);
|
||||||
assert!(d2.is_some());
|
assert_eq!(d2.year(), year);
|
||||||
assert_eq!(d2.unwrap().year(), year);
|
assert_eq!(d2.month(), month);
|
||||||
assert_eq!(d2.unwrap().month(), month);
|
assert_eq!(d2.day(), day);
|
||||||
assert_eq!(d2.unwrap().day(), day);
|
assert_eq!(d2.ordinal(), ordinal);
|
||||||
assert_eq!(d2.unwrap().ordinal(), ordinal);
|
|
||||||
|
|
||||||
assert_eq!(d1, d2);
|
assert_eq!(d1, d2);
|
||||||
}
|
}
|
||||||
|
@ -591,83 +636,83 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date_weekday() {
|
fn test_date_weekday() {
|
||||||
assert_eq!(DateZ::from_ymd(1582, 10, 15).unwrap().weekday(), Fri);
|
assert_eq!(DateZ::from_ymd(1582, 10, 15).weekday(), Fri);
|
||||||
assert_eq!(DateZ::from_ymd(1875, 5, 20).unwrap().weekday(), Thu); // ISO 8601 reference date
|
assert_eq!(DateZ::from_ymd(1875, 5, 20).weekday(), Thu); // ISO 8601 reference date
|
||||||
assert_eq!(DateZ::from_ymd(2000, 1, 1).unwrap().weekday(), Sat);
|
assert_eq!(DateZ::from_ymd(2000, 1, 1).weekday(), Sat);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date_with_fields() {
|
fn test_date_with_fields() {
|
||||||
let d = DateZ::from_ymd(2000, 2, 29).unwrap();
|
let d = DateZ::from_ymd(2000, 2, 29);
|
||||||
assert_eq!(d.with_year(-400), DateZ::from_ymd(-400, 2, 29));
|
assert_eq!(d.with_year(-400), Some(DateZ::from_ymd(-400, 2, 29)));
|
||||||
assert_eq!(d.with_year(-100), None);
|
assert_eq!(d.with_year(-100), None);
|
||||||
assert_eq!(d.with_year(1600), DateZ::from_ymd(1600, 2, 29));
|
assert_eq!(d.with_year(1600), Some(DateZ::from_ymd(1600, 2, 29)));
|
||||||
assert_eq!(d.with_year(1900), None);
|
assert_eq!(d.with_year(1900), None);
|
||||||
assert_eq!(d.with_year(2000), DateZ::from_ymd(2000, 2, 29));
|
assert_eq!(d.with_year(2000), Some(DateZ::from_ymd(2000, 2, 29)));
|
||||||
assert_eq!(d.with_year(2001), None);
|
assert_eq!(d.with_year(2001), None);
|
||||||
assert_eq!(d.with_year(2004), DateZ::from_ymd(2004, 2, 29));
|
assert_eq!(d.with_year(2004), Some(DateZ::from_ymd(2004, 2, 29)));
|
||||||
assert_eq!(d.with_year(i32::MAX), None);
|
assert_eq!(d.with_year(i32::MAX), None);
|
||||||
|
|
||||||
let d = DateZ::from_ymd(2000, 4, 30).unwrap();
|
let d = DateZ::from_ymd(2000, 4, 30);
|
||||||
assert_eq!(d.with_month(0), None);
|
assert_eq!(d.with_month(0), None);
|
||||||
assert_eq!(d.with_month(1), DateZ::from_ymd(2000, 1, 30));
|
assert_eq!(d.with_month(1), Some(DateZ::from_ymd(2000, 1, 30)));
|
||||||
assert_eq!(d.with_month(2), None);
|
assert_eq!(d.with_month(2), None);
|
||||||
assert_eq!(d.with_month(3), DateZ::from_ymd(2000, 3, 30));
|
assert_eq!(d.with_month(3), Some(DateZ::from_ymd(2000, 3, 30)));
|
||||||
assert_eq!(d.with_month(4), DateZ::from_ymd(2000, 4, 30));
|
assert_eq!(d.with_month(4), Some(DateZ::from_ymd(2000, 4, 30)));
|
||||||
assert_eq!(d.with_month(12), DateZ::from_ymd(2000, 12, 30));
|
assert_eq!(d.with_month(12), Some(DateZ::from_ymd(2000, 12, 30)));
|
||||||
assert_eq!(d.with_month(13), None);
|
assert_eq!(d.with_month(13), None);
|
||||||
assert_eq!(d.with_month(u32::MAX), None);
|
assert_eq!(d.with_month(u32::MAX), None);
|
||||||
|
|
||||||
let d = DateZ::from_ymd(2000, 2, 8).unwrap();
|
let d = DateZ::from_ymd(2000, 2, 8);
|
||||||
assert_eq!(d.with_day(0), None);
|
assert_eq!(d.with_day(0), None);
|
||||||
assert_eq!(d.with_day(1), DateZ::from_ymd(2000, 2, 1));
|
assert_eq!(d.with_day(1), Some(DateZ::from_ymd(2000, 2, 1)));
|
||||||
assert_eq!(d.with_day(29), DateZ::from_ymd(2000, 2, 29));
|
assert_eq!(d.with_day(29), Some(DateZ::from_ymd(2000, 2, 29)));
|
||||||
assert_eq!(d.with_day(30), None);
|
assert_eq!(d.with_day(30), None);
|
||||||
assert_eq!(d.with_day(u32::MAX), None);
|
assert_eq!(d.with_day(u32::MAX), None);
|
||||||
|
|
||||||
let d = DateZ::from_ymd(2000, 5, 5).unwrap();
|
let d = DateZ::from_ymd(2000, 5, 5);
|
||||||
assert_eq!(d.with_ordinal(0), None);
|
assert_eq!(d.with_ordinal(0), None);
|
||||||
assert_eq!(d.with_ordinal(1), DateZ::from_ymd(2000, 1, 1));
|
assert_eq!(d.with_ordinal(1), Some(DateZ::from_ymd(2000, 1, 1)));
|
||||||
assert_eq!(d.with_ordinal(60), DateZ::from_ymd(2000, 2, 29));
|
assert_eq!(d.with_ordinal(60), Some(DateZ::from_ymd(2000, 2, 29)));
|
||||||
assert_eq!(d.with_ordinal(61), DateZ::from_ymd(2000, 3, 1));
|
assert_eq!(d.with_ordinal(61), Some(DateZ::from_ymd(2000, 3, 1)));
|
||||||
assert_eq!(d.with_ordinal(366), DateZ::from_ymd(2000, 12, 31));
|
assert_eq!(d.with_ordinal(366), Some(DateZ::from_ymd(2000, 12, 31)));
|
||||||
assert_eq!(d.with_ordinal(367), None);
|
assert_eq!(d.with_ordinal(367), None);
|
||||||
assert_eq!(d.with_ordinal(u32::MAX), None);
|
assert_eq!(d.with_ordinal(u32::MAX), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date_ndays_from_ce() {
|
fn test_date_ndays_from_ce() {
|
||||||
assert_eq!(DateZ::from_ymd(1, 1, 1).unwrap().ndays_from_ce(), 1);
|
assert_eq!(DateZ::from_ymd(1, 1, 1).ndays_from_ce(), 1);
|
||||||
|
|
||||||
for year in range_inclusive(-9999i32, 10000) {
|
for year in range_inclusive(-9999i32, 10000) {
|
||||||
assert_eq!(DateZ::from_ymd(year, 1, 1).unwrap().ndays_from_ce(),
|
assert_eq!(DateZ::from_ymd(year, 1, 1).ndays_from_ce(),
|
||||||
DateZ::from_ymd(year - 1, 12, 31).unwrap().ndays_from_ce() + 1);
|
DateZ::from_ymd(year - 1, 12, 31).ndays_from_ce() + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date_succ() {
|
fn test_date_succ() {
|
||||||
assert_eq!(DateZ::from_ymd(2014, 5, 6).unwrap().succ(), DateZ::from_ymd(2014, 5, 7));
|
assert_eq!(DateZ::from_ymd(2014, 5, 6).succ_opt(), Some(DateZ::from_ymd(2014, 5, 7)));
|
||||||
assert_eq!(DateZ::from_ymd(2014, 5, 31).unwrap().succ(), DateZ::from_ymd(2014, 6, 1));
|
assert_eq!(DateZ::from_ymd(2014, 5, 31).succ_opt(), Some(DateZ::from_ymd(2014, 6, 1)));
|
||||||
assert_eq!(DateZ::from_ymd(2014, 12, 31).unwrap().succ(), DateZ::from_ymd(2015, 1, 1));
|
assert_eq!(DateZ::from_ymd(2014, 12, 31).succ_opt(), Some(DateZ::from_ymd(2015, 1, 1)));
|
||||||
assert_eq!(DateZ::from_ymd(2016, 2, 28).unwrap().succ(), DateZ::from_ymd(2016, 2, 29));
|
assert_eq!(DateZ::from_ymd(2016, 2, 28).succ_opt(), Some(DateZ::from_ymd(2016, 2, 29)));
|
||||||
assert_eq!(DateZ::from_ymd(MAX_YEAR, 12, 31).unwrap().succ(), None);
|
assert_eq!(DateZ::from_ymd(MAX_YEAR, 12, 31).succ_opt(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date_pred() {
|
fn test_date_pred() {
|
||||||
assert_eq!(DateZ::from_ymd(2016, 3, 1).unwrap().pred(), DateZ::from_ymd(2016, 2, 29));
|
assert_eq!(DateZ::from_ymd(2016, 3, 1).pred_opt(), Some(DateZ::from_ymd(2016, 2, 29)));
|
||||||
assert_eq!(DateZ::from_ymd(2015, 1, 1).unwrap().pred(), DateZ::from_ymd(2014, 12, 31));
|
assert_eq!(DateZ::from_ymd(2015, 1, 1).pred_opt(), Some(DateZ::from_ymd(2014, 12, 31)));
|
||||||
assert_eq!(DateZ::from_ymd(2014, 6, 1).unwrap().pred(), DateZ::from_ymd(2014, 5, 31));
|
assert_eq!(DateZ::from_ymd(2014, 6, 1).pred_opt(), Some(DateZ::from_ymd(2014, 5, 31)));
|
||||||
assert_eq!(DateZ::from_ymd(2014, 5, 7).unwrap().pred(), DateZ::from_ymd(2014, 5, 6));
|
assert_eq!(DateZ::from_ymd(2014, 5, 7).pred_opt(), Some(DateZ::from_ymd(2014, 5, 6)));
|
||||||
assert_eq!(DateZ::from_ymd(MIN_YEAR, 1, 1).unwrap().pred(), None);
|
assert_eq!(DateZ::from_ymd(MIN_YEAR, 1, 1).pred_opt(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date_add() {
|
fn test_date_add() {
|
||||||
fn check((y1,m1,d1): (i32, u32, u32), rhs: Duration, (y,m,d): (i32, u32, u32)) {
|
fn check((y1,m1,d1): (i32, u32, u32), rhs: Duration, (y,m,d): (i32, u32, u32)) {
|
||||||
let lhs = DateZ::from_ymd(y1, m1, d1).unwrap();
|
let lhs = DateZ::from_ymd(y1, m1, d1);
|
||||||
let sum = DateZ::from_ymd(y, m, d).unwrap();
|
let sum = DateZ::from_ymd(y, m, d);
|
||||||
assert_eq!(lhs + rhs, sum);
|
assert_eq!(lhs + rhs, sum);
|
||||||
//assert_eq!(rhs + lhs, sum);
|
//assert_eq!(rhs + lhs, sum);
|
||||||
}
|
}
|
||||||
|
@ -686,8 +731,8 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date_sub() {
|
fn test_date_sub() {
|
||||||
fn check((y1,m1,d1): (i32, u32, u32), (y2,m2,d2): (i32, u32, u32), diff: Duration) {
|
fn check((y1,m1,d1): (i32, u32, u32), (y2,m2,d2): (i32, u32, u32), diff: Duration) {
|
||||||
let lhs = DateZ::from_ymd(y1, m1, d1).unwrap();
|
let lhs = DateZ::from_ymd(y1, m1, d1);
|
||||||
let rhs = DateZ::from_ymd(y2, m2, d2).unwrap();
|
let rhs = DateZ::from_ymd(y2, m2, d2);
|
||||||
assert_eq!(lhs - rhs, diff);
|
assert_eq!(lhs - rhs, diff);
|
||||||
assert_eq!(rhs - lhs, -diff);
|
assert_eq!(rhs - lhs, -diff);
|
||||||
}
|
}
|
||||||
|
@ -702,10 +747,10 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date_fmt() {
|
fn test_date_fmt() {
|
||||||
assert_eq!(DateZ::from_ymd(2012, 3, 4).unwrap().to_string(), "2012-03-04".to_string());
|
assert_eq!(DateZ::from_ymd(2012, 3, 4).to_string(), "2012-03-04".to_string());
|
||||||
assert_eq!(DateZ::from_ymd(0, 3, 4).unwrap().to_string(), "0000-03-04".to_string());
|
assert_eq!(DateZ::from_ymd(0, 3, 4).to_string(), "0000-03-04".to_string());
|
||||||
assert_eq!(DateZ::from_ymd(-307, 3, 4).unwrap().to_string(), "-0307-03-04".to_string());
|
assert_eq!(DateZ::from_ymd(-307, 3, 4).to_string(), "-0307-03-04".to_string());
|
||||||
assert_eq!(DateZ::from_ymd(12345, 3, 4).unwrap().to_string(), "+12345-03-04".to_string());
|
assert_eq!(DateZ::from_ymd(12345, 3, 4).to_string(), "+12345-03-04".to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,15 @@ impl DateTimeZ {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_ymdhms(year: i32, month: u32, day: u32,
|
pub fn from_ymdhms(year: i32, month: u32, day: u32,
|
||||||
hour: u32, min: u32, sec: u32) -> Option<DateTimeZ> {
|
hour: u32, min: u32, sec: u32) -> DateTimeZ {
|
||||||
match (DateZ::from_ymd(year, month, day), TimeZ::from_hms(hour, min, sec)) {
|
let dt = DateTimeZ::from_ymdhms_opt(year, month, day, hour, min, sec);
|
||||||
|
dt.expect("invalid or out-of-range date or time")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_ymdhms_opt(year: i32, month: u32, day: u32,
|
||||||
|
hour: u32, min: u32, sec: u32) -> Option<DateTimeZ> {
|
||||||
|
match (DateZ::from_ymd_opt(year, month, day), TimeZ::from_hms_opt(hour, min, sec)) {
|
||||||
(Some(d), Some(t)) => Some(DateTimeZ::new(d, t)),
|
(Some(d), Some(t)) => Some(DateTimeZ::new(d, t)),
|
||||||
(_, _) => None,
|
(_, _) => None,
|
||||||
}
|
}
|
||||||
|
@ -34,8 +41,15 @@ impl DateTimeZ {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_yohms(year: i32, ordinal: u32,
|
pub fn from_yohms(year: i32, ordinal: u32,
|
||||||
hour: u32, min: u32, sec: u32) -> Option<DateTimeZ> {
|
hour: u32, min: u32, sec: u32) -> DateTimeZ {
|
||||||
match (DateZ::from_yo(year, ordinal), TimeZ::from_hms(hour, min, sec)) {
|
let dt = DateTimeZ::from_yohms_opt(year, ordinal, hour, min, sec);
|
||||||
|
dt.expect("invalid or out-of-range date or time")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_yohms_opt(year: i32, ordinal: u32,
|
||||||
|
hour: u32, min: u32, sec: u32) -> Option<DateTimeZ> {
|
||||||
|
match (DateZ::from_yo_opt(year, ordinal), TimeZ::from_hms_opt(hour, min, sec)) {
|
||||||
(Some(d), Some(t)) => Some(DateTimeZ::new(d, t)),
|
(Some(d), Some(t)) => Some(DateTimeZ::new(d, t)),
|
||||||
(_, _) => None,
|
(_, _) => None,
|
||||||
}
|
}
|
||||||
|
@ -43,8 +57,15 @@ impl DateTimeZ {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_isoywdhms(year: i32, week: u32, weekday: Weekday,
|
pub fn from_isoywdhms(year: i32, week: u32, weekday: Weekday,
|
||||||
hour: u32, min: u32, sec: u32) -> Option<DateTimeZ> {
|
hour: u32, min: u32, sec: u32) -> DateTimeZ {
|
||||||
match (DateZ::from_isoywd(year, week, weekday), TimeZ::from_hms(hour, min, sec)) {
|
let dt = DateTimeZ::from_isoywdhms_opt(year, week, weekday, hour, min, sec);
|
||||||
|
dt.expect("invalid or out-of-range date or time")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn from_isoywdhms_opt(year: i32, week: u32, weekday: Weekday,
|
||||||
|
hour: u32, min: u32, sec: u32) -> Option<DateTimeZ> {
|
||||||
|
match (DateZ::from_isoywd_opt(year, week, weekday), TimeZ::from_hms_opt(hour, min, sec)) {
|
||||||
(Some(d), Some(t)) => Some(DateTimeZ::new(d, t)),
|
(Some(d), Some(t)) => Some(DateTimeZ::new(d, t)),
|
||||||
(_, _) => None,
|
(_, _) => None,
|
||||||
}
|
}
|
||||||
|
@ -151,7 +172,7 @@ impl Add<Duration,DateTimeZ> for DateTimeZ {
|
||||||
if time < self.time {
|
if time < self.time {
|
||||||
// since the time portion of the duration is always positive and bounded,
|
// since the time portion of the duration is always positive and bounded,
|
||||||
// this condition always means that the time part has been overflowed.
|
// this condition always means that the time part has been overflowed.
|
||||||
date = date.succ().unwrap();
|
date = date.succ();
|
||||||
}
|
}
|
||||||
DateTimeZ { date: date, time: time }
|
DateTimeZ { date: date, time: time }
|
||||||
}
|
}
|
||||||
|
@ -184,7 +205,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_datetime_add() {
|
fn test_datetime_add() {
|
||||||
let ymdhms = |y,m,d,h,n,s| DateTimeZ::from_ymdhms(y,m,d,h,n,s).unwrap();
|
let ymdhms = |y,m,d,h,n,s| DateTimeZ::from_ymdhms(y,m,d,h,n,s);
|
||||||
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) + Duration::seconds(3600 + 60 + 1),
|
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) + Duration::seconds(3600 + 60 + 1),
|
||||||
ymdhms(2014, 5, 6, 8, 9, 10));
|
ymdhms(2014, 5, 6, 8, 9, 10));
|
||||||
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) + Duration::seconds(86399),
|
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) + Duration::seconds(86399),
|
||||||
|
@ -197,7 +218,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_datetime_sub() {
|
fn test_datetime_sub() {
|
||||||
let ymdhms = |y,m,d,h,n,s| DateTimeZ::from_ymdhms(y,m,d,h,n,s).unwrap();
|
let ymdhms = |y,m,d,h,n,s| DateTimeZ::from_ymdhms(y,m,d,h,n,s);
|
||||||
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) - ymdhms(2014, 5, 6, 7, 8, 9), Duration::zero());
|
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) - ymdhms(2014, 5, 6, 7, 8, 9), Duration::zero());
|
||||||
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 10) - ymdhms(2014, 5, 6, 7, 8, 9),
|
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 10) - ymdhms(2014, 5, 6, 7, 8, 9),
|
||||||
Duration::seconds(1));
|
Duration::seconds(1));
|
||||||
|
@ -212,7 +233,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_datetime_nseconds_from_unix_epoch() {
|
fn test_datetime_nseconds_from_unix_epoch() {
|
||||||
let to_timestamp =
|
let to_timestamp =
|
||||||
|y,m,d,h,n,s| DateTimeZ::from_ymdhms(y,m,d,h,n,s).unwrap().nseconds_from_unix_epoch();
|
|y,m,d,h,n,s| DateTimeZ::from_ymdhms(y,m,d,h,n,s).nseconds_from_unix_epoch();
|
||||||
assert_eq!(to_timestamp(1969, 12, 31, 23, 59, 59), -1);
|
assert_eq!(to_timestamp(1969, 12, 31, 23, 59, 59), -1);
|
||||||
assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 0), 0);
|
assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 0), 0);
|
||||||
assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 1), 1);
|
assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 1), 1);
|
||||||
|
|
33
src/lib.rs
33
src/lib.rs
|
@ -9,8 +9,41 @@
|
||||||
|
|
||||||
extern crate num;
|
extern crate num;
|
||||||
|
|
||||||
|
pub use duration::{MIN_DAYS, MAX_DAYS, Duration};
|
||||||
|
pub use date::{MAX_YEAR, MIN_YEAR, Weekday, Mon, Tue, Wed, Thu, Fri, Sat, Sun};
|
||||||
|
pub use date::{Datelike, DateZ};
|
||||||
|
pub use time::{Timelike, TimeZ};
|
||||||
|
pub use datetime::DateTimeZ;
|
||||||
|
|
||||||
pub mod duration;
|
pub mod duration;
|
||||||
pub mod date;
|
pub mod date;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod datetime;
|
pub mod datetime;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_readme_doomsday() {
|
||||||
|
use std::iter::range_inclusive;
|
||||||
|
|
||||||
|
for y in range_inclusive(MIN_YEAR, MAX_YEAR) {
|
||||||
|
// even months
|
||||||
|
let d4 = DateZ::from_ymd(y, 4, 4);
|
||||||
|
let d6 = DateZ::from_ymd(y, 6, 6);
|
||||||
|
let d8 = DateZ::from_ymd(y, 8, 8);
|
||||||
|
let d10 = DateZ::from_ymd(y, 10, 10);
|
||||||
|
let d12 = DateZ::from_ymd(y, 12, 12);
|
||||||
|
|
||||||
|
// nine to five, seven-eleven
|
||||||
|
let d59 = DateZ::from_ymd(y, 5, 9);
|
||||||
|
let d95 = DateZ::from_ymd(y, 9, 5);
|
||||||
|
let d711 = DateZ::from_ymd(y, 7, 11);
|
||||||
|
let d117 = DateZ::from_ymd(y, 11, 7);
|
||||||
|
|
||||||
|
// "March 0"
|
||||||
|
let d30 = DateZ::from_ymd(y, 3, 1).pred();
|
||||||
|
|
||||||
|
let weekday = d30.weekday();
|
||||||
|
let other_dates = [d4, d6, d8, d10, d12, d59, d95, d711, d117];
|
||||||
|
assert!(other_dates.iter().all(|d| d.weekday() == weekday));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
95
src/time.rs
95
src/time.rs
|
@ -72,12 +72,29 @@ pub struct TimeZ {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TimeZ {
|
impl TimeZ {
|
||||||
|
/// Makes a new `TimeZ` from hour, minute and second.
|
||||||
|
///
|
||||||
|
/// Fails on invalid hour, minute and/or second.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_hms(hour: u32, min: u32, sec: u32) -> TimeZ {
|
||||||
|
TimeZ::from_hms_opt(hour, min, sec).expect("invalid time")
|
||||||
|
}
|
||||||
|
|
||||||
/// Makes a new `TimeZ` from hour, minute and second.
|
/// Makes a new `TimeZ` from hour, minute and second.
|
||||||
///
|
///
|
||||||
/// Returns `None` on invalid hour, minute and/or second.
|
/// Returns `None` on invalid hour, minute and/or second.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_hms(hour: u32, min: u32, sec: u32) -> Option<TimeZ> {
|
pub fn from_hms_opt(hour: u32, min: u32, sec: u32) -> Option<TimeZ> {
|
||||||
TimeZ::from_hms_nano(hour, min, sec, 0)
|
TimeZ::from_hms_nano_opt(hour, min, sec, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes a new `TimeZ` from hour, minute, second and millisecond.
|
||||||
|
/// The millisecond part can exceed 1,000 in order to represent the leap second.
|
||||||
|
///
|
||||||
|
/// Fails on invalid hour, minute, second and/or millisecond.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_hms_milli(hour: u32, min: u32, sec: u32, milli: u32) -> TimeZ {
|
||||||
|
TimeZ::from_hms_milli_opt(hour, min, sec, milli).expect("invalid time")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a new `TimeZ` from hour, minute, second and millisecond.
|
/// Makes a new `TimeZ` from hour, minute, second and millisecond.
|
||||||
|
@ -85,8 +102,18 @@ impl TimeZ {
|
||||||
///
|
///
|
||||||
/// Returns `None` on invalid hour, minute, second and/or millisecond.
|
/// Returns `None` on invalid hour, minute, second and/or millisecond.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_hms_milli(hour: u32, min: u32, sec: u32, milli: u32) -> Option<TimeZ> {
|
pub fn from_hms_milli_opt(hour: u32, min: u32, sec: u32, milli: u32) -> Option<TimeZ> {
|
||||||
TimeZ::from_hms_nano(hour, min, sec, milli * 1_000_000)
|
milli.checked_mul(&1_000_000).and_then(|nano| TimeZ::from_hms_nano_opt(hour, min, sec,
|
||||||
|
nano))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes a new `TimeZ` from hour, minute, second and microsecond.
|
||||||
|
/// The microsecond part can exceed 1,000,000 in order to represent the leap second.
|
||||||
|
///
|
||||||
|
/// Fails on invalid hour, minute, second and/or microsecond.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_hms_micro(hour: u32, min: u32, sec: u32, micro: u32) -> TimeZ {
|
||||||
|
TimeZ::from_hms_micro_opt(hour, min, sec, micro).expect("invalid time")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a new `TimeZ` from hour, minute, second and microsecond.
|
/// Makes a new `TimeZ` from hour, minute, second and microsecond.
|
||||||
|
@ -94,15 +121,23 @@ impl TimeZ {
|
||||||
///
|
///
|
||||||
/// Returns `None` on invalid hour, minute, second and/or microsecond.
|
/// Returns `None` on invalid hour, minute, second and/or microsecond.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_hms_micro(hour: u32, min: u32, sec: u32, micro: u32) -> Option<TimeZ> {
|
pub fn from_hms_micro_opt(hour: u32, min: u32, sec: u32, micro: u32) -> Option<TimeZ> {
|
||||||
TimeZ::from_hms_nano(hour, min, sec, micro * 1_000)
|
micro.checked_mul(&1_000).and_then(|nano| TimeZ::from_hms_nano_opt(hour, min, sec, nano))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes a new `TimeZ` from hour, minute, second and nanosecond.
|
||||||
|
/// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second.
|
||||||
|
///
|
||||||
|
/// Fails on invalid hour, minute, second and/or nanosecond.
|
||||||
|
pub fn from_hms_nano(hour: u32, min: u32, sec: u32, nano: u32) -> TimeZ {
|
||||||
|
TimeZ::from_hms_nano_opt(hour, min, sec, nano).expect("invalid time")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a new `TimeZ` from hour, minute, second and nanosecond.
|
/// Makes a new `TimeZ` from hour, minute, second and nanosecond.
|
||||||
/// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second.
|
/// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second.
|
||||||
///
|
///
|
||||||
/// Returns `None` on invalid hour, minute, second and/or nanosecond.
|
/// Returns `None` on invalid hour, minute, second and/or nanosecond.
|
||||||
pub fn from_hms_nano(hour: u32, min: u32, sec: u32, nano: u32) -> Option<TimeZ> {
|
pub fn from_hms_nano_opt(hour: u32, min: u32, sec: u32, nano: u32) -> Option<TimeZ> {
|
||||||
if hour >= 24 || min >= 60 || sec >= 60 || nano >= 2_000_000_000 { return None; }
|
if hour >= 24 || min >= 60 || sec >= 60 || nano >= 2_000_000_000 { return None; }
|
||||||
Some(TimeZ { hour: hour as u8, min: min as u8, sec: sec as u8, frac: nano as u32 })
|
Some(TimeZ { hour: hour as u8, min: min as u8, sec: sec as u8, frac: nano as u32 })
|
||||||
}
|
}
|
||||||
|
@ -210,9 +245,34 @@ impl fmt::Show for TimeZ {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::TimeZ;
|
use super::TimeZ;
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
|
use std::u32;
|
||||||
|
|
||||||
fn hmsm(hour: u32, min: u32, sec: u32, millis: u32) -> TimeZ {
|
#[test]
|
||||||
TimeZ::from_hms_milli(hour, min, sec, millis).unwrap()
|
fn test_time_from_hms_milli() {
|
||||||
|
assert_eq!(TimeZ::from_hms_milli_opt(3, 5, 7, 0),
|
||||||
|
Some(TimeZ::from_hms_nano(3, 5, 7, 0)));
|
||||||
|
assert_eq!(TimeZ::from_hms_milli_opt(3, 5, 7, 777),
|
||||||
|
Some(TimeZ::from_hms_nano(3, 5, 7, 777_000_000)));
|
||||||
|
assert_eq!(TimeZ::from_hms_milli_opt(3, 5, 7, 1_999),
|
||||||
|
Some(TimeZ::from_hms_nano(3, 5, 7, 1_999_000_000)));
|
||||||
|
assert_eq!(TimeZ::from_hms_milli_opt(3, 5, 7, 2_000), None);
|
||||||
|
assert_eq!(TimeZ::from_hms_milli_opt(3, 5, 7, 5_000), None); // overflow check
|
||||||
|
assert_eq!(TimeZ::from_hms_milli_opt(3, 5, 7, u32::MAX), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_time_from_hms_micro() {
|
||||||
|
assert_eq!(TimeZ::from_hms_micro_opt(3, 5, 7, 0),
|
||||||
|
Some(TimeZ::from_hms_nano(3, 5, 7, 0)));
|
||||||
|
assert_eq!(TimeZ::from_hms_micro_opt(3, 5, 7, 333),
|
||||||
|
Some(TimeZ::from_hms_nano(3, 5, 7, 333_000)));
|
||||||
|
assert_eq!(TimeZ::from_hms_micro_opt(3, 5, 7, 777_777),
|
||||||
|
Some(TimeZ::from_hms_nano(3, 5, 7, 777_777_000)));
|
||||||
|
assert_eq!(TimeZ::from_hms_micro_opt(3, 5, 7, 1_999_999),
|
||||||
|
Some(TimeZ::from_hms_nano(3, 5, 7, 1_999_999_000)));
|
||||||
|
assert_eq!(TimeZ::from_hms_micro_opt(3, 5, 7, 2_000_000), None);
|
||||||
|
assert_eq!(TimeZ::from_hms_micro_opt(3, 5, 7, 5_000_000), None); // overflow check
|
||||||
|
assert_eq!(TimeZ::from_hms_micro_opt(3, 5, 7, u32::MAX), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -222,6 +282,8 @@ mod tests {
|
||||||
//assert_eq!(rhs + lhs, sum);
|
//assert_eq!(rhs + lhs, sum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let hmsm = |h,m,s,mi| TimeZ::from_hms_milli(h, m, s, mi);
|
||||||
|
|
||||||
check(hmsm(3, 5, 7, 900), Duration::zero(), hmsm(3, 5, 7, 900));
|
check(hmsm(3, 5, 7, 900), Duration::zero(), hmsm(3, 5, 7, 900));
|
||||||
check(hmsm(3, 5, 7, 900), Duration::milliseconds(100), hmsm(3, 5, 8, 0));
|
check(hmsm(3, 5, 7, 900), Duration::milliseconds(100), hmsm(3, 5, 8, 0));
|
||||||
check(hmsm(3, 5, 7, 1_300), Duration::milliseconds(800), hmsm(3, 5, 8, 100));
|
check(hmsm(3, 5, 7, 1_300), Duration::milliseconds(800), hmsm(3, 5, 8, 100));
|
||||||
|
@ -238,6 +300,8 @@ mod tests {
|
||||||
assert_eq!(rhs - lhs, -diff);
|
assert_eq!(rhs - lhs, -diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let hmsm = |h,m,s,mi| TimeZ::from_hms_milli(h, m, s, mi);
|
||||||
|
|
||||||
check(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 900), Duration::zero());
|
check(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 900), Duration::zero());
|
||||||
check(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 600), Duration::milliseconds(300));
|
check(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 600), Duration::milliseconds(300));
|
||||||
check(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 200), Duration::seconds(3600 + 60 + 1));
|
check(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 200), Duration::seconds(3600 + 60 + 1));
|
||||||
|
@ -258,12 +322,15 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_time_fmt() {
|
fn test_time_fmt() {
|
||||||
assert_eq!(hmsm(23, 59, 59, 999).to_string(), "23:59:59,999".to_string());
|
assert_eq!(TimeZ::from_hms_milli(23, 59, 59, 999).to_string(),
|
||||||
assert_eq!(hmsm(23, 59, 59, 1_000).to_string(), "23:59:60".to_string());
|
"23:59:59,999".to_string());
|
||||||
assert_eq!(hmsm(23, 59, 59, 1_001).to_string(), "23:59:60,001".to_string());
|
assert_eq!(TimeZ::from_hms_milli(23, 59, 59, 1_000).to_string(),
|
||||||
assert_eq!(TimeZ::from_hms_micro(0, 0, 0, 43210).unwrap().to_string(),
|
"23:59:60".to_string());
|
||||||
|
assert_eq!(TimeZ::from_hms_milli(23, 59, 59, 1_001).to_string(),
|
||||||
|
"23:59:60,001".to_string());
|
||||||
|
assert_eq!(TimeZ::from_hms_micro(0, 0, 0, 43210).to_string(),
|
||||||
"00:00:00,043210".to_string());
|
"00:00:00,043210".to_string());
|
||||||
assert_eq!(TimeZ::from_hms_nano(0, 0, 0, 6543210).unwrap().to_string(),
|
assert_eq!(TimeZ::from_hms_nano(0, 0, 0, 6543210).to_string(),
|
||||||
"00:00:00,006543210".to_string());
|
"00:00:00,006543210".to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue