{Date,Time,DateTime} -> {DateZ,TimeZ,DateTimeZ}, in order to distinguish them from the timezone-aware types.

This commit is contained in:
Kang Seonghoon 2014-03-28 21:56:38 +09:00
parent 646b6c27b9
commit 715a35caa6
3 changed files with 416 additions and 523 deletions

View File

@ -105,50 +105,143 @@ impl Weekday {
}
}
/// ISO 8601 calendar date. Also supports the conversion from ISO 8601 ordinal and week date.
pub trait Datelike {
/// Returns the year number.
fn year(&self) -> int;
/// Returns the absolute year number starting from 1 with a boolean flag,
/// which is false when the year predates the epoch (BCE/BC) and true otherwise (CE/AD).
#[inline]
fn year_ce(&self) -> (bool, uint) {
let year = self.year();
if year < 1 {
(false, (1 - year) as uint)
} else {
(true, year as uint)
}
}
/// Returns the month number starting from 1.
fn month(&self) -> uint;
/// Returns the month number starting from 0.
fn month0(&self) -> uint;
/// Returns the day of month starting from 1.
fn day(&self) -> uint;
/// Returns the day of month starting from 0.
fn day0(&self) -> uint;
/// Returns the day of year starting from 1.
fn ordinal(&self) -> uint;
/// Returns the day of year starting from 0.
fn ordinal0(&self) -> uint;
/// Returns the day of week.
fn weekday(&self) -> Weekday;
/// Returns the ISO week date: an adjusted year, week number and day of week.
/// The adjusted year may differ from that of the calendar date.
fn isoweekdate(&self) -> (int, uint, Weekday);
/// Makes a new value with the year number changed.
///
/// Returns `None` when the resulting value would be invalid.
fn with_year(&self, year: int) -> Option<Self>;
/// Makes a new value with the month number (starting from 1) changed.
///
/// Returns `None` when the resulting value would be invalid.
fn with_month(&self, month: uint) -> Option<Self>;
/// Makes a new value with the month number (starting from 0) changed.
///
/// Returns `None` when the resulting value would be invalid.
fn with_month0(&self, month0: uint) -> Option<Self>;
/// Makes a new value with the day of month (starting from 1) changed.
///
/// Returns `None` when the resulting value would be invalid.
fn with_day(&self, day: uint) -> Option<Self>;
/// Makes a new value with the day of month (starting from 0) changed.
///
/// Returns `None` when the resulting value would be invalid.
fn with_day0(&self, day0: uint) -> Option<Self>;
/// Makes a new value with the day of year (starting from 1) changed.
///
/// Returns `None` when the resulting value would be invalid.
fn with_ordinal(&self, ordinal: uint) -> Option<Self>;
/// Makes a new value with the day of year (starting from 0) changed.
///
/// Returns `None` when the resulting value would be invalid.
fn with_ordinal0(&self, ordinal0: uint) -> Option<Self>;
/// Returns the number of days since January 1, 1 (Day 1) in the proleptic Gregorian calendar.
fn ndays_from_ce(&self) -> int {
// we know this wouldn't overflow since year is limited to 1/2^13 of i32's full range.
let mut year = self.year() - 1;
let mut ndays = 0;
if year < 0 {
let excess = 1 + (-year) / 400;
year += excess * 400;
ndays -= excess * 146097;
}
let div_100 = year / 100;
ndays += ((year * 1461) >> 2) - div_100 + (div_100 >> 2);
ndays + self.ordinal() as int
}
}
/// ISO 8601 calendar date without timezone.
/// Allows for every proleptic Gregorian date from Jan 1, 262145 BCE to Dec 31, 262143 CE.
/// Also supports the conversion from ISO 8601 ordinal and week date.
#[deriving(Eq, TotalEq, Ord, TotalOrd, Hash)]
pub struct Date {
pub struct DateZ {
priv ymdf: DateImpl, // (year << 13) | mdf
}
impl Date {
impl DateZ {
/// The internal constructor with the verification.
fn new(year: int, mdf: Mdf) -> Option<Date> {
fn new(year: int, mdf: Mdf) -> Option<DateZ> {
if year >= MIN_YEAR as int && year <= MAX_YEAR as int && mdf.valid() {
let Mdf(mdf) = mdf;
Some(Date { ymdf: ((year << 13) as DateImpl) | (mdf as DateImpl) })
Some(DateZ { ymdf: ((year << 13) as DateImpl) | (mdf as DateImpl) })
} else {
None
}
}
/// Makes a new `Date` 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.
///
/// Returns `None` on the out-of-range date, invalid month and/or day.
pub fn from_ymd(year: int, month: uint, day: uint) -> Option<Date> {
pub fn from_ymd(year: int, month: uint, day: uint) -> Option<DateZ> {
let flags = YearFlags::from_year(year);
let mdf = Mdf::new(month, day, flags);
Date::new(year, mdf)
DateZ::new(year, mdf)
}
/// Makes a new `Date` 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.
///
/// Returns `None` on the out-of-range date and/or invalid DOY.
pub fn from_yo(year: int, ordinal: uint) -> Option<Date> {
pub fn from_yo(year: int, ordinal: uint) -> Option<DateZ> {
let flags = YearFlags::from_year(year);
let mdf = Of::new(ordinal, flags).to_mdf();
Date::new(year, mdf)
DateZ::new(year, mdf)
}
/// Makes a new `Date` 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.
/// The resulting `Date` 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.
pub fn from_isoywd(year: int, week: uint, weekday: Weekday) -> Option<Date> {
pub fn from_isoywd(year: int, week: uint, weekday: Weekday) -> Option<DateZ> {
let flags = YearFlags::from_year(year);
let nweeks = flags.nisoweeks();
if 1 <= week && week <= nweeks {
@ -158,17 +251,17 @@ impl Date {
if weekord <= delta { // ordinal < 1, previous year
let prevflags = YearFlags::from_year(year - 1);
let mdf = Of::new(weekord + prevflags.ndays() - delta, prevflags).to_mdf();
Date::new(year - 1, mdf)
DateZ::new(year - 1, mdf)
} else {
let ordinal = weekord - delta;
let ndays = flags.ndays();
if ordinal <= ndays { // this year
let mdf = Of::new(ordinal, flags).to_mdf();
Date::new(year, mdf)
DateZ::new(year, mdf)
} else { // ordinal > ndays, next year
let nextflags = YearFlags::from_year(year + 1);
let mdf = Of::new(ordinal - ndays, nextflags).to_mdf();
Date::new(year + 1, mdf)
DateZ::new(year + 1, mdf)
}
}
} else {
@ -188,69 +281,31 @@ impl Date {
self.mdf().to_of()
}
/// Returns the year number.
/// Makes a new `DateZ` with the packed month, day and year flags changed.
///
/// Returns `None` when the resulting `DateZ` would be invalid.
#[inline]
pub fn year(&self) -> int {
(self.ymdf >> 13) as int
}
/// Returns the absolute year number starting from 1 with a boolean flag,
/// which is false when the year predates the epoch (BCE/BC) and true otherwise (CE/AD).
#[inline]
pub fn year_ce(&self) -> (bool, uint) {
let year = self.year();
if year < 1 {
(false, (1 - year) as uint)
fn with_mdf(&self, mdf: Mdf) -> Option<DateZ> {
if mdf.valid() {
let Mdf(mdf) = mdf;
Some(DateZ { ymdf: (self.ymdf & !0b1111_11111_1111) | mdf as DateImpl })
} else {
(true, year as uint)
None
}
}
}
/// Returns the month number starting from 1.
#[inline]
pub fn month(&self) -> uint {
self.mdf().month()
}
impl Datelike for DateZ {
#[inline] fn year(&self) -> int { (self.ymdf >> 13) as int }
#[inline] fn month(&self) -> uint { self.mdf().month() }
#[inline] fn month0(&self) -> uint { self.mdf().month() - 1 }
#[inline] fn day(&self) -> uint { self.mdf().day() }
#[inline] fn day0(&self) -> uint { self.mdf().day() - 1 }
#[inline] fn ordinal(&self) -> uint { self.of().ordinal() }
#[inline] fn ordinal0(&self) -> uint { self.of().ordinal() - 1 }
#[inline] fn weekday(&self) -> Weekday { self.of().weekday() }
/// Returns the month number starting from 0.
#[inline]
pub fn month0(&self) -> uint {
self.mdf().month() - 1
}
/// Returns the day of month starting from 1.
#[inline]
pub fn day(&self) -> uint {
self.mdf().day()
}
/// Returns the day of month starting from 0.
#[inline]
pub fn day0(&self) -> uint {
self.mdf().day() - 1
}
/// Returns the day of year starting from 1.
#[inline]
pub fn ordinal(&self) -> uint {
self.of().ordinal()
}
/// Returns the day of year starting from 0.
#[inline]
pub fn ordinal0(&self) -> uint {
self.of().ordinal() - 1
}
/// Returns the day of week.
#[inline]
pub fn weekday(&self) -> Weekday {
self.of().weekday()
}
/// Returns the ISO week date: an adjusted year, week number and day of week.
/// The adjusted year may differ from that of the calendar date.
pub fn isoweekdate(&self) -> (int, uint, Weekday) {
fn isoweekdate(&self) -> (int, uint, Weekday) {
let of = self.of();
let year = self.year();
let (rawweek, weekday) = of.isoweekdate_raw();
@ -267,95 +322,46 @@ impl Date {
}
}
/// Makes a new `Date` with the year number changed.
///
/// Returns `None` when the resulting `Date` would be invalid.
#[inline]
pub fn with_year(&self, year: int) -> Option<Date> {
fn with_year(&self, year: int) -> Option<DateZ> {
// adjust the flags as needed
let flags = YearFlags::from_year(year);
let mdf = self.mdf().with_flags(flags);
Date::new(year, mdf)
DateZ::new(year, mdf)
}
/// Makes a new `Date` with the packed month, day and year flags changed.
///
/// Returns `None` when the resulting `Date` would be invalid.
#[inline]
fn with_mdf(&self, mdf: Mdf) -> Option<Date> {
if mdf.valid() {
let Mdf(mdf) = mdf;
Some(Date { ymdf: (self.ymdf & !0b1111_11111_1111) | mdf as DateImpl })
} else {
None
}
}
/// Makes a new `Date` with the month number (starting from 1) changed.
///
/// Returns `None` when the resulting `Date` would be invalid.
#[inline]
pub fn with_month(&self, month: uint) -> Option<Date> {
fn with_month(&self, month: uint) -> Option<DateZ> {
self.with_mdf(self.mdf().with_month(month))
}
/// Makes a new `Date` with the month number (starting from 0) changed.
///
/// Returns `None` when the resulting `Date` would be invalid.
#[inline]
pub fn with_month0(&self, month0: uint) -> Option<Date> {
fn with_month0(&self, month0: uint) -> Option<DateZ> {
self.with_mdf(self.mdf().with_month(month0 + 1))
}
/// Makes a new `Date` with the day of month (starting from 1) changed.
///
/// Returns `None` when the resulting `Date` would be invalid.
#[inline]
pub fn with_day(&self, day: uint) -> Option<Date> {
fn with_day(&self, day: uint) -> Option<DateZ> {
self.with_mdf(self.mdf().with_day(day))
}
/// Makes a new `Date` with the day of month (starting from 0) changed.
///
/// Returns `None` when the resulting `Date` would be invalid.
#[inline]
pub fn with_day0(&self, day0: uint) -> Option<Date> {
fn with_day0(&self, day0: uint) -> Option<DateZ> {
self.with_mdf(self.mdf().with_day(day0 + 1))
}
/// Makes a new `Date` with the day of year (starting from 1) changed.
///
/// Returns `None` when the resulting `Date` would be invalid.
#[inline]
pub fn with_ordinal(&self, ordinal: uint) -> Option<Date> {
fn with_ordinal(&self, ordinal: uint) -> Option<DateZ> {
self.with_mdf(self.mdf().to_of().with_ordinal(ordinal).to_mdf())
}
/// Makes a new `Date` with the day of year (starting from 0) changed.
///
/// Returns `None` when the resulting `Date` would be invalid.
#[inline]
pub fn with_ordinal0(&self, ordinal0: uint) -> Option<Date> {
fn with_ordinal0(&self, ordinal0: uint) -> Option<DateZ> {
self.with_mdf(self.mdf().to_of().with_ordinal(ordinal0 + 1).to_mdf())
}
/// Returns the number of days since January 1, 1 (Day 1) in the proleptic Gregorian calendar.
pub fn ndays_from_ce(&self) -> int {
// we know this wouldn't overflow since year is limited to 1/2^13 of i32's full range.
let mut year = self.year() - 1;
let mut ndays = 0;
if year < 0 {
let excess = 1 + (-year) / 400;
year += excess * 400;
ndays -= excess * 146097;
}
let div_100 = year / 100;
ndays += ((year * 1461) >> 2) - div_100 + (div_100 >> 2);
ndays + self.of().ordinal() as int
}
}
impl fmt::Show for Date {
impl fmt::Show for DateZ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f.buf, "{:04}-{:02}-{:02}", self.year(), self.month(), self.day())
}
@ -369,69 +375,69 @@ mod tests {
#[test]
fn test_date_from_ymd() {
assert!(Date::from_ymd(2012, 0, 1).is_none());
assert!(Date::from_ymd(2012, 1, 1).is_some());
assert!(Date::from_ymd(2012, 2, 29).is_some());
assert!(Date::from_ymd(2014, 2, 29).is_none());
assert!(Date::from_ymd(2014, 3, 0).is_none());
assert!(Date::from_ymd(2014, 3, 1).is_some());
assert!(Date::from_ymd(2014, 3, 31).is_some());
assert!(Date::from_ymd(2014, 3, 32).is_none());
assert!(Date::from_ymd(2014, 12, 31).is_some());
assert!(Date::from_ymd(2014, 13, 1).is_none());
assert!(DateZ::from_ymd(2012, 0, 1).is_none());
assert!(DateZ::from_ymd(2012, 1, 1).is_some());
assert!(DateZ::from_ymd(2012, 2, 29).is_some());
assert!(DateZ::from_ymd(2014, 2, 29).is_none());
assert!(DateZ::from_ymd(2014, 3, 0).is_none());
assert!(DateZ::from_ymd(2014, 3, 1).is_some());
assert!(DateZ::from_ymd(2014, 3, 31).is_some());
assert!(DateZ::from_ymd(2014, 3, 32).is_none());
assert!(DateZ::from_ymd(2014, 12, 31).is_some());
assert!(DateZ::from_ymd(2014, 13, 1).is_none());
}
#[test]
fn test_date_from_yo() {
assert!(Date::from_yo(2012, 0).is_none());
assert_eq!(Date::from_yo(2012, 1), Date::from_ymd(2012, 1, 1));
assert_eq!(Date::from_yo(2012, 2), Date::from_ymd(2012, 1, 2));
assert_eq!(Date::from_yo(2012, 32), Date::from_ymd(2012, 2, 1));
assert_eq!(Date::from_yo(2012, 60), Date::from_ymd(2012, 2, 29));
assert_eq!(Date::from_yo(2012, 61), Date::from_ymd(2012, 3, 1));
assert_eq!(Date::from_yo(2012, 100), Date::from_ymd(2012, 4, 9));
assert_eq!(Date::from_yo(2012, 200), Date::from_ymd(2012, 7, 18));
assert_eq!(Date::from_yo(2012, 300), Date::from_ymd(2012, 10, 26));
assert_eq!(Date::from_yo(2012, 366), Date::from_ymd(2012, 12, 31));
assert!(Date::from_yo(2012, 367).is_none());
assert!(DateZ::from_yo(2012, 0).is_none());
assert_eq!(DateZ::from_yo(2012, 1), DateZ::from_ymd(2012, 1, 1));
assert_eq!(DateZ::from_yo(2012, 2), DateZ::from_ymd(2012, 1, 2));
assert_eq!(DateZ::from_yo(2012, 32), DateZ::from_ymd(2012, 2, 1));
assert_eq!(DateZ::from_yo(2012, 60), DateZ::from_ymd(2012, 2, 29));
assert_eq!(DateZ::from_yo(2012, 61), DateZ::from_ymd(2012, 3, 1));
assert_eq!(DateZ::from_yo(2012, 100), DateZ::from_ymd(2012, 4, 9));
assert_eq!(DateZ::from_yo(2012, 200), DateZ::from_ymd(2012, 7, 18));
assert_eq!(DateZ::from_yo(2012, 300), DateZ::from_ymd(2012, 10, 26));
assert_eq!(DateZ::from_yo(2012, 366), DateZ::from_ymd(2012, 12, 31));
assert!(DateZ::from_yo(2012, 367).is_none());
assert!(Date::from_yo(2014, 0).is_none());
assert_eq!(Date::from_yo(2014, 1), Date::from_ymd(2014, 1, 1));
assert_eq!(Date::from_yo(2014, 2), Date::from_ymd(2014, 1, 2));
assert_eq!(Date::from_yo(2014, 32), Date::from_ymd(2014, 2, 1));
assert_eq!(Date::from_yo(2014, 59), Date::from_ymd(2014, 2, 28));
assert_eq!(Date::from_yo(2014, 60), Date::from_ymd(2014, 3, 1));
assert_eq!(Date::from_yo(2014, 100), Date::from_ymd(2014, 4, 10));
assert_eq!(Date::from_yo(2014, 200), Date::from_ymd(2014, 7, 19));
assert_eq!(Date::from_yo(2014, 300), Date::from_ymd(2014, 10, 27));
assert_eq!(Date::from_yo(2014, 365), Date::from_ymd(2014, 12, 31));
assert!(Date::from_yo(2014, 366).is_none());
assert!(DateZ::from_yo(2014, 0).is_none());
assert_eq!(DateZ::from_yo(2014, 1), DateZ::from_ymd(2014, 1, 1));
assert_eq!(DateZ::from_yo(2014, 2), DateZ::from_ymd(2014, 1, 2));
assert_eq!(DateZ::from_yo(2014, 32), DateZ::from_ymd(2014, 2, 1));
assert_eq!(DateZ::from_yo(2014, 59), DateZ::from_ymd(2014, 2, 28));
assert_eq!(DateZ::from_yo(2014, 60), DateZ::from_ymd(2014, 3, 1));
assert_eq!(DateZ::from_yo(2014, 100), DateZ::from_ymd(2014, 4, 10));
assert_eq!(DateZ::from_yo(2014, 200), DateZ::from_ymd(2014, 7, 19));
assert_eq!(DateZ::from_yo(2014, 300), DateZ::from_ymd(2014, 10, 27));
assert_eq!(DateZ::from_yo(2014, 365), DateZ::from_ymd(2014, 12, 31));
assert!(DateZ::from_yo(2014, 366).is_none());
}
#[test]
fn test_date_from_isoywd() {
assert!(Date::from_isoywd(2004, 0, Sun).is_none());
assert_eq!(Date::from_isoywd(2004, 1, Mon), Date::from_ymd(2003, 12, 29));
assert_eq!(Date::from_isoywd(2004, 1, Sun), Date::from_ymd(2004, 1, 4));
assert_eq!(Date::from_isoywd(2004, 2, Mon), Date::from_ymd(2004, 1, 5));
assert_eq!(Date::from_isoywd(2004, 2, Sun), Date::from_ymd(2004, 1, 11));
assert_eq!(Date::from_isoywd(2004, 52, Mon), Date::from_ymd(2004, 12, 20));
assert_eq!(Date::from_isoywd(2004, 52, Sun), Date::from_ymd(2004, 12, 26));
assert_eq!(Date::from_isoywd(2004, 53, Mon), Date::from_ymd(2004, 12, 27));
assert_eq!(Date::from_isoywd(2004, 53, Sun), Date::from_ymd(2005, 1, 2));
assert!(Date::from_isoywd(2004, 54, Mon).is_none());
assert!(DateZ::from_isoywd(2004, 0, Sun).is_none());
assert_eq!(DateZ::from_isoywd(2004, 1, Mon), 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(2004, 2, Mon), 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(2004, 52, Mon), 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(2004, 53, Mon), DateZ::from_ymd(2004, 12, 27));
assert_eq!(DateZ::from_isoywd(2004, 53, Sun), DateZ::from_ymd(2005, 1, 2));
assert!(DateZ::from_isoywd(2004, 54, Mon).is_none());
assert!(Date::from_isoywd(2011, 0, Sun).is_none());
assert_eq!(Date::from_isoywd(2011, 1, Mon), Date::from_ymd(2011, 1, 3));
assert_eq!(Date::from_isoywd(2011, 1, Sun), Date::from_ymd(2011, 1, 9));
assert_eq!(Date::from_isoywd(2011, 2, Mon), Date::from_ymd(2011, 1, 10));
assert_eq!(Date::from_isoywd(2011, 2, Sun), Date::from_ymd(2011, 1, 16));
assert!(DateZ::from_isoywd(2011, 0, Sun).is_none());
assert_eq!(DateZ::from_isoywd(2011, 1, Mon), 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(2011, 2, Mon), DateZ::from_ymd(2011, 1, 10));
assert_eq!(DateZ::from_isoywd(2011, 2, Sun), DateZ::from_ymd(2011, 1, 16));
assert_eq!(Date::from_isoywd(2018, 51, Mon), Date::from_ymd(2018, 12, 17));
assert_eq!(Date::from_isoywd(2018, 51, Sun), Date::from_ymd(2018, 12, 23));
assert_eq!(Date::from_isoywd(2018, 52, Mon), Date::from_ymd(2018, 12, 24));
assert_eq!(Date::from_isoywd(2018, 52, Sun), Date::from_ymd(2018, 12, 30));
assert!(Date::from_isoywd(2018, 53, Mon).is_none());
assert_eq!(DateZ::from_isoywd(2018, 51, Mon), 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(2018, 52, Mon), DateZ::from_ymd(2018, 12, 24));
assert_eq!(DateZ::from_isoywd(2018, 52, Sun), DateZ::from_ymd(2018, 12, 30));
assert!(DateZ::from_isoywd(2018, 53, Mon).is_none());
}
#[test]
@ -439,7 +445,7 @@ mod tests {
for year in range_inclusive(2000i, 2400) {
for week in range_inclusive(1u, 53) {
for &weekday in [Mon, Tue, Wed, Thu, Fri, Sat, Sun].iter() {
let d = Date::from_isoywd(year, week, weekday);
let d = DateZ::from_isoywd(year, week, weekday);
if d.is_some() {
let d = d.unwrap();
assert_eq!(d.weekday(), weekday);
@ -455,11 +461,11 @@ mod tests {
for year in range_inclusive(2000i, 2400) {
for month in range_inclusive(1u, 12) {
for day in range_inclusive(1u, 31) {
let d = Date::from_ymd(year, month, day);
let d = DateZ::from_ymd(year, month, day);
if d.is_some() {
let d = d.unwrap();
let (year_, week_, weekday_) = d.isoweekdate();
let d_ = Date::from_isoywd(year_, week_, weekday_).unwrap();
let d_ = DateZ::from_isoywd(year_, week_, weekday_).unwrap();
assert_eq!(d, d_);
}
}
@ -470,14 +476,14 @@ mod tests {
#[test]
fn test_date_fields() {
fn check(year: int, month: uint, day: uint, ordinal: uint) {
let d1 = Date::from_ymd(year, month, day);
let d1 = DateZ::from_ymd(year, month, day);
assert!(d1.is_some());
assert_eq!(d1.unwrap().year(), year);
assert_eq!(d1.unwrap().month(), month);
assert_eq!(d1.unwrap().day(), day);
assert_eq!(d1.unwrap().ordinal(), ordinal);
let d2 = Date::from_yo(year, ordinal);
let d2 = DateZ::from_yo(year, ordinal);
assert!(d2.is_some());
assert_eq!(d2.unwrap().year(), year);
assert_eq!(d2.unwrap().month(), month);
@ -510,57 +516,57 @@ mod tests {
#[test]
fn test_date_weekday() {
assert_eq!(Date::from_ymd(1582, 10, 15).unwrap().weekday(), Fri);
assert_eq!(Date::from_ymd(1875, 5, 20).unwrap().weekday(), Thu); // ISO 8601 reference date
assert_eq!(Date::from_ymd(2000, 1, 1).unwrap().weekday(), Sat);
assert_eq!(DateZ::from_ymd(1582, 10, 15).unwrap().weekday(), Fri);
assert_eq!(DateZ::from_ymd(1875, 5, 20).unwrap().weekday(), Thu); // ISO 8601 reference date
assert_eq!(DateZ::from_ymd(2000, 1, 1).unwrap().weekday(), Sat);
}
#[test]
fn test_date_with_fields() {
let d = Date::from_ymd(2000, 2, 29).unwrap();
assert_eq!(d.with_year(-400), Date::from_ymd(-400, 2, 29));
let d = DateZ::from_ymd(2000, 2, 29).unwrap();
assert_eq!(d.with_year(-400), DateZ::from_ymd(-400, 2, 29));
assert_eq!(d.with_year(-100), None);
assert_eq!(d.with_year(1600), Date::from_ymd(1600, 2, 29));
assert_eq!(d.with_year(1600), DateZ::from_ymd(1600, 2, 29));
assert_eq!(d.with_year(1900), None);
assert_eq!(d.with_year(2000), Date::from_ymd(2000, 2, 29));
assert_eq!(d.with_year(2000), DateZ::from_ymd(2000, 2, 29));
assert_eq!(d.with_year(2001), None);
assert_eq!(d.with_year(2004), Date::from_ymd(2004, 2, 29));
assert_eq!(d.with_year(2004), DateZ::from_ymd(2004, 2, 29));
assert_eq!(d.with_year(int::MAX), None);
let d = Date::from_ymd(2000, 4, 30).unwrap();
let d = DateZ::from_ymd(2000, 4, 30).unwrap();
assert_eq!(d.with_month(0), None);
assert_eq!(d.with_month(1), Date::from_ymd(2000, 1, 30));
assert_eq!(d.with_month(1), DateZ::from_ymd(2000, 1, 30));
assert_eq!(d.with_month(2), None);
assert_eq!(d.with_month(3), Date::from_ymd(2000, 3, 30));
assert_eq!(d.with_month(4), Date::from_ymd(2000, 4, 30));
assert_eq!(d.with_month(12), Date::from_ymd(2000, 12, 30));
assert_eq!(d.with_month(3), DateZ::from_ymd(2000, 3, 30));
assert_eq!(d.with_month(4), DateZ::from_ymd(2000, 4, 30));
assert_eq!(d.with_month(12), DateZ::from_ymd(2000, 12, 30));
assert_eq!(d.with_month(13), None);
assert_eq!(d.with_month(uint::MAX), None);
let d = Date::from_ymd(2000, 2, 8).unwrap();
let d = DateZ::from_ymd(2000, 2, 8).unwrap();
assert_eq!(d.with_day(0), None);
assert_eq!(d.with_day(1), Date::from_ymd(2000, 2, 1));
assert_eq!(d.with_day(29), Date::from_ymd(2000, 2, 29));
assert_eq!(d.with_day(1), DateZ::from_ymd(2000, 2, 1));
assert_eq!(d.with_day(29), DateZ::from_ymd(2000, 2, 29));
assert_eq!(d.with_day(30), None);
assert_eq!(d.with_day(uint::MAX), None);
let d = Date::from_ymd(2000, 5, 5).unwrap();
let d = DateZ::from_ymd(2000, 5, 5).unwrap();
assert_eq!(d.with_ordinal(0), None);
assert_eq!(d.with_ordinal(1), Date::from_ymd(2000, 1, 1));
assert_eq!(d.with_ordinal(60), Date::from_ymd(2000, 2, 29));
assert_eq!(d.with_ordinal(61), Date::from_ymd(2000, 3, 1));
assert_eq!(d.with_ordinal(366), Date::from_ymd(2000, 12, 31));
assert_eq!(d.with_ordinal(1), DateZ::from_ymd(2000, 1, 1));
assert_eq!(d.with_ordinal(60), DateZ::from_ymd(2000, 2, 29));
assert_eq!(d.with_ordinal(61), DateZ::from_ymd(2000, 3, 1));
assert_eq!(d.with_ordinal(366), DateZ::from_ymd(2000, 12, 31));
assert_eq!(d.with_ordinal(367), None);
assert_eq!(d.with_ordinal(uint::MAX), None);
}
#[test]
fn test_date_ndays_from_ce() {
assert_eq!(Date::from_ymd(1, 1, 1).unwrap().ndays_from_ce(), 1);
assert_eq!(DateZ::from_ymd(1, 1, 1).unwrap().ndays_from_ce(), 1);
for year in range_inclusive(-9999i, 10000) {
assert_eq!(Date::from_ymd(year, 1, 1).unwrap().ndays_from_ce(),
Date::from_ymd(year - 1, 12, 31).unwrap().ndays_from_ce() + 1);
assert_eq!(DateZ::from_ymd(year, 1, 1).unwrap().ndays_from_ce(),
DateZ::from_ymd(year - 1, 12, 31).unwrap().ndays_from_ce() + 1);
}
}
}
@ -570,13 +576,13 @@ mod tests {
*
* The current implementation is optimized for determining year, month, day and day of week.
* 4-bit `YearFlags` map to one of 14 possible classes of year in the Gregorian calendar,
* which are included in every packed `Date` instance.
* which are included in every packed `DateZ` instance.
* The conversion between the packed calendar date (`Mdf`) and the ordinal date (`Of`) is
* based on the moderately-sized lookup table (~1.5KB)
* and the packed representation is chosen for the efficient lookup.
* Every internal data structure does not validate its input,
* but the conversion keeps the valid value valid and the invalid value invalid
* so that the user-facing `Date` can validate the input as late as possible.
* so that the user-facing `DateZ` can validate the input as late as possible.
*/
mod internals {
use std::{i32, num, fmt};

View File

@ -3,242 +3,48 @@
*/
use std::fmt;
use time::Time;
use date::{Date, Weekday};
use time::{Timelike, TimeZ};
use date::{Datelike, DateZ, Weekday};
#[deriving(Eq, TotalEq, Ord, TotalOrd, Hash)]
pub struct DateTime {
date: Date,
time: Time,
pub struct DateTimeZ {
date: DateZ,
time: TimeZ,
}
impl DateTime {
impl DateTimeZ {
#[inline]
pub fn new(date: Date, time: Time) -> DateTime {
DateTime { date: date, time: time }
pub fn new(date: DateZ, time: TimeZ) -> DateTimeZ {
DateTimeZ { date: date, time: time }
}
#[inline]
pub fn from_ymdhms(year: int, month: uint, day: uint,
hour: uint, min: uint, sec: uint) -> Option<DateTime> {
match (Date::from_ymd(year, month, day), Time::from_hms(hour, min, sec)) {
(Some(d), Some(t)) => Some(DateTime::new(d, t)),
hour: uint, min: uint, sec: uint) -> Option<DateTimeZ> {
match (DateZ::from_ymd(year, month, day), TimeZ::from_hms(hour, min, sec)) {
(Some(d), Some(t)) => Some(DateTimeZ::new(d, t)),
(_, _) => None,
}
}
#[inline]
pub fn from_yohms(year: int, ordinal: uint,
hour: uint, min: uint, sec: uint) -> Option<DateTime> {
match (Date::from_yo(year, ordinal), Time::from_hms(hour, min, sec)) {
(Some(d), Some(t)) => Some(DateTime::new(d, t)),
hour: uint, min: uint, sec: uint) -> Option<DateTimeZ> {
match (DateZ::from_yo(year, ordinal), TimeZ::from_hms(hour, min, sec)) {
(Some(d), Some(t)) => Some(DateTimeZ::new(d, t)),
(_, _) => None,
}
}
#[inline]
pub fn from_isoywdhms(year: int, week: uint, weekday: Weekday,
hour: uint, min: uint, sec: uint) -> Option<DateTime> {
match (Date::from_isoywd(year, week, weekday), Time::from_hms(hour, min, sec)) {
(Some(d), Some(t)) => Some(DateTime::new(d, t)),
hour: uint, min: uint, sec: uint) -> Option<DateTimeZ> {
match (DateZ::from_isoywd(year, week, weekday), TimeZ::from_hms(hour, min, sec)) {
(Some(d), Some(t)) => Some(DateTimeZ::new(d, t)),
(_, _) => None,
}
}
/// Returns the year number.
#[inline]
pub fn year(&self) -> int {
self.date.year()
}
/// Returns the absolute year number starting from 1 with a boolean flag,
/// which is false when the year predates the epoch (BCE/BC) and true otherwise (CE/AD).
#[inline]
pub fn year_ce(&self) -> (bool, uint) {
self.date.year_ce()
}
/// Returns the month number starting from 1.
#[inline]
pub fn month(&self) -> uint {
self.date.month()
}
/// Returns the month number starting from 0.
#[inline]
pub fn month0(&self) -> uint {
self.date.month0()
}
/// Returns the day of month starting from 1.
#[inline]
pub fn day(&self) -> uint {
self.date.day()
}
/// Returns the day of month starting from 0.
#[inline]
pub fn day0(&self) -> uint {
self.date.day0()
}
/// Returns the day of year starting from 1.
#[inline]
pub fn ordinal(&self) -> uint {
self.date.ordinal()
}
/// Returns the day of year starting from 0.
#[inline]
pub fn ordinal0(&self) -> uint {
self.date.ordinal0()
}
/// Returns the day of week.
#[inline]
pub fn weekday(&self) -> Weekday {
self.date.weekday()
}
/// Returns the ISO week date: an adjusted year, week number and day of week.
/// The adjusted year may differ from that of the calendar date.
#[inline]
pub fn isoweekdate(&self) -> (int, uint, Weekday) {
self.date.isoweekdate()
}
/// Returns the hour number from 0 to 23.
#[inline]
pub fn hour(&self) -> uint {
self.time.hour()
}
/// Returns the hour number from 1 to 12 with a boolean flag,
/// which is false for AM and true for PM.
#[inline]
pub fn hour12(&self) -> (bool, uint) {
self.time.hour12()
}
/// Returns the minute number from 0 to 59.
#[inline]
pub fn minute(&self) -> uint {
self.time.minute()
}
/// Returns the second number from 0 to 59.
#[inline]
pub fn second(&self) -> uint {
self.time.second()
}
/// Returns the number of nanoseconds since the whole non-leap second.
/// The range from 1,000,000,000 to 1,999,999,999 represents the leap second.
#[inline]
pub fn nanosecond(&self) -> uint {
self.time.nanosecond()
}
/// Makes a new `DateTime` with the year number changed.
///
/// Returns `None` when the resulting `DateTime` would be invalid.
#[inline]
pub fn with_year(&self, year: int) -> Option<DateTime> {
self.date.with_year(year).map(|d| DateTime { date: d, ..*self })
}
/// Makes a new `DateTime` with the month number (starting from 1) changed.
///
/// Returns `None` when the resulting `DateTime` would be invalid.
#[inline]
pub fn with_month(&self, month: uint) -> Option<DateTime> {
self.date.with_month(month).map(|d| DateTime { date: d, ..*self })
}
/// Makes a new `DateTime` with the month number (starting from 0) changed.
///
/// Returns `None` when the resulting `DateTime` would be invalid.
#[inline]
pub fn with_month0(&self, month0: uint) -> Option<DateTime> {
self.date.with_month0(month0).map(|d| DateTime { date: d, ..*self })
}
/// Makes a new `DateTime` with the day of month (starting from 1) changed.
///
/// Returns `None` when the resulting `DateTime` would be invalid.
#[inline]
pub fn with_day(&self, day: uint) -> Option<DateTime> {
self.date.with_day(day).map(|d| DateTime { date: d, ..*self })
}
/// Makes a new `DateTime` with the day of month (starting from 0) changed.
///
/// Returns `None` when the resulting `DateTime` would be invalid.
#[inline]
pub fn with_day0(&self, day0: uint) -> Option<DateTime> {
self.date.with_day0(day0).map(|d| DateTime { date: d, ..*self })
}
/// Makes a new `DateTime` with the day of year (starting from 1) changed.
///
/// Returns `None` when the resulting `DateTime` would be invalid.
#[inline]
pub fn with_ordinal(&self, ordinal: uint) -> Option<DateTime> {
self.date.with_ordinal(ordinal).map(|d| DateTime { date: d, ..*self })
}
/// Makes a new `DateTime` with the day of year (starting from 0) changed.
///
/// Returns `None` when the resulting `DateTime` would be invalid.
#[inline]
pub fn with_ordinal0(&self, ordinal0: uint) -> Option<DateTime> {
self.date.with_ordinal0(ordinal0).map(|d| DateTime { date: d, ..*self })
}
/// Makes a new `Time` with the hour number changed.
///
/// Returns `None` when the resulting `Time` would be invalid.
#[inline]
pub fn with_hour(&self, hour: uint) -> Option<DateTime> {
self.time.with_hour(hour).map(|t| DateTime { time: t, ..*self })
}
/// Makes a new `Time` with the minute number changed.
///
/// Returns `None` when the resulting `Time` would be invalid.
#[inline]
pub fn with_minute(&self, min: uint) -> Option<DateTime> {
self.time.with_minute(min).map(|t| DateTime { time: t, ..*self })
}
/// Makes a new `Time` with the second number changed.
///
/// Returns `None` when the resulting `Time` would be invalid.
#[inline]
pub fn with_second(&self, sec: uint) -> Option<DateTime> {
self.time.with_second(sec).map(|t| DateTime { time: t, ..*self })
}
/// Makes a new `Time` with nanoseconds since the whole non-leap second changed.
///
/// Returns `None` when the resulting `Time` would be invalid.
#[inline]
pub fn with_nanosecond(&self, nano: uint) -> Option<DateTime> {
self.time.with_nanosecond(nano).map(|t| DateTime { time: t, ..*self })
}
/// Returns the number of days since January 1, 1 (Day 1) in the proleptic Gregorian calendar.
#[inline]
pub fn ndays_from_ce(&self) -> int {
self.date.ndays_from_ce()
}
/// Returns the number of non-leap seconds past the last midnight.
#[inline]
pub fn nseconds_from_midnight(&self) -> uint {
self.time.nseconds_from_midnight()
}
/// Returns the number of non-leap seconds since January 1, 1970 0:00:00.
/// Note that this does *not* account for the timezone!
#[inline]
@ -247,7 +53,81 @@ impl DateTime {
}
}
impl fmt::Show for DateTime {
impl Datelike for DateTimeZ {
#[inline] fn year(&self) -> int { self.date.year() }
#[inline] fn month(&self) -> uint { self.date.month() }
#[inline] fn month0(&self) -> uint { self.date.month0() }
#[inline] fn day(&self) -> uint { self.date.day() }
#[inline] fn day0(&self) -> uint { self.date.day0() }
#[inline] fn ordinal(&self) -> uint { self.date.ordinal() }
#[inline] fn ordinal0(&self) -> uint { self.date.ordinal0() }
#[inline] fn weekday(&self) -> Weekday { self.date.weekday() }
#[inline] fn isoweekdate(&self) -> (int, uint, Weekday) { self.date.isoweekdate() }
#[inline]
fn with_year(&self, year: int) -> Option<DateTimeZ> {
self.date.with_year(year).map(|d| DateTimeZ { date: d, ..*self })
}
#[inline]
fn with_month(&self, month: uint) -> Option<DateTimeZ> {
self.date.with_month(month).map(|d| DateTimeZ { date: d, ..*self })
}
#[inline]
fn with_month0(&self, month0: uint) -> Option<DateTimeZ> {
self.date.with_month0(month0).map(|d| DateTimeZ { date: d, ..*self })
}
#[inline]
fn with_day(&self, day: uint) -> Option<DateTimeZ> {
self.date.with_day(day).map(|d| DateTimeZ { date: d, ..*self })
}
#[inline]
fn with_day0(&self, day0: uint) -> Option<DateTimeZ> {
self.date.with_day0(day0).map(|d| DateTimeZ { date: d, ..*self })
}
#[inline]
fn with_ordinal(&self, ordinal: uint) -> Option<DateTimeZ> {
self.date.with_ordinal(ordinal).map(|d| DateTimeZ { date: d, ..*self })
}
#[inline]
fn with_ordinal0(&self, ordinal0: uint) -> Option<DateTimeZ> {
self.date.with_ordinal0(ordinal0).map(|d| DateTimeZ { date: d, ..*self })
}
}
impl Timelike for DateTimeZ {
#[inline] fn hour(&self) -> uint { self.time.hour() }
#[inline] fn minute(&self) -> uint { self.time.minute() }
#[inline] fn second(&self) -> uint { self.time.second() }
#[inline] fn nanosecond(&self) -> uint { self.time.nanosecond() }
#[inline]
fn with_hour(&self, hour: uint) -> Option<DateTimeZ> {
self.time.with_hour(hour).map(|t| DateTimeZ { time: t, ..*self })
}
#[inline]
fn with_minute(&self, min: uint) -> Option<DateTimeZ> {
self.time.with_minute(min).map(|t| DateTimeZ { time: t, ..*self })
}
#[inline]
fn with_second(&self, sec: uint) -> Option<DateTimeZ> {
self.time.with_second(sec).map(|t| DateTimeZ { time: t, ..*self })
}
#[inline]
fn with_nanosecond(&self, nano: uint) -> Option<DateTimeZ> {
self.time.with_nanosecond(nano).map(|t| DateTimeZ { time: t, ..*self })
}
}
impl fmt::Show for DateTimeZ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f.buf, "{}T{}", self.date, self.time)
}
@ -260,7 +140,7 @@ mod tests {
#[test]
fn test_time_nseconds_from_unix_epoch() {
let to_timestamp =
|y,m,d,h,n,s| DateTime::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).unwrap().nseconds_from_unix_epoch();
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, 1), 1);

View File

@ -4,129 +4,136 @@
use std::fmt;
/// ISO 8601 time. Allows for the nanosecond precision and optional leap second representation.
pub trait Timelike {
/// Returns the hour number from 0 to 23.
fn hour(&self) -> uint;
/// Returns the hour number from 1 to 12 with a boolean flag,
/// which is false for AM and true for PM.
#[inline]
fn hour12(&self) -> (bool, uint) {
let hour = self.hour();
let mut hour12 = hour % 12;
if hour12 == 0 { hour12 = 12; }
(hour >= 12, hour12)
}
/// Returns the minute number from 0 to 59.
fn minute(&self) -> uint;
/// Returns the second number from 0 to 59.
fn second(&self) -> uint;
/// Returns the number of nanoseconds since the whole non-leap second.
/// The range from 1,000,000,000 to 1,999,999,999 represents the leap second.
fn nanosecond(&self) -> uint;
/// Makes a new value with the hour number changed.
///
/// Returns `None` when the resulting value would be invalid.
fn with_hour(&self, hour: uint) -> Option<Self>;
/// Makes a new value with the minute number changed.
///
/// Returns `None` when the resulting value would be invalid.
fn with_minute(&self, min: uint) -> Option<Self>;
/// Makes a new value with the second number changed.
///
/// Returns `None` when the resulting value would be invalid.
fn with_second(&self, sec: uint) -> Option<Self>;
/// Makes a new value with nanoseconds since the whole non-leap second changed.
///
/// Returns `None` when the resulting value would be invalid.
fn with_nanosecond(&self, nano: uint) -> Option<Self>;
/// Returns the number of non-leap seconds past the last midnight.
#[inline]
fn nseconds_from_midnight(&self) -> uint {
self.hour() * 3600 + self.minute() * 60 + self.second()
}
}
/// ISO 8601 time without timezone.
/// Allows for the nanosecond precision and optional leap second representation.
#[deriving(Eq, TotalEq, Ord, TotalOrd, Hash)]
pub struct Time {
pub struct TimeZ {
priv hour: u8,
priv min: u8,
priv sec: u8,
priv frac: u32,
}
impl Time {
/// Makes a new `Time` from hour, minute and second.
impl TimeZ {
/// Makes a new `TimeZ` from hour, minute and second.
///
/// Returns `None` on invalid hour, minute and/or second.
#[inline]
pub fn from_hms(hour: uint, min: uint, sec: uint) -> Option<Time> {
Time::from_hms_nano(hour, min, sec, 0)
pub fn from_hms(hour: uint, min: uint, sec: uint) -> Option<TimeZ> {
TimeZ::from_hms_nano(hour, min, sec, 0)
}
/// Makes a new `Time` from hour, minute, second and millisecond.
/// Makes a new `TimeZ` from hour, minute, second and millisecond.
/// The millisecond part can exceed 1,000 in order to represent the leap second.
///
/// Returns `None` on invalid hour, minute, second and/or millisecond.
#[inline]
pub fn from_hms_milli(hour: uint, min: uint, sec: uint, milli: uint) -> Option<Time> {
Time::from_hms_nano(hour, min, sec, milli * 1_000_000)
pub fn from_hms_milli(hour: uint, min: uint, sec: uint, milli: uint) -> Option<TimeZ> {
TimeZ::from_hms_nano(hour, min, sec, milli * 1_000_000)
}
/// Makes a new `Time` from hour, minute, second and microsecond.
/// 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.
///
/// Returns `None` on invalid hour, minute, second and/or microsecond.
#[inline]
pub fn from_hms_micro(hour: uint, min: uint, sec: uint, micro: uint) -> Option<Time> {
Time::from_hms_nano(hour, min, sec, micro * 1_000)
pub fn from_hms_micro(hour: uint, min: uint, sec: uint, micro: uint) -> Option<TimeZ> {
TimeZ::from_hms_nano(hour, min, sec, micro * 1_000)
}
/// Makes a new `Time` 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.
///
/// Returns `None` on invalid hour, minute, second and/or nanosecond.
pub fn from_hms_nano(hour: uint, min: uint, sec: uint, nano: uint) -> Option<Time> {
pub fn from_hms_nano(hour: uint, min: uint, sec: uint, nano: uint) -> Option<TimeZ> {
if hour >= 24 || min >= 60 || sec >= 60 || nano >= 2_000_000_000 { return None; }
Some(Time { hour: hour as u8, min: min as u8, sec: sec as u8, frac: nano as u32 })
}
/// Returns the hour number from 0 to 23.
#[inline]
pub fn hour(&self) -> uint {
self.hour as uint
}
/// Returns the hour number from 1 to 12 with a boolean flag,
/// which is false for AM and true for PM.
#[inline]
pub fn hour12(&self) -> (bool, uint) {
let mut hour12 = self.hour % 12;
if hour12 == 0 { hour12 = 12; }
(self.hour >= 12, hour12 as uint)
}
/// Returns the minute number from 0 to 59.
#[inline]
pub fn minute(&self) -> uint {
self.min as uint
}
/// Returns the second number from 0 to 59.
#[inline]
pub fn second(&self) -> uint {
self.sec as uint
}
/// Returns the number of nanoseconds since the whole non-leap second.
/// The range from 1,000,000,000 to 1,999,999,999 represents the leap second.
#[inline]
pub fn nanosecond(&self) -> uint {
self.frac as uint
}
/// Makes a new `Time` with the hour number changed.
///
/// Returns `None` when the resulting `Time` would be invalid.
#[inline]
pub fn with_hour(&self, hour: uint) -> Option<Time> {
if hour >= 24 { return None; }
Some(Time { hour: hour as u8, ..*self })
}
/// Makes a new `Time` with the minute number changed.
///
/// Returns `None` when the resulting `Time` would be invalid.
#[inline]
pub fn with_minute(&self, min: uint) -> Option<Time> {
if min >= 60 { return None; }
Some(Time { min: min as u8, ..*self })
}
/// Makes a new `Time` with the second number changed.
///
/// Returns `None` when the resulting `Time` would be invalid.
#[inline]
pub fn with_second(&self, sec: uint) -> Option<Time> {
if sec >= 60 { return None; }
Some(Time { sec: sec as u8, ..*self })
}
/// Makes a new `Time` with nanoseconds since the whole non-leap second changed.
///
/// Returns `None` when the resulting `Time` would be invalid.
#[inline]
pub fn with_nanosecond(&self, nano: uint) -> Option<Time> {
if nano >= 2_000_000_000 { return None; }
Some(Time { frac: nano as u32, ..*self })
}
/// Returns the number of non-leap seconds past the last midnight.
#[inline]
pub fn nseconds_from_midnight(&self) -> uint {
self.hour as uint * 3600 + self.min as uint * 60 + self.sec as uint
Some(TimeZ { hour: hour as u8, min: min as u8, sec: sec as u8, frac: nano as u32 })
}
}
impl fmt::Show for Time {
impl Timelike for TimeZ {
#[inline] fn hour(&self) -> uint { self.hour as uint }
#[inline] fn minute(&self) -> uint { self.min as uint }
#[inline] fn second(&self) -> uint { self.sec as uint }
#[inline] fn nanosecond(&self) -> uint { self.frac as uint }
#[inline]
fn with_hour(&self, hour: uint) -> Option<TimeZ> {
if hour >= 24 { return None; }
Some(TimeZ { hour: hour as u8, ..*self })
}
#[inline]
fn with_minute(&self, min: uint) -> Option<TimeZ> {
if min >= 60 { return None; }
Some(TimeZ { min: min as u8, ..*self })
}
#[inline]
fn with_second(&self, sec: uint) -> Option<TimeZ> {
if sec >= 60 { return None; }
Some(TimeZ { sec: sec as u8, ..*self })
}
#[inline]
fn with_nanosecond(&self, nano: uint) -> Option<TimeZ> {
if nano >= 2_000_000_000 { return None; }
Some(TimeZ { frac: nano as u32, ..*self })
}
}
impl fmt::Show for TimeZ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (sec, nano) = if self.frac >= 1_000_000_000 {
(self.sec + 1, self.frac - 1_000_000_000)
@ -153,9 +160,9 @@ mod tests {
#[test]
fn test_time_fmt() {
assert_eq!(Time::from_hms_milli(23, 59, 59, 999).unwrap().to_str(), ~"23:59:59,999");
assert_eq!(Time::from_hms_milli(23, 59, 59, 1_000).unwrap().to_str(), ~"23:59:60");
assert_eq!(Time::from_hms_milli(23, 59, 59, 1_001).unwrap().to_str(), ~"23:59:60,001");
assert_eq!(TimeZ::from_hms_milli(23, 59, 59, 999).unwrap().to_str(), ~"23:59:59,999");
assert_eq!(TimeZ::from_hms_milli(23, 59, 59, 1_000).unwrap().to_str(), ~"23:59:60");
assert_eq!(TimeZ::from_hms_milli(23, 59, 59, 1_001).unwrap().to_str(), ~"23:59:60,001");
}
}