From 75c21b0c3ebb2b13c233c75d0f81f0ac32007707 Mon Sep 17 00:00:00 2001 From: Kang Seonghoon Date: Mon, 31 Mar 2014 14:33:47 +0900 Subject: [PATCH] fixed some issues on negative division/modulo. --- src/chrono/date.rs | 29 +++++++++++++---------------- src/chrono/duration.rs | 17 +++++------------ src/chrono/lib.rs | 8 +++++--- src/chrono/time.rs | 5 +++-- 4 files changed, 26 insertions(+), 33 deletions(-) diff --git a/src/chrono/date.rs b/src/chrono/date.rs index 570a049..5c24d67 100644 --- a/src/chrono/date.rs +++ b/src/chrono/date.rs @@ -3,6 +3,7 @@ */ use std::fmt; +use num::Integer; use duration::Duration; use self::internals::{DateImpl, Of, Mdf, YearFlags}; @@ -381,16 +382,11 @@ impl Add for DateZ { // TODO overflow let year = self.year(); - let mut year_div_400 = year / 400; - let year_mod_400 = (year % 400) as uint; - let mut cycle = internals::yo_to_cycle(year_mod_400, self.of().ordinal()) as int; - cycle += rhs.ndays(); - year_div_400 += cycle / 146097; - cycle %= 146097; - if cycle < 0 { - cycle += 146097; - year_div_400 -= 400; - } + 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_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) }; @@ -411,8 +407,8 @@ impl Sub for DateZ { fn sub(&self, rhs: &DateZ) -> Duration { let year1 = self.year(); let year2 = rhs.year(); - let (year1_div_400, year1_mod_400) = (year1 / 400, year1 % 400); - let (year2_div_400, year2_mod_400) = (year2 / 400, year2 % 400); + let (year1_div_400, year1_mod_400) = year1.div_mod_floor(&400); + let (year2_div_400, year2_mod_400) = year2.div_mod_floor(&400); let cycle1 = internals::yo_to_cycle(year1_mod_400 as uint, self.of().ordinal()) as int; let cycle2 = internals::yo_to_cycle(year2_mod_400 as uint, rhs.of().ordinal()) as int; Duration::days((year1_div_400 - year2_div_400) * 146097 + (cycle1 - cycle2)) @@ -669,6 +665,8 @@ mod tests { check((2014, 1, 1), Duration::days(364), (2014, 12, 31)); check((2014, 1, 1), Duration::days(365*4 + 1), (2018, 1, 1)); check((2014, 1, 1), Duration::days(365*400 + 97), (2414, 1, 1)); + + check((-7, 1, 1), Duration::days(365*12 + 3), (5, 1, 1)); } #[test] @@ -712,6 +710,7 @@ mod tests { */ mod internals { use std::{i32, num, fmt}; + use num::Integer; pub use super::{Weekday, Sun, Mon, Tue, Wed, Thu, Fri, Sat}; /// The internal date representation. This also includes the packed `Mdf` value. @@ -786,8 +785,7 @@ mod internals { ]; pub fn cycle_to_yo(cycle: uint) -> (uint, uint) { - let mut year_mod_400 = cycle / 365; - let mut ordinal0 = cycle % 365; + let (mut year_mod_400, mut ordinal0) = cycle.div_rem(&365); let delta = YEAR_DELTAS[year_mod_400] as uint; if ordinal0 < delta { year_mod_400 -= 1; @@ -805,8 +803,7 @@ mod internals { impl YearFlags { #[inline] pub fn from_year(year: int) -> YearFlags { - let mut year = year % 400; - if year < 0 { year += 400; } + let year = year.mod_floor(&400); unsafe { YearFlags::from_year_mod_400(year) } } diff --git a/src/chrono/duration.rs b/src/chrono/duration.rs index c82c1dc..bf755d9 100644 --- a/src/chrono/duration.rs +++ b/src/chrono/duration.rs @@ -3,6 +3,7 @@ */ use std::{fmt, num}; +use num::Integer; static NANOS_PER_SEC: int = 1_000_000_000; static SECS_PER_DAY: int = 86400; @@ -16,13 +17,9 @@ pub struct Duration { impl Duration { pub fn new(days: int, secs: int, nanos: int) -> Option { - let mut secs_ = nanos / NANOS_PER_SEC; - let mut nanos = nanos % NANOS_PER_SEC; - if nanos < 0 { secs_ -= 1; nanos += NANOS_PER_SEC; } + let (secs_, nanos) = nanos.div_mod_floor(&NANOS_PER_SEC); let secs = match secs.checked_add(&secs_) { Some(v) => v, None => return None }; - let mut days_ = secs / SECS_PER_DAY; - let mut secs = secs % SECS_PER_DAY; - if secs < 0 { days_ -= 1; secs += SECS_PER_DAY; } + let (days_, secs) = secs.div_mod_floor(&SECS_PER_DAY); let days = match days.checked_add(&days_) { Some(v) => v, None => return None }; Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 }) } @@ -54,9 +51,7 @@ impl Duration { #[inline] pub fn seconds(secs: int) -> Duration { - let mut days = secs / SECS_PER_DAY; - let mut secs = secs % SECS_PER_DAY; - if secs < 0 { days -= 1; secs += SECS_PER_DAY; } + let (days, secs) = secs.div_mod_floor(&SECS_PER_DAY); Duration { secs: secs as u32, ..Duration::days(days) } } @@ -72,9 +67,7 @@ impl Duration { #[inline] pub fn nanoseconds(nanos: int) -> Duration { - let mut secs = nanos / NANOS_PER_SEC; - let mut nanos = nanos % NANOS_PER_SEC; - if nanos < 0 { secs -= 1; nanos += NANOS_PER_SEC; } + let (secs, nanos) = nanos.div_mod_floor(&NANOS_PER_SEC); Duration { nanos: nanos as u32, ..Duration::seconds(secs) } } diff --git a/src/chrono/lib.rs b/src/chrono/lib.rs index c8a9a64..994ce0d 100644 --- a/src/chrono/lib.rs +++ b/src/chrono/lib.rs @@ -1,7 +1,9 @@ -#[crate_id = "chrono#0.1.0"]; -#[crate_type = "lib"]; +#![crate_id = "chrono#0.1.0"] +#![crate_type = "lib"] -#[feature(globs, macro_rules)]; +#![feature(globs, macro_rules)] + +extern crate num; pub mod duration; pub mod date; diff --git a/src/chrono/time.rs b/src/chrono/time.rs index 5e14df4..57ea56f 100644 --- a/src/chrono/time.rs +++ b/src/chrono/time.rs @@ -3,6 +3,7 @@ */ use std::fmt; +use num::Integer; use duration::Duration; pub trait Timelike { @@ -146,8 +147,8 @@ impl Add for TimeZ { nanos -= maxnanos; secs += 1; } - let (s, mins) = (secs % 60, secs / 60); - let (m, hours) = (mins % 60, mins / 60); + let (mins, s) = secs.div_rem(&60); + let (hours, m) = mins.div_rem(&60); let h = hours % 24; TimeZ { hour: h as u8, min: m as u8, sec: s as u8, frac: nanos } }