Skip to content

Commit 110c7de

Browse files
committed
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
1 parent f7065f1 commit 110c7de

File tree

3 files changed

+103
-16
lines changed

3 files changed

+103
-16
lines changed

src/date.rs

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
* ISO 8601 calendar date.
77
*/
88

9-
use std::fmt;
9+
use std::{fmt, num};
1010
use num::Integer;
1111
use duration::Duration;
1212

1313
use self::internals::{DateImpl, Of, Mdf, YearFlags};
1414

15-
pub static MAX_YEAR: i32 = internals::MAX_YEAR as i32;
16-
pub static MIN_YEAR: i32 = internals::MIN_YEAR as i32;
15+
static MAX_YEAR: i32 = internals::MAX_YEAR as i32;
16+
static MIN_YEAR: i32 = internals::MIN_YEAR as i32;
1717

1818
/// The day of week (DOW).
1919
#[deriving(PartialEq, Eq, FromPrimitive, Show)]
@@ -213,6 +213,20 @@ pub struct DateZ {
213213
ymdf: DateImpl, // (year << 13) | of
214214
}
215215

216+
/// The minimum possible `DateZ`.
217+
pub static MIN: DateZ = DateZ { ymdf: (MIN_YEAR << 13) | (1 << 4) | 0o07 /*FE*/ };
218+
/// The maximum possible `DateZ`.
219+
pub static MAX: DateZ = DateZ { ymdf: (MAX_YEAR << 13) | (365 << 4) | 0o17 /*F*/ };
220+
221+
// as it is hard to verify year flags in `MIN` and `MAX`, we use a separate run-time test.
222+
#[test]
223+
fn test_datez_bounds() {
224+
let calculated_min = DateZ::from_ymd(MIN_YEAR, 1, 1);
225+
let calculated_max = DateZ::from_ymd(MAX_YEAR, 12, 31);
226+
assert!(MIN == calculated_min, "`MIN` should have a year flag {}", calculated_min.of().flags());
227+
assert!(MAX == calculated_max, "`MAX` should have a year flag {}", calculated_max.of().flags());
228+
}
229+
216230
impl DateZ {
217231
/// Makes a new `DateZ` from year and packed ordinal-flags, with a verification.
218232
fn from_of(year: i32, of: Of) -> Option<DateZ> {
@@ -438,6 +452,11 @@ impl Datelike for DateZ {
438452
}
439453
}
440454

455+
impl num::Bounded for DateZ {
456+
#[inline] fn min_value() -> DateZ { MIN }
457+
#[inline] fn max_value() -> DateZ { MAX }
458+
}
459+
441460
impl Add<Duration,DateZ> for DateZ {
442461
fn add(&self, rhs: &Duration) -> DateZ {
443462
// TODO overflow
@@ -478,11 +497,12 @@ impl Sub<DateZ,Duration> for DateZ {
478497
impl fmt::Show for DateZ {
479498
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
480499
let year = self.year();
500+
let mdf = self.mdf();
481501
if 0 <= year && year <= 9999 {
482-
write!(f, "{:04}-{:02}-{:02}", year, self.month(), self.day())
502+
write!(f, "{:04}-{:02}-{:02}", year, mdf.month(), mdf.day())
483503
} else {
484504
// ISO 8601 requires the explicit sign for out-of-range years
485-
write!(f, "{:+05}-{:02}-{:02}", year, self.month(), self.day())
505+
write!(f, "{:+05}-{:02}-{:02}", year, mdf.month(), mdf.day())
486506
}
487507
}
488508
}
@@ -914,10 +934,10 @@ mod internals {
914934
}
915935
}
916936

917-
static MIN_OL: u32 = 1 << 1;
918-
static MAX_OL: u32 = 366 << 1; // larger than the non-leap last day `(365 << 1) | 1`
919-
static MIN_MDL: u32 = (1 << 6) | (1 << 1);
920-
static MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1;
937+
pub static MIN_OL: u32 = 1 << 1;
938+
pub static MAX_OL: u32 = 366 << 1; // larger than the non-leap last day `(365 << 1) | 1`
939+
pub static MIN_MDL: u32 = (1 << 6) | (1 << 1);
940+
pub static MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1;
921941

922942
static XX: i8 = -128;
923943
static MDL_TO_OL: [i8, ..MAX_MDL+1] = [

src/duration.rs

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,104 +9,171 @@
99
use std::{fmt, num, i32};
1010
use num::Integer;
1111

12-
pub static MIN_DAYS: i32 = i32::MIN;
13-
pub static MAX_DAYS: i32 = i32::MAX;
12+
/// `Duration`'s `days` component should have no more than this value.
13+
static MIN_DAYS: i32 = i32::MIN;
14+
/// `Duration`'s `days` component should have no less than this value.
15+
static MAX_DAYS: i32 = i32::MAX;
1416

17+
/// The number of nanoseconds in seconds.
1518
static NANOS_PER_SEC: i32 = 1_000_000_000;
19+
/// The number of (non-leap) seconds in days.
1620
static SECS_PER_DAY: i32 = 86400;
1721

1822
macro_rules! earlyexit(
1923
($e:expr) => (match $e { Some(v) => v, None => return None })
2024
)
2125

26+
/// ISO 8601 time duration with nanosecond precision.
27+
/// This also allows for the negative duration; see individual methods for details.
2228
#[deriving(PartialEq, Eq, PartialOrd, Ord)]
2329
pub struct Duration {
2430
days: i32,
2531
secs: u32,
2632
nanos: u32,
2733
}
2834

35+
/// The minimum possible `Duration`.
36+
pub static MIN: Duration = Duration { days: MIN_DAYS, secs: 0, nanos: 0 };
37+
/// The maximum possible `Duration`.
38+
pub static MAX: Duration = Duration { days: MAX_DAYS, secs: SECS_PER_DAY as u32 - 1,
39+
nanos: NANOS_PER_SEC as u32 - 1 };
40+
2941
impl Duration {
30-
pub fn new(days: i32, secs: i32, nanos: i32) -> Option<Duration> {
42+
/// Makes a new `Duration` with given number of days, seconds and nanoseconds.
43+
///
44+
/// Fails when the duration is out of bounds.
45+
#[inline]
46+
pub fn new(days: i32, secs: i32, nanos: i32) -> Duration {
47+
Duration::new_opt(days, secs, nanos).expect("Duration::new out of bounds")
48+
}
49+
50+
/// Makes a new `Duration` with given number of days, seconds and nanoseconds.
51+
/// Returns `None` when the duration is out of bounds.
52+
pub fn new_opt(days: i32, secs: i32, nanos: i32) -> Option<Duration> {
3153
let (secs_, nanos) = nanos.div_mod_floor(&NANOS_PER_SEC);
3254
let secs = earlyexit!(secs.checked_add(&secs_));
3355
let (days_, secs) = secs.div_mod_floor(&SECS_PER_DAY);
3456
let days = earlyexit!(days.checked_add(&days_).and_then(|v| v.to_i32()));
3557
Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 })
3658
}
3759

60+
/// Makes a new `Duration` with zero seconds.
3861
#[inline]
3962
pub fn zero() -> Duration {
4063
Duration { days: 0, secs: 0, nanos: 0 }
4164
}
4265

66+
/// Makes a new `Duration` with given number of weeks.
67+
/// Equivalent to `Duration::new(weeks * 7, 0, 0)` with overflow checks.
68+
///
69+
/// Fails when the duration is out of bounds.
4370
#[inline]
4471
pub fn weeks(weeks: i32) -> Duration {
45-
Duration::days(weeks * 7)
72+
let days = weeks.checked_mul(&7).expect("Duration::weeks out of bounds");
73+
Duration::days(days)
4674
}
4775

76+
/// Makes a new `Duration` with given number of days.
77+
/// Equivalent to `Duration::new(days, 0, 0)`.
78+
///
79+
/// Fails when the duration is out of bounds.
4880
#[inline]
4981
pub fn days(days: i32) -> Duration {
5082
let days = days.to_i32().expect("Duration::days out of bounds");
5183
Duration { days: days, secs: 0, nanos: 0 }
5284
}
5385

86+
/// Makes a new `Duration` with given number of hours.
87+
/// Equivalent to `Duration::new(0, hours * 3600, 0)` with overflow checks.
88+
///
89+
/// Fails when the duration is out of bounds.
5490
#[inline]
5591
pub fn hours(hours: i32) -> Duration {
5692
let (days, hours) = hours.div_mod_floor(&(SECS_PER_DAY / 3600));
5793
let secs = hours * 3600;
5894
Duration { secs: secs as u32, ..Duration::days(days) }
5995
}
6096

97+
/// Makes a new `Duration` with given number of minutes.
98+
/// Equivalent to `Duration::new(0, mins * 60, 0)` with overflow checks.
99+
///
100+
/// Fails when the duration is out of bounds.
61101
#[inline]
62102
pub fn minutes(mins: i32) -> Duration {
63103
let (days, mins) = mins.div_mod_floor(&(SECS_PER_DAY / 60));
64104
let secs = mins * 60;
65105
Duration { secs: secs as u32, ..Duration::days(days) }
66106
}
67107

108+
/// Makes a new `Duration` with given number of seconds.
109+
/// Equivalent to `Duration::new(0, secs, 0)`.
110+
///
111+
/// Fails when the duration is out of bounds.
68112
#[inline]
69113
pub fn seconds(secs: i32) -> Duration {
70114
let (days, secs) = secs.div_mod_floor(&SECS_PER_DAY);
71115
Duration { secs: secs as u32, ..Duration::days(days) }
72116
}
73117

118+
/// Makes a new `Duration` with given number of milliseconds.
119+
/// Equivalent to `Duration::new(0, 0, millis * 1_000_000)` with overflow checks.
120+
///
121+
/// Fails when the duration is out of bounds.
74122
#[inline]
75123
pub fn milliseconds(millis: i32) -> Duration {
76124
let (secs, millis) = millis.div_mod_floor(&(NANOS_PER_SEC / 1_000_000));
77125
let nanos = millis * 1_000_000;
78126
Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
79127
}
80128

129+
/// Makes a new `Duration` with given number of microseconds.
130+
/// Equivalent to `Duration::new(0, 0, micros * 1_000)` with overflow checks.
131+
///
132+
/// Fails when the duration is out of bounds.
81133
#[inline]
82134
pub fn microseconds(micros: i32) -> Duration {
83135
let (secs, micros) = micros.div_mod_floor(&(NANOS_PER_SEC / 1_000));
84136
let nanos = micros * 1_000;
85137
Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
86138
}
87139

140+
/// Makes a new `Duration` with given number of nanoseconds.
141+
/// Equivalent to `Duration::new(0, 0, nanos)`.
142+
///
143+
/// Fails when the duration is out of bounds.
88144
#[inline]
89145
pub fn nanoseconds(nanos: i32) -> Duration {
90146
let (secs, nanos) = nanos.div_mod_floor(&NANOS_PER_SEC);
91147
Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
92148
}
93149

150+
/// Returns the number of days in the duration.
151+
/// For the negative duration, this is a largest integral number of days smaller than `self`.
94152
#[inline]
95153
pub fn ndays(&self) -> i32 {
96154
self.days as i32
97155
}
98156

157+
/// Returns the number of (non-leap) seconds in the duration.
158+
/// This never goes negative even when the duration is negative.
99159
#[inline]
100160
pub fn nseconds(&self) -> u32 {
101161
self.secs as u32
102162
}
103163

164+
/// Returns the number of nanoseconds in the duration.
165+
/// This never goes negative even when the duration is negative.
104166
#[inline]
105167
pub fn nnanoseconds(&self) -> u32 {
106168
self.nanos as u32
107169
}
108170
}
109171

172+
impl num::Bounded for Duration {
173+
#[inline] fn min_value() -> Duration { MIN }
174+
#[inline] fn max_value() -> Duration { MAX }
175+
}
176+
110177
impl num::Zero for Duration {
111178
#[inline]
112179
fn zero() -> Duration {

src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99

1010
extern crate num;
1111

12-
pub use duration::{MIN_DAYS, MAX_DAYS, Duration};
13-
pub use date::{MAX_YEAR, MIN_YEAR, Weekday, Mon, Tue, Wed, Thu, Fri, Sat, Sun};
12+
pub use duration::Duration;
13+
pub use date::{Weekday, Mon, Tue, Wed, Thu, Fri, Sat, Sun};
1414
pub use date::{Datelike, DateZ};
1515
pub use time::{Timelike, TimeZ};
1616
pub use datetime::DateTimeZ;
@@ -24,7 +24,7 @@ pub mod datetime;
2424
fn test_readme_doomsday() {
2525
use std::iter::range_inclusive;
2626

27-
for y in range_inclusive(MIN_YEAR, MAX_YEAR) {
27+
for y in range_inclusive(date::MIN.year(), date::MAX.year()) {
2828
// even months
2929
let d4 = DateZ::from_ymd(y, 4, 4);
3030
let d6 = DateZ::from_ymd(y, 6, 6);

0 commit comments

Comments
 (0)