0.1.2: no more `num` dependency, multidispatched addition.

- `num` dependency is gone. It was only used for floored division
  and it is not hard to copy only that portion from num.
- `Duration + Date` (or so) was blocked by rust-lang/rust#7590,
  which has been subsequently fixed.
- Removed unused `unsafe` checks.
This commit is contained in:
Kang Seonghoon 2014-11-24 14:49:13 +09:00
parent 0a04ae1aa9
commit 86665d0a7f
10 changed files with 95 additions and 46 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "chrono" name = "chrono"
version = "0.1.1" version = "0.1.2"
authors = ["Kang Seonghoon <public+rust@mearie.org>"] authors = ["Kang Seonghoon <public+rust@mearie.org>"]
description = "Date and time library for Rust" description = "Date and time library for Rust"
@ -13,9 +13,6 @@ license = "MIT/Apache-2.0"
[lib] [lib]
name = "chrono" name = "chrono"
[dependencies.num]
git = "https://github.com/rust-lang/num"
[dependencies.time] [dependencies.time]
git = "https://github.com/rust-lang/time" git = "https://github.com/rust-lang/time"

View File

@ -263,13 +263,10 @@ impl<Off:Offset> Add<Duration,Date<Off>> for Date<Off> {
} }
} }
/*
// Rust issue #7590, the current coherence checker can't handle multiple Add impls
impl<Off:Offset> Add<Date<Off>,Date<Off>> for Duration { impl<Off:Offset> Add<Date<Off>,Date<Off>> for Duration {
#[inline] #[inline]
fn add(&self, rhs: &Date<Off>) -> Date<Off> { rhs.add(self) } fn add(&self, rhs: &Date<Off>) -> Date<Off> { rhs.add(self) }
} }
*/
impl<Off:Offset, Off2:Offset> Sub<Date<Off2>,Duration> for Date<Off> { impl<Off:Offset, Off2:Offset> Sub<Date<Off2>,Duration> for Date<Off> {
fn sub(&self, rhs: &Date<Off2>) -> Duration { fn sub(&self, rhs: &Date<Off2>) -> Duration {

View File

@ -185,13 +185,10 @@ impl<Off:Offset> Add<Duration,DateTime<Off>> for DateTime<Off> {
} }
} }
/*
// Rust issue #7590, the current coherence checker can't handle multiple Add impls
impl<Off:Offset> Add<DateTime<Off>,DateTime<Off>> for Duration { impl<Off:Offset> Add<DateTime<Off>,DateTime<Off>> for Duration {
#[inline] #[inline]
fn add(&self, rhs: &DateTime<Off>) -> DateTime<Off> { rhs.add(self) } fn add(&self, rhs: &DateTime<Off>) -> DateTime<Off> { rhs.add(self) }
} }
*/
impl<Off:Offset, Off2:Offset> Sub<DateTime<Off2>,Duration> for DateTime<Off> { impl<Off:Offset, Off2:Offset> Sub<DateTime<Off2>,Duration> for DateTime<Off> {
fn sub(&self, rhs: &DateTime<Off2>) -> Duration { fn sub(&self, rhs: &DateTime<Off2>) -> Duration {

70
src/div.rs Normal file
View File

@ -0,0 +1,70 @@
// This is a part of rust-chrono.
// Copyright (c) 2014, Kang Seonghoon.
// Copyright 2013-2014 The Rust Project Developers.
// See README.md and LICENSE.txt for details.
//! Integer division utilities. (Shamelessly copied from [num](https://github.com/rust-lang/num/))
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
use std::num::Int;
/// Same as `(a / b, a % b)`.
#[inline]
pub fn div_rem<T: Int>(a: T, b: T) -> (T, T) {
(a / b, a % b)
}
/// Same as `let (q, r) = div_mod_floor(a, b); r`.
#[inline]
pub fn mod_floor<T: Int>(a: T, b: T) -> T {
let zero = Int::zero();
match a % b {
r if (r > zero && b < zero) || (r < zero && b > zero) => r + b,
r => r,
}
}
/// Calculates a floored integer quotient and modulo.
#[inline]
pub fn div_mod_floor<T: Int>(a: T, b: T) -> (T, T) {
let zero = Int::zero();
let one = Int::one();
match (a / b, a % b) {
(d, r) if (r > zero && b < zero) || (r < zero && b > zero) => (d - one, r + b),
(d, r) => (d, r),
}
}
#[cfg(test)]
mod tests {
use super::{mod_floor, div_mod_floor};
#[test]
fn test_mod_floor() {
assert_eq!(mod_floor( 8i, 3), 2);
assert_eq!(mod_floor( 8i, -3), -1);
assert_eq!(mod_floor(-8i, 3), 1);
assert_eq!(mod_floor(-8i, -3), -2);
assert_eq!(mod_floor( 1i, 2), 1);
assert_eq!(mod_floor( 1i, -2), -1);
assert_eq!(mod_floor(-1i, 2), 1);
assert_eq!(mod_floor(-1i, -2), -1);
}
#[test]
fn test_div_mod_floor() {
assert_eq!(div_mod_floor( 8i, 3), ( 2, 2));
assert_eq!(div_mod_floor( 8i, -3), (-3, -1));
assert_eq!(div_mod_floor(-8i, 3), (-3, 1));
assert_eq!(div_mod_floor(-8i, -3), ( 2, -2));
assert_eq!(div_mod_floor( 1i, 2), ( 0, 1));
assert_eq!(div_mod_floor( 1i, -2), (-1, -1));
assert_eq!(div_mod_floor(-1i, 2), (-1, 1));
assert_eq!(div_mod_floor(-1i, -2), ( 0, -1));
}
}

View File

@ -13,7 +13,6 @@ Experimental date and time handling for Rust.
#![feature(macro_rules)] #![feature(macro_rules)]
#![deny(missing_docs)] #![deny(missing_docs)]
extern crate num;
extern crate "time" as stdtime; extern crate "time" as stdtime;
pub use duration::Duration; pub use duration::Duration;
@ -26,6 +25,7 @@ pub use date::Date;
pub use time::Time; pub use time::Time;
pub use datetime::DateTime; pub use datetime::DateTime;
mod div;
pub mod duration { pub mod duration {
//! ISO 8601 duration. //! ISO 8601 duration.
//! //!

View File

@ -8,9 +8,9 @@
use std::fmt; use std::fmt;
use std::num::Int; use std::num::Int;
use num::Integer;
use {Weekday, Datelike}; use {Weekday, Datelike};
use div::div_mod_floor;
use duration::Duration; use duration::Duration;
use naive::time::NaiveTime; use naive::time::NaiveTime;
use naive::datetime::NaiveDateTime; use naive::datetime::NaiveDateTime;
@ -148,9 +148,9 @@ impl NaiveDate {
/// Returns `None` on the out-of-range date. /// Returns `None` on the out-of-range date.
pub fn from_num_days_from_ce_opt(days: i32) -> Option<NaiveDate> { pub fn from_num_days_from_ce_opt(days: i32) -> Option<NaiveDate> {
let days = days + 365; // make January 1, 1 BCE equal to day 0 let days = days + 365; // make January 1, 1 BCE equal to day 0
let (year_div_400, cycle) = days.div_mod_floor(&146097); let (year_div_400, cycle) = div_mod_floor(days, 146097);
let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32);
let flags = unsafe { YearFlags::from_year_mod_400(year_mod_400 as i32) }; let flags = YearFlags::from_year_mod_400(year_mod_400 as i32);
NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32,
Of::new(ordinal, flags)) Of::new(ordinal, flags))
} }
@ -382,33 +382,30 @@ impl Add<Duration,NaiveDate> for NaiveDate {
// TODO overflow currently fails // TODO overflow currently fails
let year = self.year(); let year = self.year();
let (mut year_div_400, year_mod_400) = year.div_mod_floor(&400); let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400);
let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal()); let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal());
let cycle = (cycle as i32).checked_add(rhs.num_days().to_i32().unwrap()).unwrap(); let cycle = (cycle as i32).checked_add(rhs.num_days().to_i32().unwrap()).unwrap();
let (cycle_div_400y, cycle) = cycle.div_mod_floor(&146097); let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146097);
year_div_400 += cycle_div_400y; year_div_400 += cycle_div_400y;
let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32);
let flags = unsafe { YearFlags::from_year_mod_400(year_mod_400 as i32) }; let flags = YearFlags::from_year_mod_400(year_mod_400 as i32);
NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32,
Of::new(ordinal, flags)).unwrap() Of::new(ordinal, flags)).unwrap()
} }
} }
/*
// Rust issue #7590, the current coherence checker can't handle multiple Add impls
impl Add<NaiveDate,NaiveDate> for Duration { impl Add<NaiveDate,NaiveDate> for Duration {
#[inline] #[inline]
fn add(&self, rhs: &NaiveDate) -> NaiveDate { rhs.add(self) } fn add(&self, rhs: &NaiveDate) -> NaiveDate { rhs.add(self) }
} }
*/
impl Sub<NaiveDate,Duration> for NaiveDate { impl Sub<NaiveDate,Duration> for NaiveDate {
fn sub(&self, rhs: &NaiveDate) -> Duration { fn sub(&self, rhs: &NaiveDate) -> Duration {
let year1 = self.year(); let year1 = self.year();
let year2 = rhs.year(); let year2 = rhs.year();
let (year1_div_400, year1_mod_400) = year1.div_mod_floor(&400); let (year1_div_400, year1_mod_400) = div_mod_floor(year1, 400);
let (year2_div_400, year2_mod_400) = year2.div_mod_floor(&400); let (year2_div_400, year2_mod_400) = div_mod_floor(year2, 400);
let cycle1 = internals::yo_to_cycle(year1_mod_400 as u32, self.of().ordinal()) as i64; let cycle1 = internals::yo_to_cycle(year1_mod_400 as u32, self.of().ordinal()) as i64;
let cycle2 = internals::yo_to_cycle(year2_mod_400 as u32, rhs.of().ordinal()) as i64; let cycle2 = internals::yo_to_cycle(year2_mod_400 as u32, rhs.of().ordinal()) as i64;
Duration::days((year1_div_400 as i64 - year2_div_400 as i64) * 146097 + (cycle1 - cycle2)) Duration::days((year1_div_400 as i64 - year2_div_400 as i64) * 146097 + (cycle1 - cycle2))
@ -698,7 +695,7 @@ mod tests {
let lhs = NaiveDate::from_ymd(y1, m1, d1); let lhs = NaiveDate::from_ymd(y1, m1, d1);
let sum = NaiveDate::from_ymd(y, m, d); let sum = NaiveDate::from_ymd(y, m, d);
assert_eq!(lhs + rhs, sum); assert_eq!(lhs + rhs, sum);
//assert_eq!(rhs + lhs, sum); assert_eq!(rhs + lhs, sum);
} }
check((2014, 1, 1), Duration::zero(), (2014, 1, 1)); check((2014, 1, 1), Duration::zero(), (2014, 1, 1));
@ -780,8 +777,8 @@ mod tests {
#[allow(dead_code)] // some internal methods have been left for consistency #[allow(dead_code)] // some internal methods have been left for consistency
mod internals { mod internals {
use std::{i32, num, fmt}; use std::{i32, num, fmt};
use num::Integer;
use Weekday; use Weekday;
use div::{div_rem, mod_floor};
/// The internal date representation. This also includes the packed `Mdf` value. /// The internal date representation. This also includes the packed `Mdf` value.
pub type DateImpl = i32; pub type DateImpl = i32;
@ -855,7 +852,7 @@ mod internals {
]; ];
pub fn cycle_to_yo(cycle: u32) -> (u32, u32) { pub fn cycle_to_yo(cycle: u32) -> (u32, u32) {
let (mut year_mod_400, mut ordinal0) = cycle.div_rem(&365); let (mut year_mod_400, mut ordinal0) = div_rem(cycle, 365);
let delta = YEAR_DELTAS[year_mod_400 as uint] as u32; let delta = YEAR_DELTAS[year_mod_400 as uint] as u32;
if ordinal0 < delta { if ordinal0 < delta {
year_mod_400 -= 1; year_mod_400 -= 1;
@ -873,12 +870,12 @@ mod internals {
impl YearFlags { impl YearFlags {
#[inline] #[inline]
pub fn from_year(year: i32) -> YearFlags { pub fn from_year(year: i32) -> YearFlags {
let year = year.mod_floor(&400); let year = mod_floor(year, 400);
unsafe { YearFlags::from_year_mod_400(year) } YearFlags::from_year_mod_400(year)
} }
#[inline] #[inline]
pub unsafe fn from_year_mod_400(year: i32) -> YearFlags { pub fn from_year_mod_400(year: i32) -> YearFlags {
YEAR_TO_FLAGS[year as uint] YEAR_TO_FLAGS[year as uint]
} }

View File

@ -8,9 +8,9 @@
use std::fmt; use std::fmt;
use std::num::Int; use std::num::Int;
use num::Integer;
use {Weekday, Timelike, Datelike}; use {Weekday, Timelike, Datelike};
use div::div_mod_floor;
use duration::Duration; use duration::Duration;
use naive::time::NaiveTime; use naive::time::NaiveTime;
use naive::date::NaiveDate; use naive::date::NaiveDate;
@ -49,7 +49,7 @@ impl NaiveDateTime {
/// Returns `None` on the out-of-range number of seconds and/or invalid nanosecond. /// Returns `None` on the out-of-range number of seconds and/or invalid nanosecond.
#[inline] #[inline]
pub fn from_num_seconds_from_unix_epoch_opt(secs: i64, nsecs: u32) -> Option<NaiveDateTime> { pub fn from_num_seconds_from_unix_epoch_opt(secs: i64, nsecs: u32) -> Option<NaiveDateTime> {
let (days, secs) = secs.div_mod_floor(&86400); let (days, secs) = div_mod_floor(secs, 86400);
let date = days.to_i32().and_then(|days| days.checked_add(719163)) let date = days.to_i32().and_then(|days| days.checked_add(719163))
.and_then(|days_ce| NaiveDate::from_num_days_from_ce_opt(days_ce)); .and_then(|days_ce| NaiveDate::from_num_days_from_ce_opt(days_ce));
let time = NaiveTime::from_num_seconds_from_midnight_opt(secs as u32, nsecs); let time = NaiveTime::from_num_seconds_from_midnight_opt(secs as u32, nsecs);
@ -183,13 +183,10 @@ impl Add<Duration,NaiveDateTime> for NaiveDateTime {
} }
} }
/*
// Rust issue #7590, the current coherence checker can't handle multiple Add impls
impl Add<NaiveDateTime,NaiveDateTime> for Duration { impl Add<NaiveDateTime,NaiveDateTime> for Duration {
#[inline] #[inline]
fn add(&self, rhs: &NaiveDateTime) -> NaiveDateTime { rhs.add(self) } fn add(&self, rhs: &NaiveDateTime) -> NaiveDateTime { rhs.add(self) }
} }
*/
impl Sub<NaiveDateTime,Duration> for NaiveDateTime { impl Sub<NaiveDateTime,Duration> for NaiveDateTime {
fn sub(&self, rhs: &NaiveDateTime) -> Duration { fn sub(&self, rhs: &NaiveDateTime) -> Duration {

View File

@ -8,9 +8,9 @@
use std::fmt; use std::fmt;
use std::num::Int; use std::num::Int;
use num::Integer;
use Timelike; use Timelike;
use div::div_mod_floor;
use offset::Offset; use offset::Offset;
use duration::Duration; use duration::Duration;
use format::DelayedFormat; use format::DelayedFormat;
@ -126,8 +126,8 @@ impl NaiveTime {
/// Returns a triple of the hour, minute and second numbers. /// Returns a triple of the hour, minute and second numbers.
fn hms(&self) -> (u32, u32, u32) { fn hms(&self) -> (u32, u32, u32) {
let (mins, sec) = self.secs.div_mod_floor(&60); let (mins, sec) = div_mod_floor(self.secs, 60);
let (hour, min) = mins.div_mod_floor(&60); let (hour, min) = div_mod_floor(mins, 60);
(hour, min, sec) (hour, min, sec)
} }
} }
@ -190,13 +190,10 @@ impl Add<Duration,NaiveTime> for NaiveTime {
} }
} }
/*
// Rust issue #7590, the current coherence checker can't handle multiple Add impls
impl Add<NaiveTime,NaiveTime> for Duration { impl Add<NaiveTime,NaiveTime> for Duration {
#[inline] #[inline]
fn add(&self, rhs: &NaiveTime) -> NaiveTime { rhs.add(self) } fn add(&self, rhs: &NaiveTime) -> NaiveTime { rhs.add(self) }
} }
*/
impl Sub<NaiveTime,Duration> for NaiveTime { impl Sub<NaiveTime,Duration> for NaiveTime {
fn sub(&self, rhs: &NaiveTime) -> Duration { fn sub(&self, rhs: &NaiveTime) -> Duration {
@ -303,7 +300,7 @@ mod tests {
fn test_time_add() { fn test_time_add() {
fn check(lhs: NaiveTime, rhs: Duration, sum: NaiveTime) { fn check(lhs: NaiveTime, rhs: Duration, sum: NaiveTime) {
assert_eq!(lhs + rhs, sum); assert_eq!(lhs + rhs, sum);
//assert_eq!(rhs + lhs, sum); assert_eq!(rhs + lhs, sum);
} }
let hmsm = |h,m,s,mi| NaiveTime::from_hms_milli(h, m, s, mi); let hmsm = |h,m,s,mi| NaiveTime::from_hms_milli(h, m, s, mi);

View File

@ -9,9 +9,9 @@
use std::fmt; use std::fmt;
use std::str::MaybeOwned; use std::str::MaybeOwned;
use stdtime; use stdtime;
use num::Integer;
use {Weekday, Datelike, Timelike}; use {Weekday, Datelike, Timelike};
use div::div_mod_floor;
use duration::Duration; use duration::Duration;
use naive::date::NaiveDate; use naive::date::NaiveDate;
use naive::time::NaiveTime; use naive::time::NaiveTime;
@ -365,8 +365,8 @@ impl fmt::Show for FixedOffset {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let offset = self.local_minus_utc; let offset = self.local_minus_utc;
let (sign, offset) = if offset < 0 {('-', -offset)} else {('+', offset)}; let (sign, offset) = if offset < 0 {('-', -offset)} else {('+', offset)};
let (mins, sec) = offset.div_mod_floor(&60); let (mins, sec) = div_mod_floor(offset, 60);
let (hour, min) = mins.div_mod_floor(&60); let (hour, min) = div_mod_floor(mins, 60);
if sec == 0 { if sec == 0 {
write!(f, "{}{:02}:{:02}", sign, hour, min) write!(f, "{}{:02}:{:02}", sign, hour, min)
} else { } else {

View File

@ -113,13 +113,10 @@ impl<Off:Offset> Add<Duration,Time<Off>> for Time<Off> {
} }
} }
/*
// Rust issue #7590, the current coherence checker can't handle multiple Add impls
impl<Off:Offset> Add<Time<Off>,Time<Off>> for Duration { impl<Off:Offset> Add<Time<Off>,Time<Off>> for Duration {
#[inline] #[inline]
fn add(&self, rhs: &Time<Off>) -> Time<Off> { rhs.add(self) } fn add(&self, rhs: &Time<Off>) -> Time<Off> { rhs.add(self) }
} }
*/
impl<Off:Offset, Off2:Offset> Sub<Time<Off2>,Duration> for Time<Off> { impl<Off:Offset, Off2:Offset> Sub<Time<Off2>,Duration> for Time<Off> {
fn sub(&self, rhs: &Time<Off2>) -> Duration { fn sub(&self, rhs: &Time<Off2>) -> Duration {