switches to std::time::duration::Duration.
This commit is contained in:
parent
80ed400689
commit
10c580f664
|
@ -211,7 +211,7 @@ mod tests {
|
||||||
use offset::{Offset, UTC, FixedOffset};
|
use offset::{Offset, UTC, FixedOffset};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(uppercase_variables)]
|
#[allow(non_snake_case)]
|
||||||
fn test_datetime_offset() {
|
fn test_datetime_offset() {
|
||||||
let EST = FixedOffset::east(5*60*60);
|
let EST = FixedOffset::east(5*60*60);
|
||||||
let EDT = FixedOffset::east(4*60*60);
|
let EDT = FixedOffset::east(4*60*60);
|
||||||
|
|
609
src/duration.rs
609
src/duration.rs
|
@ -1,609 +0,0 @@
|
||||||
// This is a part of rust-chrono.
|
|
||||||
// Copyright (c) 2014, Kang Seonghoon.
|
|
||||||
// See README.md and LICENSE.txt for details.
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* ISO 8601 duration.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use std::{fmt, num, i32};
|
|
||||||
use num::Integer;
|
|
||||||
|
|
||||||
/// `Duration`'s `days` component should have no more than this value.
|
|
||||||
static MIN_DAYS: i32 = i32::MIN;
|
|
||||||
/// `Duration`'s `days` component should have no less than this value.
|
|
||||||
static MAX_DAYS: i32 = i32::MAX;
|
|
||||||
|
|
||||||
/// The number of nanoseconds in seconds.
|
|
||||||
static NANOS_PER_SEC: i32 = 1_000_000_000;
|
|
||||||
/// The number of (non-leap) seconds in days.
|
|
||||||
static SECS_PER_DAY: i32 = 86400;
|
|
||||||
|
|
||||||
macro_rules! try_opt(
|
|
||||||
($e:expr) => (match $e { Some(v) => v, None => return None })
|
|
||||||
)
|
|
||||||
|
|
||||||
/// ISO 8601 time duration with nanosecond precision.
|
|
||||||
/// This also allows for the negative duration; see individual methods for details.
|
|
||||||
#[deriving(PartialEq, Eq, PartialOrd, Ord, Clone)]
|
|
||||||
pub struct Duration {
|
|
||||||
days: i32,
|
|
||||||
secs: u32,
|
|
||||||
nanos: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The minimum possible `Duration`.
|
|
||||||
pub static MIN: Duration = Duration { days: MIN_DAYS, secs: 0, nanos: 0 };
|
|
||||||
/// The maximum possible `Duration`.
|
|
||||||
pub static MAX: Duration = Duration { days: MAX_DAYS, secs: SECS_PER_DAY as u32 - 1,
|
|
||||||
nanos: NANOS_PER_SEC as u32 - 1 };
|
|
||||||
|
|
||||||
impl Duration {
|
|
||||||
/// Makes a new `Duration` with given number of days, seconds and nanoseconds.
|
|
||||||
///
|
|
||||||
/// Fails when the duration is out of bounds.
|
|
||||||
#[inline]
|
|
||||||
pub fn new(days: i32, secs: i32, nanos: i32) -> Duration {
|
|
||||||
Duration::new_opt(days, secs, nanos).expect("Duration::new out of bounds")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a new `Duration` with given number of days, seconds and nanoseconds.
|
|
||||||
///
|
|
||||||
/// Returns `None` when the duration is out of bounds.
|
|
||||||
pub fn new_opt(days: i32, secs: i32, nanos: i32) -> Option<Duration> {
|
|
||||||
let (secs_, nanos) = nanos.div_mod_floor(&NANOS_PER_SEC);
|
|
||||||
let secs = try_opt!(secs.checked_add(&secs_));
|
|
||||||
let (days_, secs) = secs.div_mod_floor(&SECS_PER_DAY);
|
|
||||||
let days = try_opt!(days.checked_add(&days_).and_then(|v| v.to_i32()));
|
|
||||||
Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a new `Duration` with zero seconds.
|
|
||||||
#[inline]
|
|
||||||
pub fn zero() -> Duration {
|
|
||||||
Duration { days: 0, secs: 0, nanos: 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a new `Duration` with given number of weeks.
|
|
||||||
/// Equivalent to `Duration::new(weeks * 7, 0, 0)` with overflow checks.
|
|
||||||
///
|
|
||||||
/// Fails when the duration is out of bounds.
|
|
||||||
#[inline]
|
|
||||||
pub fn weeks(weeks: i32) -> Duration {
|
|
||||||
let days = weeks.checked_mul(&7).expect("Duration::weeks out of bounds");
|
|
||||||
Duration::days(days)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a new `Duration` with given number of days.
|
|
||||||
/// Equivalent to `Duration::new(days, 0, 0)`.
|
|
||||||
///
|
|
||||||
/// Fails when the duration is out of bounds.
|
|
||||||
#[inline]
|
|
||||||
pub fn days(days: i32) -> Duration {
|
|
||||||
let days = days.to_i32().expect("Duration::days out of bounds");
|
|
||||||
Duration { days: days, secs: 0, nanos: 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a new `Duration` with given number of hours.
|
|
||||||
/// Equivalent to `Duration::new(0, hours * 3600, 0)` with overflow checks.
|
|
||||||
///
|
|
||||||
/// Fails when the duration is out of bounds.
|
|
||||||
#[inline]
|
|
||||||
pub fn hours(hours: i32) -> Duration {
|
|
||||||
let (days, hours) = hours.div_mod_floor(&(SECS_PER_DAY / 3600));
|
|
||||||
let secs = hours * 3600;
|
|
||||||
Duration { secs: secs as u32, ..Duration::days(days) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a new `Duration` with given number of minutes.
|
|
||||||
/// Equivalent to `Duration::new(0, mins * 60, 0)` with overflow checks.
|
|
||||||
///
|
|
||||||
/// Fails when the duration is out of bounds.
|
|
||||||
#[inline]
|
|
||||||
pub fn minutes(mins: i32) -> Duration {
|
|
||||||
let (days, mins) = mins.div_mod_floor(&(SECS_PER_DAY / 60));
|
|
||||||
let secs = mins * 60;
|
|
||||||
Duration { secs: secs as u32, ..Duration::days(days) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a new `Duration` with given number of seconds.
|
|
||||||
/// Equivalent to `Duration::new(0, secs, 0)`.
|
|
||||||
///
|
|
||||||
/// Fails when the duration is out of bounds.
|
|
||||||
#[inline]
|
|
||||||
pub fn seconds(secs: i32) -> Duration {
|
|
||||||
let (days, secs) = secs.div_mod_floor(&SECS_PER_DAY);
|
|
||||||
Duration { secs: secs as u32, ..Duration::days(days) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a new `Duration` with given number of milliseconds.
|
|
||||||
/// Equivalent to `Duration::new(0, 0, millis * 1_000_000)` with overflow checks.
|
|
||||||
///
|
|
||||||
/// Fails when the duration is out of bounds.
|
|
||||||
#[inline]
|
|
||||||
pub fn milliseconds(millis: i32) -> Duration {
|
|
||||||
let (secs, millis) = millis.div_mod_floor(&(NANOS_PER_SEC / 1_000_000));
|
|
||||||
let nanos = millis * 1_000_000;
|
|
||||||
Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a new `Duration` with given number of microseconds.
|
|
||||||
/// Equivalent to `Duration::new(0, 0, micros * 1_000)` with overflow checks.
|
|
||||||
///
|
|
||||||
/// Fails when the duration is out of bounds.
|
|
||||||
#[inline]
|
|
||||||
pub fn microseconds(micros: i32) -> Duration {
|
|
||||||
let (secs, micros) = micros.div_mod_floor(&(NANOS_PER_SEC / 1_000));
|
|
||||||
let nanos = micros * 1_000;
|
|
||||||
Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a new `Duration` with given number of nanoseconds.
|
|
||||||
/// Equivalent to `Duration::new(0, 0, nanos)`.
|
|
||||||
///
|
|
||||||
/// Fails when the duration is out of bounds.
|
|
||||||
#[inline]
|
|
||||||
pub fn nanoseconds(nanos: i32) -> Duration {
|
|
||||||
let (secs, nanos) = nanos.div_mod_floor(&NANOS_PER_SEC);
|
|
||||||
Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a tuple of the number of days, (non-leap) seconds and nanoseconds in the duration.
|
|
||||||
/// Note that the number of seconds and nanoseconds are always positive,
|
|
||||||
/// so that for example `-Duration::seconds(3)` has -1 days and 86,397 seconds.
|
|
||||||
#[inline]
|
|
||||||
pub fn to_tuple(&self) -> (i32, u32, u32) {
|
|
||||||
(self.days, self.secs, self.nanos)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Same as `to_tuple` but returns a tuple compatible to `to_negated_tuple`.
|
|
||||||
#[inline]
|
|
||||||
fn to_tuple_64(&self) -> (i64, u32, u32) {
|
|
||||||
(self.days as i64, self.secs, self.nanos)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Negates the duration and returns a tuple like `to_tuple`.
|
|
||||||
/// This does not overflow and thus is internally used for several methods.
|
|
||||||
fn to_negated_tuple_64(&self) -> (i64, u32, u32) {
|
|
||||||
let mut days = -(self.days as i64);
|
|
||||||
let mut secs = -(self.secs as i32);
|
|
||||||
let mut nanos = -(self.nanos as i32);
|
|
||||||
if nanos < 0 {
|
|
||||||
nanos += NANOS_PER_SEC;
|
|
||||||
secs -= 1;
|
|
||||||
}
|
|
||||||
if secs < 0 {
|
|
||||||
secs += SECS_PER_DAY;
|
|
||||||
days -= 1;
|
|
||||||
}
|
|
||||||
(days, secs as u32, nanos as u32)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the total number of whole weeks in the duration.
|
|
||||||
#[inline]
|
|
||||||
pub fn num_weeks(&self) -> i32 {
|
|
||||||
self.num_days() / 7
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the total number of whole days in the duration.
|
|
||||||
pub fn num_days(&self) -> i32 {
|
|
||||||
if self.days < 0 {
|
|
||||||
let negated = -*self;
|
|
||||||
-negated.days
|
|
||||||
} else {
|
|
||||||
self.days
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the total number of whole hours in the duration.
|
|
||||||
#[inline]
|
|
||||||
pub fn num_hours(&self) -> i64 {
|
|
||||||
self.num_seconds() / 3600
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the total number of whole minutes in the duration.
|
|
||||||
#[inline]
|
|
||||||
pub fn num_minutes(&self) -> i64 {
|
|
||||||
self.num_seconds() / 60
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the total number of (non-leap) whole seconds in the duration.
|
|
||||||
pub fn num_seconds(&self) -> i64 {
|
|
||||||
// cannot overflow, 2^32 * 86400 < 2^64
|
|
||||||
fn secs((days, secs, _): (i64, u32, u32)) -> i64 {
|
|
||||||
days as i64 * SECS_PER_DAY as i64 + secs as i64
|
|
||||||
}
|
|
||||||
if self.days < 0 {-secs(self.to_negated_tuple_64())} else {secs(self.to_tuple_64())}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the total number of whole milliseconds in the duration.
|
|
||||||
pub fn num_milliseconds(&self) -> i64 {
|
|
||||||
// cannot overflow, 2^32 * 86400 * 1000 < 2^64
|
|
||||||
fn millis((days, secs, nanos): (i64, u32, u32)) -> i64 {
|
|
||||||
static MILLIS_PER_SEC: i64 = 1_000;
|
|
||||||
static NANOS_PER_MILLI: i64 = 1_000_000;
|
|
||||||
(days as i64 * MILLIS_PER_SEC * SECS_PER_DAY as i64 +
|
|
||||||
secs as i64 * MILLIS_PER_SEC +
|
|
||||||
nanos as i64 / NANOS_PER_MILLI)
|
|
||||||
}
|
|
||||||
if self.days < 0 {-millis(self.to_negated_tuple_64())} else {millis(self.to_tuple_64())}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the total number of whole microseconds in the duration,
|
|
||||||
/// or `None` on the overflow (exceeding 2^63 microseconds in either directions).
|
|
||||||
pub fn num_microseconds(&self) -> Option<i64> {
|
|
||||||
fn micros((days, secs, nanos): (i64, u32, u32)) -> Option<i64> {
|
|
||||||
static MICROS_PER_SEC: i64 = 1_000_000;
|
|
||||||
static MICROS_PER_DAY: i64 = MICROS_PER_SEC * SECS_PER_DAY as i64;
|
|
||||||
static NANOS_PER_MICRO: i64 = 1_000;
|
|
||||||
let nmicros = try_opt!((days as i64).checked_mul(&MICROS_PER_DAY));
|
|
||||||
let nmicros = try_opt!(nmicros.checked_add(&(secs as i64 * MICROS_PER_SEC)));
|
|
||||||
let nmicros = try_opt!(nmicros.checked_add(&(nanos as i64 / NANOS_PER_MICRO as i64)));
|
|
||||||
Some(nmicros)
|
|
||||||
}
|
|
||||||
if self.days < 0 {
|
|
||||||
// the final negation won't overflow since we start with positive numbers.
|
|
||||||
micros(self.to_negated_tuple_64()).map(|micros| -micros)
|
|
||||||
} else {
|
|
||||||
micros(self.to_tuple_64())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the total number of whole nanoseconds in the duration,
|
|
||||||
/// or `None` on the overflow (exceeding 2^63 nanoseconds in either directions).
|
|
||||||
pub fn num_nanoseconds(&self) -> Option<i64> {
|
|
||||||
fn nanos((days, secs, nanos): (i64, u32, u32)) -> Option<i64> {
|
|
||||||
static NANOS_PER_DAY: i64 = NANOS_PER_SEC as i64 * SECS_PER_DAY as i64;
|
|
||||||
let nnanos = try_opt!((days as i64).checked_mul(&NANOS_PER_DAY));
|
|
||||||
let nnanos = try_opt!(nnanos.checked_add(&(secs as i64 * NANOS_PER_SEC as i64)));
|
|
||||||
let nnanos = try_opt!(nnanos.checked_add(&(nanos as i64)));
|
|
||||||
Some(nnanos)
|
|
||||||
}
|
|
||||||
if self.days < 0 {
|
|
||||||
// the final negation won't overflow since we start with positive numbers.
|
|
||||||
nanos(self.to_negated_tuple_64()).map(|micros| -micros)
|
|
||||||
} else {
|
|
||||||
nanos(self.to_tuple_64())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::Bounded for Duration {
|
|
||||||
#[inline] fn min_value() -> Duration { MIN }
|
|
||||||
#[inline] fn max_value() -> Duration { MAX }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::Zero for Duration {
|
|
||||||
#[inline]
|
|
||||||
fn zero() -> Duration {
|
|
||||||
Duration { days: 0, secs: 0, nanos: 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_zero(&self) -> bool {
|
|
||||||
self.days == 0 && self.secs == 0 && self.nanos == 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Neg<Duration> for Duration {
|
|
||||||
#[inline]
|
|
||||||
fn neg(&self) -> Duration {
|
|
||||||
let (days, secs, nanos) = self.to_negated_tuple_64();
|
|
||||||
Duration { days: days as i32, secs: secs, nanos: nanos } // XXX can overflow
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<Duration,Duration> for Duration {
|
|
||||||
fn add(&self, rhs: &Duration) -> Duration {
|
|
||||||
let mut days = self.days + rhs.days;
|
|
||||||
let mut secs = self.secs + rhs.secs;
|
|
||||||
let mut nanos = self.nanos + rhs.nanos;
|
|
||||||
if nanos >= NANOS_PER_SEC as u32 {
|
|
||||||
nanos -= NANOS_PER_SEC as u32;
|
|
||||||
secs += 1;
|
|
||||||
}
|
|
||||||
if secs >= SECS_PER_DAY as u32 {
|
|
||||||
secs -= SECS_PER_DAY as u32;
|
|
||||||
days += 1;
|
|
||||||
}
|
|
||||||
Duration { days: days, secs: secs, nanos: nanos }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::CheckedAdd for Duration {
|
|
||||||
fn checked_add(&self, rhs: &Duration) -> Option<Duration> {
|
|
||||||
let mut days = try_opt!(self.days.checked_add(&rhs.days));
|
|
||||||
let mut secs = self.secs + rhs.secs;
|
|
||||||
let mut nanos = self.nanos + rhs.nanos;
|
|
||||||
if nanos >= NANOS_PER_SEC as u32 {
|
|
||||||
nanos -= NANOS_PER_SEC as u32;
|
|
||||||
secs += 1;
|
|
||||||
}
|
|
||||||
if secs >= SECS_PER_DAY as u32 {
|
|
||||||
secs -= SECS_PER_DAY as u32;
|
|
||||||
days = try_opt!(days.checked_add(&1));
|
|
||||||
}
|
|
||||||
Some(Duration { days: days, secs: secs, nanos: nanos })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sub<Duration,Duration> for Duration {
|
|
||||||
fn sub(&self, rhs: &Duration) -> Duration {
|
|
||||||
let mut days = self.days - rhs.days;
|
|
||||||
let mut secs = self.secs as i32 - rhs.secs as i32;
|
|
||||||
let mut nanos = self.nanos as i32 - rhs.nanos as i32;
|
|
||||||
if nanos < 0 {
|
|
||||||
nanos += NANOS_PER_SEC;
|
|
||||||
secs -= 1;
|
|
||||||
}
|
|
||||||
if secs < 0 {
|
|
||||||
secs += SECS_PER_DAY;
|
|
||||||
days -= 1;
|
|
||||||
}
|
|
||||||
Duration { days: days, secs: secs as u32, nanos: nanos as u32 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl num::CheckedSub for Duration {
|
|
||||||
fn checked_sub(&self, rhs: &Duration) -> Option<Duration> {
|
|
||||||
let mut days = try_opt!(self.days.checked_sub(&rhs.days));
|
|
||||||
let mut secs = self.secs as i32 - rhs.secs as i32;
|
|
||||||
let mut nanos = self.nanos as i32 - rhs.nanos as i32;
|
|
||||||
if nanos < 0 {
|
|
||||||
nanos += NANOS_PER_SEC;
|
|
||||||
secs -= 1;
|
|
||||||
}
|
|
||||||
if secs < 0 {
|
|
||||||
secs += SECS_PER_DAY;
|
|
||||||
days = try_opt!(days.checked_sub(&1));
|
|
||||||
}
|
|
||||||
Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mul<i32,Duration> for Duration {
|
|
||||||
fn mul(&self, rhs: &i32) -> Duration {
|
|
||||||
/// Given `0 <= y < limit <= 2^30`,
|
|
||||||
/// returns `(h,l)` such that `x * y = h * limit + l` where `0 <= l < limit`.
|
|
||||||
fn mul_i64_u32_limit(x: i64, y: u32, limit: u32) -> (i64,u32) {
|
|
||||||
let y = y as i64;
|
|
||||||
let limit = limit as i64;
|
|
||||||
let (xh, xl) = x.div_mod_floor(&limit);
|
|
||||||
let (h, l) = (xh * y, xl * y);
|
|
||||||
let (h_, l) = l.div_rem(&limit);
|
|
||||||
(h + h_, l as u32)
|
|
||||||
}
|
|
||||||
|
|
||||||
let rhs = *rhs as i64;
|
|
||||||
let (secs1, nanos) = mul_i64_u32_limit(rhs, self.nanos, NANOS_PER_SEC as u32);
|
|
||||||
let (days1, secs1) = secs1.div_mod_floor(&(SECS_PER_DAY as i64));
|
|
||||||
let (days2, secs2) = mul_i64_u32_limit(rhs, self.secs, SECS_PER_DAY as u32);
|
|
||||||
let mut days = self.days as i64 * rhs + days1 + days2;
|
|
||||||
let mut secs = secs1 as u32 + secs2;
|
|
||||||
if secs >= SECS_PER_DAY as u32 {
|
|
||||||
secs -= 1;
|
|
||||||
days += 1;
|
|
||||||
}
|
|
||||||
Duration { days: days as i32, secs: secs, nanos: nanos }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Div<i32,Duration> for Duration {
|
|
||||||
fn div(&self, rhs: &i32) -> Duration {
|
|
||||||
let (rhs, days, secs, nanos) = if *rhs < 0 {
|
|
||||||
let (days, secs, nanos) = self.to_negated_tuple_64();
|
|
||||||
(-(*rhs as i64), days, secs as i64, nanos as i64)
|
|
||||||
} else {
|
|
||||||
(*rhs as i64, self.days as i64, self.secs as i64, self.nanos as i64)
|
|
||||||
};
|
|
||||||
|
|
||||||
let (days, carry) = days.div_mod_floor(&rhs);
|
|
||||||
let secs = secs + carry * SECS_PER_DAY as i64;
|
|
||||||
let (secs, carry) = secs.div_mod_floor(&rhs);
|
|
||||||
let nanos = nanos + carry * NANOS_PER_SEC as i64;
|
|
||||||
let nanos = nanos / rhs;
|
|
||||||
Duration { days: days as i32, secs: secs as u32, nanos: nanos as u32 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Show for Duration {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
let hasdate = self.days != 0;
|
|
||||||
let hastime = (self.secs != 0 || self.nanos != 0) || !hasdate;
|
|
||||||
|
|
||||||
try!(write!(f, "P"));
|
|
||||||
if hasdate {
|
|
||||||
// technically speaking the negative part is not the valid ISO 8601,
|
|
||||||
// but we need to print it anyway.
|
|
||||||
try!(write!(f, "{}D", self.days));
|
|
||||||
}
|
|
||||||
if hastime {
|
|
||||||
if self.nanos == 0 {
|
|
||||||
try!(write!(f, "T{}S", self.secs));
|
|
||||||
} else if self.nanos % 1_000_000 == 0 {
|
|
||||||
try!(write!(f, "T{}.{:03}S", self.secs, self.nanos / 1_000_000));
|
|
||||||
} else if self.nanos % 1_000 == 0 {
|
|
||||||
try!(write!(f, "T{}.{:06}S", self.secs, self.nanos / 1_000));
|
|
||||||
} else {
|
|
||||||
try!(write!(f, "T{}.{:09}S", self.secs, self.nanos));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::{Duration, MIN_DAYS, MAX_DAYS, MIN, MAX};
|
|
||||||
use std::{i32, i64};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_duration() {
|
|
||||||
assert_eq!(Duration::zero(), Duration::zero());
|
|
||||||
assert!(Duration::zero() != Duration::seconds(1));
|
|
||||||
assert_eq!(Duration::seconds(1) + Duration::seconds(2), Duration::seconds(3));
|
|
||||||
assert_eq!(Duration::milliseconds(997) + Duration::milliseconds(15),
|
|
||||||
Duration::new(0, 1, 12_000_000));
|
|
||||||
assert_eq!(Duration::seconds(86399) + Duration::seconds(4), Duration::new(1, 3, 0));
|
|
||||||
assert_eq!(Duration::days(10) - Duration::seconds(1000), Duration::seconds(863000));
|
|
||||||
assert_eq!(Duration::days(10) - Duration::seconds(1000000), Duration::seconds(-136000));
|
|
||||||
assert_eq!(Duration::days(2) + Duration::seconds(86399) + Duration::nanoseconds(1234567890),
|
|
||||||
Duration::new(3, 0, 234567890));
|
|
||||||
assert_eq!(-Duration::days(3), Duration::days(-3));
|
|
||||||
assert_eq!(-(Duration::days(3) + Duration::seconds(70)),
|
|
||||||
Duration::days(-4) + Duration::seconds(86400-70));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_duration_num_days() {
|
|
||||||
assert_eq!(Duration::zero().num_days(), 0);
|
|
||||||
assert_eq!(Duration::days(1).num_days(), 1);
|
|
||||||
assert_eq!(Duration::days(-1).num_days(), -1);
|
|
||||||
assert_eq!(Duration::seconds(86399).num_days(), 0);
|
|
||||||
assert_eq!(Duration::seconds(86401).num_days(), 1);
|
|
||||||
assert_eq!(Duration::seconds(-86399).num_days(), 0);
|
|
||||||
assert_eq!(Duration::seconds(-86401).num_days(), -1);
|
|
||||||
assert_eq!(Duration::new(1, 2, 3_004_005).num_days(), 1);
|
|
||||||
assert_eq!(Duration::new(-1, -2, -3_004_005).num_days(), -1);
|
|
||||||
assert_eq!(Duration::days(i32::MAX).num_days(), i32::MAX);
|
|
||||||
assert_eq!(Duration::days(i32::MIN).num_days(), i32::MIN);
|
|
||||||
assert_eq!(MAX.num_days(), MAX_DAYS);
|
|
||||||
assert_eq!(MIN.num_days(), MIN_DAYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_duration_num_seconds() {
|
|
||||||
assert_eq!(Duration::zero().num_seconds(), 0);
|
|
||||||
assert_eq!(Duration::seconds(1).num_seconds(), 1);
|
|
||||||
assert_eq!(Duration::seconds(-1).num_seconds(), -1);
|
|
||||||
assert_eq!(Duration::milliseconds(999).num_seconds(), 0);
|
|
||||||
assert_eq!(Duration::milliseconds(1001).num_seconds(), 1);
|
|
||||||
assert_eq!(Duration::milliseconds(-999).num_seconds(), 0);
|
|
||||||
assert_eq!(Duration::milliseconds(-1001).num_seconds(), -1);
|
|
||||||
assert_eq!(Duration::new(1, 2, 3_004_005).num_seconds(), 86402);
|
|
||||||
assert_eq!(Duration::new(-1, -2, -3_004_005).num_seconds(), -86402);
|
|
||||||
assert_eq!(Duration::seconds(i32::MAX).num_seconds(), i32::MAX as i64);
|
|
||||||
assert_eq!(Duration::seconds(i32::MIN).num_seconds(), i32::MIN as i64);
|
|
||||||
assert_eq!(MAX.num_seconds(), (MAX_DAYS as i64 + 1) * 86400 - 1);
|
|
||||||
assert_eq!(MIN.num_seconds(), MIN_DAYS as i64 * 86400);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_duration_num_milliseconds() {
|
|
||||||
assert_eq!(Duration::zero().num_milliseconds(), 0);
|
|
||||||
assert_eq!(Duration::milliseconds(1).num_milliseconds(), 1);
|
|
||||||
assert_eq!(Duration::milliseconds(-1).num_milliseconds(), -1);
|
|
||||||
assert_eq!(Duration::microseconds(999).num_milliseconds(), 0);
|
|
||||||
assert_eq!(Duration::microseconds(1001).num_milliseconds(), 1);
|
|
||||||
assert_eq!(Duration::microseconds(-999).num_milliseconds(), 0);
|
|
||||||
assert_eq!(Duration::microseconds(-1001).num_milliseconds(), -1);
|
|
||||||
assert_eq!(Duration::new(1, 2, 3_004_005).num_milliseconds(), 86402_003);
|
|
||||||
assert_eq!(Duration::new(-1, -2, -3_004_005).num_milliseconds(), -86402_003);
|
|
||||||
assert_eq!(Duration::milliseconds(i32::MAX).num_milliseconds(), i32::MAX as i64);
|
|
||||||
assert_eq!(Duration::milliseconds(i32::MIN).num_milliseconds(), i32::MIN as i64);
|
|
||||||
assert_eq!(MAX.num_milliseconds(), (MAX_DAYS as i64 + 1) * 86400_000 - 1);
|
|
||||||
assert_eq!(MIN.num_milliseconds(), MIN_DAYS as i64 * 86400_000);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_duration_num_microseconds() {
|
|
||||||
assert_eq!(Duration::zero().num_microseconds(), Some(0));
|
|
||||||
assert_eq!(Duration::microseconds(1).num_microseconds(), Some(1));
|
|
||||||
assert_eq!(Duration::microseconds(-1).num_microseconds(), Some(-1));
|
|
||||||
assert_eq!(Duration::nanoseconds(999).num_microseconds(), Some(0));
|
|
||||||
assert_eq!(Duration::nanoseconds(1001).num_microseconds(), Some(1));
|
|
||||||
assert_eq!(Duration::nanoseconds(-999).num_microseconds(), Some(0));
|
|
||||||
assert_eq!(Duration::nanoseconds(-1001).num_microseconds(), Some(-1));
|
|
||||||
assert_eq!(Duration::new(1, 2, 3_004_005).num_microseconds(), Some(86402_003_004));
|
|
||||||
assert_eq!(Duration::new(-1, -2, -3_004_005).num_microseconds(), Some(-86402_003_004));
|
|
||||||
assert_eq!(Duration::microseconds(i32::MAX).num_microseconds(), Some(i32::MAX as i64));
|
|
||||||
assert_eq!(Duration::microseconds(i32::MIN).num_microseconds(), Some(i32::MIN as i64));
|
|
||||||
assert_eq!(MAX.num_microseconds(), None);
|
|
||||||
assert_eq!(MIN.num_microseconds(), None);
|
|
||||||
|
|
||||||
// overflow checks
|
|
||||||
static MICROS_PER_DAY: i64 = 86400_000_000;
|
|
||||||
assert_eq!(Duration::days((i64::MAX / MICROS_PER_DAY) as i32).num_microseconds(),
|
|
||||||
Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY));
|
|
||||||
assert_eq!(Duration::days((i64::MIN / MICROS_PER_DAY) as i32).num_microseconds(),
|
|
||||||
Some(i64::MIN / MICROS_PER_DAY * MICROS_PER_DAY));
|
|
||||||
assert_eq!(Duration::days((i64::MAX / MICROS_PER_DAY + 1) as i32).num_microseconds(), None);
|
|
||||||
assert_eq!(Duration::days((i64::MIN / MICROS_PER_DAY - 1) as i32).num_microseconds(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_duration_num_nanoseconds() {
|
|
||||||
assert_eq!(Duration::zero().num_nanoseconds(), Some(0));
|
|
||||||
assert_eq!(Duration::nanoseconds(1).num_nanoseconds(), Some(1));
|
|
||||||
assert_eq!(Duration::nanoseconds(-1).num_nanoseconds(), Some(-1));
|
|
||||||
assert_eq!(Duration::new(1, 2, 3_004_005).num_nanoseconds(), Some(86402_003_004_005));
|
|
||||||
assert_eq!(Duration::new(-1, -2, -3_004_005).num_nanoseconds(), Some(-86402_003_004_005));
|
|
||||||
assert_eq!(Duration::nanoseconds(i32::MAX).num_nanoseconds(), Some(i32::MAX as i64));
|
|
||||||
assert_eq!(Duration::nanoseconds(i32::MIN).num_nanoseconds(), Some(i32::MIN as i64));
|
|
||||||
assert_eq!(MAX.num_nanoseconds(), None);
|
|
||||||
assert_eq!(MIN.num_nanoseconds(), None);
|
|
||||||
|
|
||||||
// overflow checks
|
|
||||||
static NANOS_PER_DAY: i64 = 86400_000_000_000;
|
|
||||||
assert_eq!(Duration::days((i64::MAX / NANOS_PER_DAY) as i32).num_nanoseconds(),
|
|
||||||
Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY));
|
|
||||||
assert_eq!(Duration::days((i64::MIN / NANOS_PER_DAY) as i32).num_nanoseconds(),
|
|
||||||
Some(i64::MIN / NANOS_PER_DAY * NANOS_PER_DAY));
|
|
||||||
assert_eq!(Duration::days((i64::MAX / NANOS_PER_DAY + 1) as i32).num_nanoseconds(), None);
|
|
||||||
assert_eq!(Duration::days((i64::MIN / NANOS_PER_DAY - 1) as i32).num_nanoseconds(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_duration_checked_ops() {
|
|
||||||
assert_eq!(Duration::days(MAX_DAYS).checked_add(&Duration::seconds(86399)),
|
|
||||||
Some(Duration::days(MAX_DAYS - 1) + Duration::seconds(86400+86399)));
|
|
||||||
assert!(Duration::days(MAX_DAYS).checked_add(&Duration::seconds(86400)).is_none());
|
|
||||||
|
|
||||||
assert_eq!(Duration::days(MIN_DAYS).checked_sub(&Duration::seconds(0)),
|
|
||||||
Some(Duration::days(MIN_DAYS)));
|
|
||||||
assert!(Duration::days(MIN_DAYS).checked_sub(&Duration::seconds(1)).is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_duration_mul() {
|
|
||||||
assert_eq!(Duration::zero() * i32::MAX, Duration::zero());
|
|
||||||
assert_eq!(Duration::zero() * i32::MIN, Duration::zero());
|
|
||||||
assert_eq!(Duration::nanoseconds(1) * 0, Duration::zero());
|
|
||||||
assert_eq!(Duration::nanoseconds(1) * 1, Duration::nanoseconds(1));
|
|
||||||
assert_eq!(Duration::nanoseconds(1) * 1_000_000_000, Duration::seconds(1));
|
|
||||||
assert_eq!(Duration::nanoseconds(1) * -1_000_000_000, -Duration::seconds(1));
|
|
||||||
assert_eq!(-Duration::nanoseconds(1) * 1_000_000_000, -Duration::seconds(1));
|
|
||||||
assert_eq!(Duration::nanoseconds(30) * 333_333_333,
|
|
||||||
Duration::seconds(10) - Duration::nanoseconds(10));
|
|
||||||
assert_eq!((Duration::nanoseconds(1) + Duration::seconds(1) + Duration::days(1)) * 3,
|
|
||||||
Duration::nanoseconds(3) + Duration::seconds(3) + Duration::days(3));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_duration_div() {
|
|
||||||
assert_eq!(Duration::zero() / i32::MAX, Duration::zero());
|
|
||||||
assert_eq!(Duration::zero() / i32::MIN, Duration::zero());
|
|
||||||
assert_eq!(Duration::nanoseconds(123_456_789) / 1, Duration::nanoseconds(123_456_789));
|
|
||||||
assert_eq!(Duration::nanoseconds(123_456_789) / -1, -Duration::nanoseconds(123_456_789));
|
|
||||||
assert_eq!(-Duration::nanoseconds(123_456_789) / -1, Duration::nanoseconds(123_456_789));
|
|
||||||
assert_eq!(-Duration::nanoseconds(123_456_789) / 1, -Duration::nanoseconds(123_456_789));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_duration_fmt() {
|
|
||||||
assert_eq!(Duration::zero().to_string(), "PT0S".to_string());
|
|
||||||
assert_eq!(Duration::days(42).to_string(), "P42D".to_string());
|
|
||||||
assert_eq!(Duration::days(-42).to_string(), "P-42D".to_string());
|
|
||||||
assert_eq!(Duration::seconds(42).to_string(), "PT42S".to_string());
|
|
||||||
assert_eq!(Duration::milliseconds(42).to_string(), "PT0.042S".to_string());
|
|
||||||
assert_eq!(Duration::microseconds(42).to_string(), "PT0.000042S".to_string());
|
|
||||||
assert_eq!(Duration::nanoseconds(42).to_string(), "PT0.000000042S".to_string());
|
|
||||||
assert_eq!((Duration::days(7) + Duration::milliseconds(6543)).to_string(),
|
|
||||||
"P7DT6.543S".to_string());
|
|
||||||
|
|
||||||
// the format specifier should have no effect on `Duration`
|
|
||||||
assert_eq!(format!("{:30}", Duration::days(1) + Duration::milliseconds(2345)),
|
|
||||||
"P1DT2.345S".to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -25,7 +25,13 @@ pub use date::Date;
|
||||||
pub use time::Time;
|
pub use time::Time;
|
||||||
pub use datetime::DateTime;
|
pub use datetime::DateTime;
|
||||||
|
|
||||||
pub mod duration;
|
pub mod duration {
|
||||||
|
//! ISO 8601 duration.
|
||||||
|
//!
|
||||||
|
//! This used to be a part of rust-chrono,
|
||||||
|
//! but has been subsequently merged into Rust's standard library.
|
||||||
|
pub use std::time::duration::{MIN, MAX, Duration};
|
||||||
|
}
|
||||||
pub mod offset;
|
pub mod offset;
|
||||||
pub mod naive {
|
pub mod naive {
|
||||||
//! Date and time types which do not concern about the timezones.
|
//! Date and time types which do not concern about the timezones.
|
||||||
|
|
|
@ -383,12 +383,12 @@ impl num::Bounded for NaiveDate {
|
||||||
|
|
||||||
impl Add<Duration,NaiveDate> for NaiveDate {
|
impl Add<Duration,NaiveDate> for NaiveDate {
|
||||||
fn add(&self, rhs: &Duration) -> NaiveDate {
|
fn add(&self, rhs: &Duration) -> NaiveDate {
|
||||||
// TODO overflow
|
// 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) = year.div_mod_floor(&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 + rhs.num_days();
|
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) = cycle.div_mod_floor(&146097);
|
||||||
year_div_400 += cycle_div_400y;
|
year_div_400 += cycle_div_400y;
|
||||||
|
|
||||||
|
@ -413,9 +413,9 @@ impl Sub<NaiveDate,Duration> for NaiveDate {
|
||||||
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) = year1.div_mod_floor(&400);
|
||||||
let (year2_div_400, year2_mod_400) = year2.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 u32, self.of().ordinal()) as i32;
|
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 i32;
|
let cycle2 = internals::yo_to_cycle(year2_mod_400 as u32, rhs.of().ordinal()) as i64;
|
||||||
Duration::days((year1_div_400 - year2_div_400) * 146097 + (cycle1 - cycle2))
|
Duration::days((year1_div_400 as i64 - year2_div_400 as i64) * 146097 + (cycle1 - cycle2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,6 +439,7 @@ mod tests {
|
||||||
use {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
|
use {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
use std::{i32, u32};
|
use std::{i32, u32};
|
||||||
|
use std::num::Zero;
|
||||||
use std::iter::{range_inclusive, range_step_inclusive};
|
use std::iter::{range_inclusive, range_step_inclusive};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -704,7 +705,7 @@ mod tests {
|
||||||
//assert_eq!(rhs + lhs, sum);
|
//assert_eq!(rhs + lhs, sum);
|
||||||
}
|
}
|
||||||
|
|
||||||
check((2014, 1, 1), Duration::zero(), (2014, 1, 1));
|
check((2014, 1, 1), Zero::zero(), (2014, 1, 1));
|
||||||
check((2014, 1, 1), Duration::seconds(86399), (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::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), (2014, 1, 2));
|
||||||
|
@ -725,7 +726,7 @@ mod tests {
|
||||||
assert_eq!(rhs - lhs, -diff);
|
assert_eq!(rhs - lhs, -diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
check((2014, 1, 1), (2014, 1, 1), Duration::zero());
|
check((2014, 1, 1), (2014, 1, 1), Zero::zero());
|
||||||
check((2014, 1, 2), (2014, 1, 1), Duration::days(1));
|
check((2014, 1, 2), (2014, 1, 1), Duration::days(1));
|
||||||
check((2014, 12, 31), (2014, 1, 1), Duration::days(364));
|
check((2014, 12, 31), (2014, 1, 1), Duration::days(364));
|
||||||
check((2015, 1, 3), (2014, 1, 1), Duration::days(365 + 2));
|
check((2015, 1, 3), (2014, 1, 1), Duration::days(365 + 2));
|
||||||
|
|
|
@ -163,13 +163,19 @@ impl Timelike for NaiveDateTime {
|
||||||
|
|
||||||
impl Add<Duration,NaiveDateTime> for NaiveDateTime {
|
impl Add<Duration,NaiveDateTime> for NaiveDateTime {
|
||||||
fn add(&self, rhs: &Duration) -> NaiveDateTime {
|
fn add(&self, rhs: &Duration) -> NaiveDateTime {
|
||||||
// we want `(NaiveDate + days in Duration) + (NaiveTime + secs/nanos in Duration)`
|
// Duration does not directly give its parts, so we need some additional calculations.
|
||||||
// to be equal to `NaiveDateTime + Duration`, but `NaiveDate + Duration` rounds towards zero.
|
let days = rhs.num_days();
|
||||||
let mut date = self.date + Duration::days(rhs.to_tuple().val0());
|
let nanos = (*rhs - Duration::days(days)).num_nanoseconds().unwrap();
|
||||||
let time = self.time + *rhs;
|
debug_assert!(Duration::days(days) + Duration::nanoseconds(nanos) == *rhs);
|
||||||
if time < self.time {
|
debug_assert!(-86400_000_000_000 < nanos && nanos < 86400_000_000_000);
|
||||||
// since the time portion of the duration is always positive and bounded,
|
|
||||||
// this condition always means that the time part has been overflowed.
|
let mut date = self.date + Duration::days(days);
|
||||||
|
let time = self.time + Duration::nanoseconds(nanos);
|
||||||
|
|
||||||
|
// time always wraps around, but date needs to be adjusted for overflow.
|
||||||
|
if nanos < 0 && time > self.time {
|
||||||
|
date = date.pred();
|
||||||
|
} else if nanos > 0 && time < self.time {
|
||||||
date = date.succ();
|
date = date.succ();
|
||||||
}
|
}
|
||||||
NaiveDateTime { date: date, time: time }
|
NaiveDateTime { date: date, time: time }
|
||||||
|
@ -202,6 +208,7 @@ mod tests {
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
use naive::date::NaiveDate;
|
use naive::date::NaiveDate;
|
||||||
use std::i64;
|
use std::i64;
|
||||||
|
use std::num::Zero;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_datetime_from_num_seconds_from_unix_epoch() {
|
fn test_datetime_from_num_seconds_from_unix_epoch() {
|
||||||
|
@ -234,7 +241,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_datetime_sub() {
|
fn test_datetime_sub() {
|
||||||
let ymdhms = |y,m,d,h,n,s| NaiveDate::from_ymd(y,m,d).and_hms(h,n,s);
|
let ymdhms = |y,m,d,h,n,s| NaiveDate::from_ymd(y,m,d).and_hms(h,n,s);
|
||||||
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) - ymdhms(2014, 5, 6, 7, 8, 9), Duration::zero());
|
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) - ymdhms(2014, 5, 6, 7, 8, 9), Zero::zero());
|
||||||
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 10) - ymdhms(2014, 5, 6, 7, 8, 9),
|
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 10) - ymdhms(2014, 5, 6, 7, 8, 9),
|
||||||
Duration::seconds(1));
|
Duration::seconds(1));
|
||||||
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) - ymdhms(2014, 5, 6, 7, 8, 10),
|
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) - ymdhms(2014, 5, 6, 7, 8, 10),
|
||||||
|
|
|
@ -172,9 +172,11 @@ impl Timelike for NaiveTime {
|
||||||
|
|
||||||
impl Add<Duration,NaiveTime> for NaiveTime {
|
impl Add<Duration,NaiveTime> for NaiveTime {
|
||||||
fn add(&self, rhs: &Duration) -> NaiveTime {
|
fn add(&self, rhs: &Duration) -> NaiveTime {
|
||||||
let (_, rhssecs, rhsnanos) = rhs.to_tuple();
|
// there is no direct interface in `Duration` to get only the nanosecond part,
|
||||||
let mut secs = self.secs + rhssecs;
|
// so we need to do the additional calculation here.
|
||||||
let mut nanos = self.frac + rhsnanos;
|
let rhs2 = *rhs - Duration::seconds(rhs.num_seconds());
|
||||||
|
let mut secs = self.secs + (rhs.num_seconds() % 86400 + 86400) as u32;
|
||||||
|
let mut nanos = self.frac + rhs2.num_nanoseconds().unwrap() as u32;
|
||||||
|
|
||||||
// always ignore leap seconds after the current whole second
|
// always ignore leap seconds after the current whole second
|
||||||
let maxnanos = if self.frac >= 1_000_000_000 {2_000_000_000} else {1_000_000_000};
|
let maxnanos = if self.frac >= 1_000_000_000 {2_000_000_000} else {1_000_000_000};
|
||||||
|
@ -198,7 +200,7 @@ impl Add<NaiveTime,NaiveTime> for Duration {
|
||||||
impl Sub<NaiveTime,Duration> for NaiveTime {
|
impl Sub<NaiveTime,Duration> for NaiveTime {
|
||||||
fn sub(&self, rhs: &NaiveTime) -> Duration {
|
fn sub(&self, rhs: &NaiveTime) -> Duration {
|
||||||
// the number of whole non-leap seconds
|
// the number of whole non-leap seconds
|
||||||
let secs = self.secs as i32 - rhs.secs as i32 - 1;
|
let secs = self.secs as i64 - rhs.secs as i64 - 1;
|
||||||
|
|
||||||
// the fractional second from the rhs to the next non-leap second
|
// the fractional second from the rhs to the next non-leap second
|
||||||
let maxnanos = if rhs.frac >= 1_000_000_000 {2_000_000_000} else {1_000_000_000};
|
let maxnanos = if rhs.frac >= 1_000_000_000 {2_000_000_000} else {1_000_000_000};
|
||||||
|
@ -208,7 +210,7 @@ impl Sub<NaiveTime,Duration> for NaiveTime {
|
||||||
let lastfrac = if self.frac >= 1_000_000_000 {1_000_000_000} else {0};
|
let lastfrac = if self.frac >= 1_000_000_000 {1_000_000_000} else {0};
|
||||||
let nanos2 = self.frac - lastfrac;
|
let nanos2 = self.frac - lastfrac;
|
||||||
|
|
||||||
Duration::seconds(secs) + Duration::nanoseconds(nanos1 as i32 + nanos2 as i32)
|
Duration::seconds(secs) + Duration::nanoseconds(nanos1 as i64 + nanos2 as i64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,6 +242,7 @@ mod tests {
|
||||||
use Timelike;
|
use Timelike;
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
use std::u32;
|
use std::u32;
|
||||||
|
use std::num::Zero;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_time_from_hms_milli() {
|
fn test_time_from_hms_milli() {
|
||||||
|
@ -305,7 +308,7 @@ mod tests {
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
check(hmsm(3, 5, 7, 900), Duration::zero(), hmsm(3, 5, 7, 900));
|
check(hmsm(3, 5, 7, 900), Zero::zero(), hmsm(3, 5, 7, 900));
|
||||||
check(hmsm(3, 5, 7, 900), Duration::milliseconds(100), hmsm(3, 5, 8, 0));
|
check(hmsm(3, 5, 7, 900), Duration::milliseconds(100), hmsm(3, 5, 8, 0));
|
||||||
check(hmsm(3, 5, 7, 1_300), Duration::milliseconds(800), hmsm(3, 5, 8, 100));
|
check(hmsm(3, 5, 7, 1_300), Duration::milliseconds(800), hmsm(3, 5, 8, 100));
|
||||||
check(hmsm(3, 5, 7, 900), Duration::seconds(86399), hmsm(3, 5, 6, 900)); // overwrap
|
check(hmsm(3, 5, 7, 900), Duration::seconds(86399), hmsm(3, 5, 6, 900)); // overwrap
|
||||||
|
@ -323,7 +326,7 @@ mod tests {
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
check(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 900), Duration::zero());
|
check(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 900), Zero::zero());
|
||||||
check(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 600), Duration::milliseconds(300));
|
check(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 600), Duration::milliseconds(300));
|
||||||
check(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 200), Duration::seconds(3600 + 60 + 1));
|
check(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 200), Duration::seconds(3600 + 60 + 1));
|
||||||
check(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 300),
|
check(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 300),
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::str::MaybeOwned;
|
use std::str::MaybeOwned;
|
||||||
|
use std::num::Zero;
|
||||||
use stdtime;
|
use stdtime;
|
||||||
use num::Integer;
|
use num::Integer;
|
||||||
|
|
||||||
|
@ -261,7 +262,7 @@ impl UTC {
|
||||||
|
|
||||||
impl Offset for UTC {
|
impl Offset for UTC {
|
||||||
fn name(&self) -> MaybeOwned<'static> { "UTC".into_maybe_owned() }
|
fn name(&self) -> MaybeOwned<'static> { "UTC".into_maybe_owned() }
|
||||||
fn local_minus_utc(&self) -> Duration { Duration::zero() }
|
fn local_minus_utc(&self) -> Duration { Zero::zero() }
|
||||||
|
|
||||||
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<UTC>> {
|
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<UTC>> {
|
||||||
Single(Date::from_utc(local.clone(), UTC))
|
Single(Date::from_utc(local.clone(), UTC))
|
||||||
|
@ -332,26 +333,28 @@ impl FixedOffset {
|
||||||
|
|
||||||
impl Offset for FixedOffset {
|
impl Offset for FixedOffset {
|
||||||
fn name(&self) -> MaybeOwned<'static> { "UTC".into_maybe_owned() } // XXX
|
fn name(&self) -> MaybeOwned<'static> { "UTC".into_maybe_owned() } // XXX
|
||||||
fn local_minus_utc(&self) -> Duration { Duration::seconds(self.local_minus_utc) }
|
fn local_minus_utc(&self) -> Duration { Duration::seconds(self.local_minus_utc as i64) }
|
||||||
|
|
||||||
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<FixedOffset>> {
|
fn from_local_date(&self, local: &NaiveDate) -> LocalResult<Date<FixedOffset>> {
|
||||||
Single(Date::from_utc(local.clone(), self.clone()))
|
Single(Date::from_utc(local.clone(), self.clone()))
|
||||||
}
|
}
|
||||||
fn from_local_time(&self, local: &NaiveTime) -> LocalResult<Time<FixedOffset>> {
|
fn from_local_time(&self, local: &NaiveTime) -> LocalResult<Time<FixedOffset>> {
|
||||||
Single(Time::from_utc(*local + Duration::seconds(-self.local_minus_utc), self.clone()))
|
Single(Time::from_utc(*local + Duration::seconds(-self.local_minus_utc as i64),
|
||||||
|
self.clone()))
|
||||||
}
|
}
|
||||||
fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<FixedOffset>> {
|
fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<DateTime<FixedOffset>> {
|
||||||
Single(DateTime::from_utc(*local + Duration::seconds(-self.local_minus_utc), self.clone()))
|
Single(DateTime::from_utc(*local + Duration::seconds(-self.local_minus_utc as i64),
|
||||||
|
self.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_local_date(&self, utc: &NaiveDate) -> NaiveDate {
|
fn to_local_date(&self, utc: &NaiveDate) -> NaiveDate {
|
||||||
utc.clone()
|
utc.clone()
|
||||||
}
|
}
|
||||||
fn to_local_time(&self, utc: &NaiveTime) -> NaiveTime {
|
fn to_local_time(&self, utc: &NaiveTime) -> NaiveTime {
|
||||||
*utc + Duration::seconds(self.local_minus_utc)
|
*utc + Duration::seconds(self.local_minus_utc as i64)
|
||||||
}
|
}
|
||||||
fn to_local_datetime(&self, utc: &NaiveDateTime) -> NaiveDateTime {
|
fn to_local_datetime(&self, utc: &NaiveDateTime) -> NaiveDateTime {
|
||||||
*utc + Duration::seconds(self.local_minus_utc)
|
*utc + Duration::seconds(self.local_minus_utc as i64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,7 +392,7 @@ impl Local {
|
||||||
let time = NaiveTime::from_hms_nano(tm.tm_hour as u32, tm.tm_min as u32,
|
let time = NaiveTime::from_hms_nano(tm.tm_hour as u32, tm.tm_min as u32,
|
||||||
tm.tm_sec as u32, tm.tm_nsec as u32);
|
tm.tm_sec as u32, tm.tm_nsec as u32);
|
||||||
let offset = Local { cached: FixedOffset::east(tm.tm_gmtoff) };
|
let offset = Local { cached: FixedOffset::east(tm.tm_gmtoff) };
|
||||||
DateTime::from_utc(date.and_time(time) + Duration::seconds(-tm.tm_gmtoff), offset)
|
DateTime::from_utc(date.and_time(time) + Duration::seconds(-tm.tm_gmtoff as i64), offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a local `NaiveDateTime` to the `time::Timespec`.
|
/// Converts a local `NaiveDateTime` to the `time::Timespec`.
|
||||||
|
|
Loading…
Reference in New Issue