diff --git a/src/date.rs b/src/date.rs index 9b5d944..66af09d 100644 --- a/src/date.rs +++ b/src/date.rs @@ -832,6 +832,7 @@ mod tests { check((2014, 1, 1), Duration::zero(), (2014, 1, 1)); check((2014, 1, 1), Duration::seconds(86399), (2014, 1, 1)); + check((2014, 1, 1), Duration::seconds(-86399), (2014, 1, 1)); // always round towards zero check((2014, 1, 1), Duration::days(1), (2014, 1, 2)); check((2014, 1, 1), Duration::days(-1), (2013, 12, 31)); check((2014, 1, 1), Duration::days(364), (2014, 12, 31)); diff --git a/src/datetime.rs b/src/datetime.rs index 67190cf..b7dba96 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -191,7 +191,9 @@ impl Timelike for DateTimeZ { impl Add for DateTimeZ { fn add(&self, rhs: &Duration) -> DateTimeZ { - let mut date = self.date + *rhs; + // we want `(DateZ + days in Duration) + (TimeZ + secs/nanos in Duration)` + // to be equal to `DateTimeZ + Duration`, but `DateZ + Duration` rounds towards zero. + let mut date = self.date + Duration::days(rhs.to_tuple().val0()); let time = self.time + *rhs; if time < self.time { // since the time portion of the duration is always positive and bounded, @@ -232,6 +234,8 @@ mod tests { let ymdhms = |y,m,d,h,n,s| DateTimeZ::from_ymdhms(y,m,d,h,n,s); assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) + Duration::seconds(3600 + 60 + 1), ymdhms(2014, 5, 6, 8, 9, 10)); + assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) + Duration::seconds(-(3600 + 60 + 1)), + ymdhms(2014, 5, 6, 6, 7, 8)); assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) + Duration::seconds(86399), ymdhms(2014, 5, 7, 7, 8, 8)); assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) + Duration::seconds(86400 * 10),