added docs to `Duration`; added `Duration::new_opt`; removed `{MIN,MAX}_{DAYS,YEAR}`.
the minimum and maximum for `DateZ` and `Duration` is now provided via dedicated constants `{date,duration}::{MIN,MAX}`, much like built-in `std::int` and others. they also now implements `std::num::Bounded`. cf. rust-lang/rust#15934
This commit is contained in:
parent
f7065f1625
commit
110c7de7d3
38
src/date.rs
38
src/date.rs
|
@ -6,14 +6,14 @@
|
||||||
* ISO 8601 calendar date.
|
* ISO 8601 calendar date.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::fmt;
|
use std::{fmt, num};
|
||||||
use num::Integer;
|
use num::Integer;
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
|
|
||||||
use self::internals::{DateImpl, Of, Mdf, YearFlags};
|
use self::internals::{DateImpl, Of, Mdf, YearFlags};
|
||||||
|
|
||||||
pub static MAX_YEAR: i32 = internals::MAX_YEAR as i32;
|
static MAX_YEAR: i32 = internals::MAX_YEAR as i32;
|
||||||
pub static MIN_YEAR: i32 = internals::MIN_YEAR as i32;
|
static MIN_YEAR: i32 = internals::MIN_YEAR as i32;
|
||||||
|
|
||||||
/// The day of week (DOW).
|
/// The day of week (DOW).
|
||||||
#[deriving(PartialEq, Eq, FromPrimitive, Show)]
|
#[deriving(PartialEq, Eq, FromPrimitive, Show)]
|
||||||
|
@ -213,6 +213,20 @@ pub struct DateZ {
|
||||||
ymdf: DateImpl, // (year << 13) | of
|
ymdf: DateImpl, // (year << 13) | of
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The minimum possible `DateZ`.
|
||||||
|
pub static MIN: DateZ = DateZ { ymdf: (MIN_YEAR << 13) | (1 << 4) | 0o07 /*FE*/ };
|
||||||
|
/// The maximum possible `DateZ`.
|
||||||
|
pub static MAX: DateZ = DateZ { ymdf: (MAX_YEAR << 13) | (365 << 4) | 0o17 /*F*/ };
|
||||||
|
|
||||||
|
// as it is hard to verify year flags in `MIN` and `MAX`, we use a separate run-time test.
|
||||||
|
#[test]
|
||||||
|
fn test_datez_bounds() {
|
||||||
|
let calculated_min = DateZ::from_ymd(MIN_YEAR, 1, 1);
|
||||||
|
let calculated_max = DateZ::from_ymd(MAX_YEAR, 12, 31);
|
||||||
|
assert!(MIN == calculated_min, "`MIN` should have a year flag {}", calculated_min.of().flags());
|
||||||
|
assert!(MAX == calculated_max, "`MAX` should have a year flag {}", calculated_max.of().flags());
|
||||||
|
}
|
||||||
|
|
||||||
impl DateZ {
|
impl DateZ {
|
||||||
/// Makes a new `DateZ` from year and packed ordinal-flags, with a verification.
|
/// Makes a new `DateZ` from year and packed ordinal-flags, with a verification.
|
||||||
fn from_of(year: i32, of: Of) -> Option<DateZ> {
|
fn from_of(year: i32, of: Of) -> Option<DateZ> {
|
||||||
|
@ -438,6 +452,11 @@ impl Datelike for DateZ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl num::Bounded for DateZ {
|
||||||
|
#[inline] fn min_value() -> DateZ { MIN }
|
||||||
|
#[inline] fn max_value() -> DateZ { MAX }
|
||||||
|
}
|
||||||
|
|
||||||
impl Add<Duration,DateZ> for DateZ {
|
impl Add<Duration,DateZ> for DateZ {
|
||||||
fn add(&self, rhs: &Duration) -> DateZ {
|
fn add(&self, rhs: &Duration) -> DateZ {
|
||||||
// TODO overflow
|
// TODO overflow
|
||||||
|
@ -478,11 +497,12 @@ impl Sub<DateZ,Duration> for DateZ {
|
||||||
impl fmt::Show for DateZ {
|
impl fmt::Show for DateZ {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let year = self.year();
|
let year = self.year();
|
||||||
|
let mdf = self.mdf();
|
||||||
if 0 <= year && year <= 9999 {
|
if 0 <= year && year <= 9999 {
|
||||||
write!(f, "{:04}-{:02}-{:02}", year, self.month(), self.day())
|
write!(f, "{:04}-{:02}-{:02}", year, mdf.month(), mdf.day())
|
||||||
} else {
|
} else {
|
||||||
// ISO 8601 requires the explicit sign for out-of-range years
|
// ISO 8601 requires the explicit sign for out-of-range years
|
||||||
write!(f, "{:+05}-{:02}-{:02}", year, self.month(), self.day())
|
write!(f, "{:+05}-{:02}-{:02}", year, mdf.month(), mdf.day())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -914,10 +934,10 @@ mod internals {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static MIN_OL: u32 = 1 << 1;
|
pub static MIN_OL: u32 = 1 << 1;
|
||||||
static MAX_OL: u32 = 366 << 1; // larger than the non-leap last day `(365 << 1) | 1`
|
pub static MAX_OL: u32 = 366 << 1; // larger than the non-leap last day `(365 << 1) | 1`
|
||||||
static MIN_MDL: u32 = (1 << 6) | (1 << 1);
|
pub static MIN_MDL: u32 = (1 << 6) | (1 << 1);
|
||||||
static MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1;
|
pub static MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1;
|
||||||
|
|
||||||
static XX: i8 = -128;
|
static XX: i8 = -128;
|
||||||
static MDL_TO_OL: [i8, ..MAX_MDL+1] = [
|
static MDL_TO_OL: [i8, ..MAX_MDL+1] = [
|
||||||
|
|
|
@ -9,16 +9,22 @@
|
||||||
use std::{fmt, num, i32};
|
use std::{fmt, num, i32};
|
||||||
use num::Integer;
|
use num::Integer;
|
||||||
|
|
||||||
pub static MIN_DAYS: i32 = i32::MIN;
|
/// `Duration`'s `days` component should have no more than this value.
|
||||||
pub static MAX_DAYS: i32 = i32::MAX;
|
static MIN_DAYS: i32 = i32::MIN;
|
||||||
|
/// `Duration`'s `days` component should have no less than this value.
|
||||||
|
static MAX_DAYS: i32 = i32::MAX;
|
||||||
|
|
||||||
|
/// The number of nanoseconds in seconds.
|
||||||
static NANOS_PER_SEC: i32 = 1_000_000_000;
|
static NANOS_PER_SEC: i32 = 1_000_000_000;
|
||||||
|
/// The number of (non-leap) seconds in days.
|
||||||
static SECS_PER_DAY: i32 = 86400;
|
static SECS_PER_DAY: i32 = 86400;
|
||||||
|
|
||||||
macro_rules! earlyexit(
|
macro_rules! earlyexit(
|
||||||
($e:expr) => (match $e { Some(v) => v, None => return None })
|
($e:expr) => (match $e { Some(v) => v, None => return None })
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/// ISO 8601 time duration with nanosecond precision.
|
||||||
|
/// This also allows for the negative duration; see individual methods for details.
|
||||||
#[deriving(PartialEq, Eq, PartialOrd, Ord)]
|
#[deriving(PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Duration {
|
pub struct Duration {
|
||||||
days: i32,
|
days: i32,
|
||||||
|
@ -26,8 +32,24 @@ pub struct Duration {
|
||||||
nanos: u32,
|
nanos: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The minimum possible `Duration`.
|
||||||
|
pub static MIN: Duration = Duration { days: MIN_DAYS, secs: 0, nanos: 0 };
|
||||||
|
/// The maximum possible `Duration`.
|
||||||
|
pub static MAX: Duration = Duration { days: MAX_DAYS, secs: SECS_PER_DAY as u32 - 1,
|
||||||
|
nanos: NANOS_PER_SEC as u32 - 1 };
|
||||||
|
|
||||||
impl Duration {
|
impl Duration {
|
||||||
pub fn new(days: i32, secs: i32, nanos: i32) -> Option<Duration> {
|
/// Makes a new `Duration` with given number of days, seconds and nanoseconds.
|
||||||
|
///
|
||||||
|
/// Fails when the duration is out of bounds.
|
||||||
|
#[inline]
|
||||||
|
pub fn new(days: i32, secs: i32, nanos: i32) -> Duration {
|
||||||
|
Duration::new_opt(days, secs, nanos).expect("Duration::new out of bounds")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes a new `Duration` with given number of days, seconds and nanoseconds.
|
||||||
|
/// Returns `None` when the duration is out of bounds.
|
||||||
|
pub fn new_opt(days: i32, secs: i32, nanos: i32) -> Option<Duration> {
|
||||||
let (secs_, nanos) = nanos.div_mod_floor(&NANOS_PER_SEC);
|
let (secs_, nanos) = nanos.div_mod_floor(&NANOS_PER_SEC);
|
||||||
let secs = earlyexit!(secs.checked_add(&secs_));
|
let secs = earlyexit!(secs.checked_add(&secs_));
|
||||||
let (days_, secs) = secs.div_mod_floor(&SECS_PER_DAY);
|
let (days_, secs) = secs.div_mod_floor(&SECS_PER_DAY);
|
||||||
|
@ -35,22 +57,36 @@ impl Duration {
|
||||||
Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 })
|
Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a new `Duration` with zero seconds.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn zero() -> Duration {
|
pub fn zero() -> Duration {
|
||||||
Duration { days: 0, secs: 0, nanos: 0 }
|
Duration { days: 0, secs: 0, nanos: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a new `Duration` with given number of weeks.
|
||||||
|
/// Equivalent to `Duration::new(weeks * 7, 0, 0)` with overflow checks.
|
||||||
|
///
|
||||||
|
/// Fails when the duration is out of bounds.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn weeks(weeks: i32) -> Duration {
|
pub fn weeks(weeks: i32) -> Duration {
|
||||||
Duration::days(weeks * 7)
|
let days = weeks.checked_mul(&7).expect("Duration::weeks out of bounds");
|
||||||
|
Duration::days(days)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a new `Duration` with given number of days.
|
||||||
|
/// Equivalent to `Duration::new(days, 0, 0)`.
|
||||||
|
///
|
||||||
|
/// Fails when the duration is out of bounds.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn days(days: i32) -> Duration {
|
pub fn days(days: i32) -> Duration {
|
||||||
let days = days.to_i32().expect("Duration::days out of bounds");
|
let days = days.to_i32().expect("Duration::days out of bounds");
|
||||||
Duration { days: days, secs: 0, nanos: 0 }
|
Duration { days: days, secs: 0, nanos: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a new `Duration` with given number of hours.
|
||||||
|
/// Equivalent to `Duration::new(0, hours * 3600, 0)` with overflow checks.
|
||||||
|
///
|
||||||
|
/// Fails when the duration is out of bounds.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn hours(hours: i32) -> Duration {
|
pub fn hours(hours: i32) -> Duration {
|
||||||
let (days, hours) = hours.div_mod_floor(&(SECS_PER_DAY / 3600));
|
let (days, hours) = hours.div_mod_floor(&(SECS_PER_DAY / 3600));
|
||||||
|
@ -58,6 +94,10 @@ impl Duration {
|
||||||
Duration { secs: secs as u32, ..Duration::days(days) }
|
Duration { secs: secs as u32, ..Duration::days(days) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a new `Duration` with given number of minutes.
|
||||||
|
/// Equivalent to `Duration::new(0, mins * 60, 0)` with overflow checks.
|
||||||
|
///
|
||||||
|
/// Fails when the duration is out of bounds.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn minutes(mins: i32) -> Duration {
|
pub fn minutes(mins: i32) -> Duration {
|
||||||
let (days, mins) = mins.div_mod_floor(&(SECS_PER_DAY / 60));
|
let (days, mins) = mins.div_mod_floor(&(SECS_PER_DAY / 60));
|
||||||
|
@ -65,12 +105,20 @@ impl Duration {
|
||||||
Duration { secs: secs as u32, ..Duration::days(days) }
|
Duration { secs: secs as u32, ..Duration::days(days) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a new `Duration` with given number of seconds.
|
||||||
|
/// Equivalent to `Duration::new(0, secs, 0)`.
|
||||||
|
///
|
||||||
|
/// Fails when the duration is out of bounds.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn seconds(secs: i32) -> Duration {
|
pub fn seconds(secs: i32) -> Duration {
|
||||||
let (days, secs) = secs.div_mod_floor(&SECS_PER_DAY);
|
let (days, secs) = secs.div_mod_floor(&SECS_PER_DAY);
|
||||||
Duration { secs: secs as u32, ..Duration::days(days) }
|
Duration { secs: secs as u32, ..Duration::days(days) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a new `Duration` with given number of milliseconds.
|
||||||
|
/// Equivalent to `Duration::new(0, 0, millis * 1_000_000)` with overflow checks.
|
||||||
|
///
|
||||||
|
/// Fails when the duration is out of bounds.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn milliseconds(millis: i32) -> Duration {
|
pub fn milliseconds(millis: i32) -> Duration {
|
||||||
let (secs, millis) = millis.div_mod_floor(&(NANOS_PER_SEC / 1_000_000));
|
let (secs, millis) = millis.div_mod_floor(&(NANOS_PER_SEC / 1_000_000));
|
||||||
|
@ -78,6 +126,10 @@ impl Duration {
|
||||||
Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
|
Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a new `Duration` with given number of microseconds.
|
||||||
|
/// Equivalent to `Duration::new(0, 0, micros * 1_000)` with overflow checks.
|
||||||
|
///
|
||||||
|
/// Fails when the duration is out of bounds.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn microseconds(micros: i32) -> Duration {
|
pub fn microseconds(micros: i32) -> Duration {
|
||||||
let (secs, micros) = micros.div_mod_floor(&(NANOS_PER_SEC / 1_000));
|
let (secs, micros) = micros.div_mod_floor(&(NANOS_PER_SEC / 1_000));
|
||||||
|
@ -85,28 +137,43 @@ impl Duration {
|
||||||
Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
|
Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a new `Duration` with given number of nanoseconds.
|
||||||
|
/// Equivalent to `Duration::new(0, 0, nanos)`.
|
||||||
|
///
|
||||||
|
/// Fails when the duration is out of bounds.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn nanoseconds(nanos: i32) -> Duration {
|
pub fn nanoseconds(nanos: i32) -> Duration {
|
||||||
let (secs, nanos) = nanos.div_mod_floor(&NANOS_PER_SEC);
|
let (secs, nanos) = nanos.div_mod_floor(&NANOS_PER_SEC);
|
||||||
Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
|
Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the number of days in the duration.
|
||||||
|
/// For the negative duration, this is a largest integral number of days smaller than `self`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ndays(&self) -> i32 {
|
pub fn ndays(&self) -> i32 {
|
||||||
self.days as i32
|
self.days as i32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the number of (non-leap) seconds in the duration.
|
||||||
|
/// This never goes negative even when the duration is negative.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn nseconds(&self) -> u32 {
|
pub fn nseconds(&self) -> u32 {
|
||||||
self.secs as u32
|
self.secs as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the number of nanoseconds in the duration.
|
||||||
|
/// This never goes negative even when the duration is negative.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn nnanoseconds(&self) -> u32 {
|
pub fn nnanoseconds(&self) -> u32 {
|
||||||
self.nanos as u32
|
self.nanos as u32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl num::Bounded for Duration {
|
||||||
|
#[inline] fn min_value() -> Duration { MIN }
|
||||||
|
#[inline] fn max_value() -> Duration { MAX }
|
||||||
|
}
|
||||||
|
|
||||||
impl num::Zero for Duration {
|
impl num::Zero for Duration {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn zero() -> Duration {
|
fn zero() -> Duration {
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
|
|
||||||
extern crate num;
|
extern crate num;
|
||||||
|
|
||||||
pub use duration::{MIN_DAYS, MAX_DAYS, Duration};
|
pub use duration::Duration;
|
||||||
pub use date::{MAX_YEAR, MIN_YEAR, Weekday, Mon, Tue, Wed, Thu, Fri, Sat, Sun};
|
pub use date::{Weekday, Mon, Tue, Wed, Thu, Fri, Sat, Sun};
|
||||||
pub use date::{Datelike, DateZ};
|
pub use date::{Datelike, DateZ};
|
||||||
pub use time::{Timelike, TimeZ};
|
pub use time::{Timelike, TimeZ};
|
||||||
pub use datetime::DateTimeZ;
|
pub use datetime::DateTimeZ;
|
||||||
|
@ -24,7 +24,7 @@ pub mod datetime;
|
||||||
fn test_readme_doomsday() {
|
fn test_readme_doomsday() {
|
||||||
use std::iter::range_inclusive;
|
use std::iter::range_inclusive;
|
||||||
|
|
||||||
for y in range_inclusive(MIN_YEAR, MAX_YEAR) {
|
for y in range_inclusive(date::MIN.year(), date::MAX.year()) {
|
||||||
// even months
|
// even months
|
||||||
let d4 = DateZ::from_ymd(y, 4, 4);
|
let d4 = DateZ::from_ymd(y, 4, 4);
|
||||||
let d6 = DateZ::from_ymd(y, 6, 6);
|
let d6 = DateZ::from_ymd(y, 6, 6);
|
||||||
|
|
Loading…
Reference in New Issue