switched the internal Date representation from Mdf to Of; made most Date operations representation-agnostic.

This commit is contained in:
Kang Seonghoon 2014-03-31 15:34:21 +09:00
parent 75c21b0c3e
commit 0f6ccf0728
1 changed files with 45 additions and 36 deletions

View File

@ -206,28 +206,32 @@ pub trait Datelike {
/// Also supports the conversion from ISO 8601 ordinal and week date.
#[deriving(Eq, TotalEq, Ord, TotalOrd, Hash)]
pub struct DateZ {
priv ymdf: DateImpl, // (year << 13) | mdf
priv ymdf: DateImpl, // (year << 13) | of
}
impl DateZ {
/// The internal constructor with the verification.
fn new(year: int, mdf: Mdf) -> Option<DateZ> {
if year >= MIN_YEAR && year <= MAX_YEAR && mdf.valid() {
let Mdf(mdf) = mdf;
Some(DateZ { ymdf: ((year << 13) as DateImpl) | (mdf as DateImpl) })
/// Makes a new `DateZ` from year and packed ordinal-flags, with a verification.
fn from_of(year: int, of: Of) -> Option<DateZ> {
if year >= MIN_YEAR && year <= MAX_YEAR && of.valid() {
let Of(of) = of;
Some(DateZ { ymdf: ((year << 13) as DateImpl) | (of as DateImpl) })
} else {
None
}
}
/// Makes a new `DateZ` from year and packed month-day-flags, with a verification.
fn from_mdf(year: int, mdf: Mdf) -> Option<DateZ> {
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.
///
/// Returns `None` on the out-of-range date, invalid month and/or day.
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);
DateZ::new(year, mdf)
DateZ::from_mdf(year, Mdf::new(month, day, flags))
}
/// Makes a new `DateZ` from year and day of year (DOY or "ordinal").
@ -236,8 +240,7 @@ impl DateZ {
/// Returns `None` on the out-of-range date and/or invalid DOY.
pub fn from_yo(year: int, ordinal: uint) -> Option<DateZ> {
let flags = YearFlags::from_year(year);
let mdf = Of::new(ordinal, flags).to_mdf();
DateZ::new(year, mdf)
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).
@ -254,18 +257,15 @@ impl DateZ {
let delta = flags.isoweek_delta();
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();
DateZ::new(year - 1, mdf)
DateZ::from_of(year - 1, Of::new(weekord + prevflags.ndays() - delta, prevflags))
} else {
let ordinal = weekord - delta;
let ndays = flags.ndays();
if ordinal <= ndays { // this year
let mdf = Of::new(ordinal, flags).to_mdf();
DateZ::new(year, mdf)
DateZ::from_of(year, Of::new(ordinal, flags))
} else { // ordinal > ndays, next year
let nextflags = YearFlags::from_year(year + 1);
let mdf = Of::new(ordinal - ndays, nextflags).to_mdf();
DateZ::new(year + 1, mdf)
DateZ::from_of(year + 1, Of::new(ordinal - ndays, nextflags))
}
}
} else {
@ -273,26 +273,34 @@ impl DateZ {
}
}
/// Returns the packed month, day and year flags.
/// Returns the packed month-day-flags.
#[inline]
fn mdf(&self) -> Mdf {
Mdf((self.ymdf & 0b1111_11111_1111) as uint)
self.of().to_mdf()
}
/// Returns the packed ordinal and year flags.
/// Returns the packed ordinal-flags.
#[inline]
fn of(&self) -> Of {
self.mdf().to_of()
Of((self.ymdf & 0b1111_11111_1111) as uint)
}
/// Makes a new `DateZ` with the packed month, day and year flags changed.
/// Makes a new `DateZ` with the packed month-day-flags changed.
///
/// Returns `None` when the resulting `DateZ` would be invalid.
#[inline]
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 })
self.with_of(mdf.to_of())
}
/// Makes a new `DateZ` with the packed ordinal-flags changed.
///
/// Returns `None` when the resulting `DateZ` would be invalid.
#[inline]
fn with_of(&self, of: Of) -> Option<DateZ> {
if of.valid() {
let Of(of) = of;
Some(DateZ { ymdf: (self.ymdf & !0b111111111_1111) | of as DateImpl })
} else {
None
}
@ -300,14 +308,12 @@ impl DateZ {
#[inline]
pub fn succ(&self) -> Option<DateZ> {
let mdf = self.of().succ().to_mdf();
self.with_mdf(mdf).or_else(|| DateZ::from_ymd(self.year() + 1, 1, 1))
self.with_of(self.of().succ()).or_else(|| DateZ::from_ymd(self.year() + 1, 1, 1))
}
#[inline]
pub fn pred(&self) -> Option<DateZ> {
let mdf = self.of().pred().to_mdf();
self.with_mdf(mdf).or_else(|| DateZ::from_ymd(self.year() - 1, 12, 31))
self.with_of(self.of().pred()).or_else(|| DateZ::from_ymd(self.year() - 1, 12, 31))
}
}
@ -340,10 +346,14 @@ impl Datelike for DateZ {
#[inline]
fn with_year(&self, year: int) -> Option<DateZ> {
// we need to operate with `mdf` since we should keep the month and day number as is
let mdf = self.mdf();
// adjust the flags as needed
let flags = YearFlags::from_year(year);
let mdf = self.mdf().with_flags(flags);
DateZ::new(year, mdf)
let mdf = mdf.with_flags(flags);
DateZ::from_mdf(year, mdf)
}
#[inline]
@ -368,12 +378,12 @@ impl Datelike for DateZ {
#[inline]
fn with_ordinal(&self, ordinal: uint) -> Option<DateZ> {
self.with_mdf(self.mdf().to_of().with_ordinal(ordinal).to_mdf())
self.with_of(self.of().with_ordinal(ordinal))
}
#[inline]
fn with_ordinal0(&self, ordinal0: uint) -> Option<DateZ> {
self.with_mdf(self.mdf().to_of().with_ordinal(ordinal0 + 1).to_mdf())
self.with_of(self.of().with_ordinal(ordinal0 + 1))
}
}
@ -383,15 +393,14 @@ impl Add<Duration,DateZ> for DateZ {
let year = self.year();
let (mut year_div_400, year_mod_400) = year.div_mod_floor(&400);
let cycle = internals::yo_to_cycle(year_mod_400 as uint, self.of().ordinal()) as int;
let cycle = cycle + rhs.ndays();
let cycle = internals::yo_to_cycle(year_mod_400 as uint, self.of().ordinal());
let cycle = cycle as int + rhs.ndays();
let (cycle_div_400y, cycle) = cycle.div_mod_floor(&146097);
year_div_400 += cycle_div_400y;
let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as uint);
let flags = unsafe { YearFlags::from_year_mod_400(year_mod_400 as int) };
let mdf = Of::new(ordinal, flags).to_mdf();
DateZ::new(year_div_400 * 400 + year_mod_400 as int, mdf).unwrap()
DateZ::from_of(year_div_400 * 400 + year_mod_400 as int, Of::new(ordinal, flags)).unwrap()
}
}