splitted naive types into their own modules.
This commit is contained in:
parent
586b41df54
commit
95f5c0c095
|
@ -10,10 +10,10 @@ Date and time handling for Rust.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
// find out if the doomsday rule is correct!
|
// find out if the doomsday rule is correct!
|
||||||
use chrono::{Weekday, NaiveDate, date};
|
use chrono::{Weekday, NaiveDate, naive};
|
||||||
use std::iter::range_inclusive;
|
use std::iter::range_inclusive;
|
||||||
|
|
||||||
for y in range_inclusive(date::MIN_NAIVE.year(), date::MAX_NAIVE.year()) {
|
for y in range_inclusive(naive::date::MIN.year(), naive::date::MAX.year()) {
|
||||||
// even months
|
// even months
|
||||||
let d4 = NaiveDate::from_ymd(y, 4, 4);
|
let d4 = NaiveDate::from_ymd(y, 4, 4);
|
||||||
let d6 = NaiveDate::from_ymd(y, 6, 6);
|
let d6 = NaiveDate::from_ymd(y, 6, 6);
|
||||||
|
|
1663
src/date.rs
1663
src/date.rs
File diff suppressed because it is too large
Load Diff
196
src/datetime.rs
196
src/datetime.rs
|
@ -7,156 +7,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::{fmt, hash};
|
use std::{fmt, hash};
|
||||||
|
|
||||||
|
use {Weekday, Timelike, Datelike};
|
||||||
use offset::Offset;
|
use offset::Offset;
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
use time::{Timelike, NaiveTime, Time};
|
use naive::datetime::NaiveDateTime;
|
||||||
use date::{Datelike, NaiveDate, Date, Weekday};
|
use time::Time;
|
||||||
|
use date::Date;
|
||||||
/// ISO 8601 combined date and time without timezone.
|
|
||||||
#[deriving(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
|
|
||||||
pub struct NaiveDateTime {
|
|
||||||
date: NaiveDate,
|
|
||||||
time: NaiveTime,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NaiveDateTime {
|
|
||||||
/// Makes a new `NaiveDateTime` from date and time components.
|
|
||||||
/// Equivalent to `date.and_time(time)` and many other helper constructors on `NaiveDate`.
|
|
||||||
#[inline]
|
|
||||||
pub fn new(date: NaiveDate, time: NaiveTime) -> NaiveDateTime {
|
|
||||||
NaiveDateTime { date: date, time: time }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves a date component.
|
|
||||||
#[inline]
|
|
||||||
pub fn date(&self) -> NaiveDate {
|
|
||||||
self.date
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves a time component.
|
|
||||||
#[inline]
|
|
||||||
pub fn time(&self) -> NaiveTime {
|
|
||||||
self.time
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the number of non-leap seconds since January 1, 1970 0:00:00 UTC.
|
|
||||||
/// Note that this does *not* account for the timezone!
|
|
||||||
#[inline]
|
|
||||||
pub fn num_seconds_from_unix_epoch(&self) -> i64 {
|
|
||||||
let ndays = self.date.num_days_from_ce() as i64;
|
|
||||||
let nseconds = self.time.num_seconds_from_midnight() as i64;
|
|
||||||
(ndays - 719163) * 86400 + nseconds
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Datelike for NaiveDateTime {
|
|
||||||
#[inline] fn year(&self) -> i32 { self.date.year() }
|
|
||||||
#[inline] fn month(&self) -> u32 { self.date.month() }
|
|
||||||
#[inline] fn month0(&self) -> u32 { self.date.month0() }
|
|
||||||
#[inline] fn day(&self) -> u32 { self.date.day() }
|
|
||||||
#[inline] fn day0(&self) -> u32 { self.date.day0() }
|
|
||||||
#[inline] fn ordinal(&self) -> u32 { self.date.ordinal() }
|
|
||||||
#[inline] fn ordinal0(&self) -> u32 { self.date.ordinal0() }
|
|
||||||
#[inline] fn weekday(&self) -> Weekday { self.date.weekday() }
|
|
||||||
#[inline] fn isoweekdate(&self) -> (i32, u32, Weekday) { self.date.isoweekdate() }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_year(&self, year: i32) -> Option<NaiveDateTime> {
|
|
||||||
self.date.with_year(year).map(|d| NaiveDateTime { date: d, ..*self })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_month(&self, month: u32) -> Option<NaiveDateTime> {
|
|
||||||
self.date.with_month(month).map(|d| NaiveDateTime { date: d, ..*self })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_month0(&self, month0: u32) -> Option<NaiveDateTime> {
|
|
||||||
self.date.with_month0(month0).map(|d| NaiveDateTime { date: d, ..*self })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_day(&self, day: u32) -> Option<NaiveDateTime> {
|
|
||||||
self.date.with_day(day).map(|d| NaiveDateTime { date: d, ..*self })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_day0(&self, day0: u32) -> Option<NaiveDateTime> {
|
|
||||||
self.date.with_day0(day0).map(|d| NaiveDateTime { date: d, ..*self })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_ordinal(&self, ordinal: u32) -> Option<NaiveDateTime> {
|
|
||||||
self.date.with_ordinal(ordinal).map(|d| NaiveDateTime { date: d, ..*self })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_ordinal0(&self, ordinal0: u32) -> Option<NaiveDateTime> {
|
|
||||||
self.date.with_ordinal0(ordinal0).map(|d| NaiveDateTime { date: d, ..*self })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Timelike for NaiveDateTime {
|
|
||||||
#[inline] fn hour(&self) -> u32 { self.time.hour() }
|
|
||||||
#[inline] fn minute(&self) -> u32 { self.time.minute() }
|
|
||||||
#[inline] fn second(&self) -> u32 { self.time.second() }
|
|
||||||
#[inline] fn nanosecond(&self) -> u32 { self.time.nanosecond() }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_hour(&self, hour: u32) -> Option<NaiveDateTime> {
|
|
||||||
self.time.with_hour(hour).map(|t| NaiveDateTime { time: t, ..*self })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_minute(&self, min: u32) -> Option<NaiveDateTime> {
|
|
||||||
self.time.with_minute(min).map(|t| NaiveDateTime { time: t, ..*self })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_second(&self, sec: u32) -> Option<NaiveDateTime> {
|
|
||||||
self.time.with_second(sec).map(|t| NaiveDateTime { time: t, ..*self })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_nanosecond(&self, nano: u32) -> Option<NaiveDateTime> {
|
|
||||||
self.time.with_nanosecond(nano).map(|t| NaiveDateTime { time: t, ..*self })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<Duration,NaiveDateTime> for NaiveDateTime {
|
|
||||||
fn add(&self, rhs: &Duration) -> NaiveDateTime {
|
|
||||||
// we want `(NaiveDate + days in Duration) + (NaiveTime + secs/nanos in Duration)`
|
|
||||||
// to be equal to `NaiveDateTime + Duration`, but `NaiveDate + 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,
|
|
||||||
// this condition always means that the time part has been overflowed.
|
|
||||||
date = date.succ();
|
|
||||||
}
|
|
||||||
NaiveDateTime { date: date, time: time }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// Rust issue #7590, the current coherence checker can't handle multiple Add impls
|
|
||||||
impl Add<NaiveDateTime,NaiveDateTime> for Duration {
|
|
||||||
#[inline]
|
|
||||||
fn add(&self, rhs: &NaiveDateTime) -> NaiveDateTime { rhs.add(self) }
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
impl Sub<NaiveDateTime,Duration> for NaiveDateTime {
|
|
||||||
fn sub(&self, rhs: &NaiveDateTime) -> Duration {
|
|
||||||
(self.date - rhs.date) + (self.time - rhs.time)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Show for NaiveDateTime {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}T{}", self.date, self.time)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ISO 8601 combined date and time with timezone.
|
/// ISO 8601 combined date and time with timezone.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
|
@ -335,53 +192,12 @@ impl<Off:Offset> fmt::Show for DateTime<Off> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use date::NaiveDate;
|
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
|
use offset::{Offset, UTC, FixedOffset};
|
||||||
#[test]
|
|
||||||
fn test_datetime_add() {
|
|
||||||
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) + 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),
|
|
||||||
ymdhms(2014, 5, 16, 7, 8, 9));
|
|
||||||
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) + Duration::seconds(-86400 * 10),
|
|
||||||
ymdhms(2014, 4, 26, 7, 8, 9));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_datetime_sub() {
|
|
||||||
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, 10) - ymdhms(2014, 5, 6, 7, 8, 9),
|
|
||||||
Duration::seconds(1));
|
|
||||||
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) - ymdhms(2014, 5, 6, 7, 8, 10),
|
|
||||||
Duration::seconds(-1));
|
|
||||||
assert_eq!(ymdhms(2014, 5, 7, 7, 8, 9) - ymdhms(2014, 5, 6, 7, 8, 10),
|
|
||||||
Duration::seconds(86399));
|
|
||||||
assert_eq!(ymdhms(2001, 9, 9, 1, 46, 39) - ymdhms(1970, 1, 1, 0, 0, 0),
|
|
||||||
Duration::seconds(999_999_999));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_datetime_num_seconds_from_unix_epoch() {
|
|
||||||
let to_timestamp =
|
|
||||||
|y,m,d,h,n,s| NaiveDate::from_ymd(y,m,d).and_hms(h,n,s).num_seconds_from_unix_epoch();
|
|
||||||
assert_eq!(to_timestamp(1969, 12, 31, 23, 59, 59), -1);
|
|
||||||
assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 0), 0);
|
|
||||||
assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 1), 1);
|
|
||||||
assert_eq!(to_timestamp(2001, 9, 9, 1, 46, 40), 1_000_000_000);
|
|
||||||
assert_eq!(to_timestamp(2038, 1, 19, 3, 14, 7), 0x7fffffff);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(uppercase_variables)]
|
#[allow(uppercase_variables)]
|
||||||
fn test_datetime_offset() {
|
fn test_datetime_offset() {
|
||||||
use offset::{Offset, UTC, FixedOffset};
|
|
||||||
let EDT = FixedOffset::east(4*60*60);
|
let EDT = FixedOffset::east(4*60*60);
|
||||||
assert_eq!(UTC.ymd(2014, 5, 6).and_hms(7, 8, 9).to_string(),
|
assert_eq!(UTC.ymd(2014, 5, 6).and_hms(7, 8, 9).to_string(),
|
||||||
"2014-05-06T07:08:09Z".to_string());
|
"2014-05-06T07:08:09Z".to_string());
|
||||||
|
|
276
src/lib.rs
276
src/lib.rs
|
@ -15,22 +15,288 @@ Experimental date and time handling for Rust.
|
||||||
extern crate num;
|
extern crate num;
|
||||||
|
|
||||||
pub use duration::Duration;
|
pub use duration::Duration;
|
||||||
pub use date::{Weekday, Mon, Tue, Wed, Thu, Fri, Sat, Sun};
|
pub use offset::{Offset, LocalResult};
|
||||||
pub use date::{Datelike, NaiveDate};
|
pub use offset::{UTC, FixedOffset};
|
||||||
pub use time::{Timelike, NaiveTime};
|
pub use naive::date::NaiveDate;
|
||||||
pub use datetime::NaiveDateTime;
|
pub use naive::time::NaiveTime;
|
||||||
|
pub use naive::datetime::NaiveDateTime;
|
||||||
|
pub use date::Date;
|
||||||
|
pub use time::Time;
|
||||||
|
pub use datetime::DateTime;
|
||||||
|
|
||||||
pub mod duration;
|
pub mod duration;
|
||||||
pub mod offset;
|
pub mod offset;
|
||||||
|
pub mod naive {
|
||||||
|
//! Date and time types which do not concern about the timezones.
|
||||||
|
//!
|
||||||
|
//! They are primarily building blocks for other types (e.g. `Offset`),
|
||||||
|
//! but can be also used for the simpler date and time handling.
|
||||||
pub mod date;
|
pub mod date;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod datetime;
|
pub mod datetime;
|
||||||
|
}
|
||||||
|
pub mod date;
|
||||||
|
pub mod time;
|
||||||
|
pub mod datetime;
|
||||||
|
|
||||||
|
/// The day of week (DOW).
|
||||||
|
///
|
||||||
|
/// The order of the days of week depends on the context.
|
||||||
|
/// One should prefer `*_from_monday` or `*_from_sunday` methods to get the correct result.
|
||||||
|
#[deriving(PartialEq, Eq, Clone, FromPrimitive, Show)]
|
||||||
|
pub enum Weekday {
|
||||||
|
/// Monday.
|
||||||
|
Mon = 0,
|
||||||
|
/// Tuesday.
|
||||||
|
Tue = 1,
|
||||||
|
/// Wednesday.
|
||||||
|
Wed = 2,
|
||||||
|
/// Thursday.
|
||||||
|
Thu = 3,
|
||||||
|
/// Friday.
|
||||||
|
Fri = 4,
|
||||||
|
/// Saturday.
|
||||||
|
Sat = 5,
|
||||||
|
/// Sunday.
|
||||||
|
Sun = 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Weekday {
|
||||||
|
/// The next day in the week.
|
||||||
|
#[inline]
|
||||||
|
pub fn succ(&self) -> Weekday {
|
||||||
|
match *self {
|
||||||
|
Mon => Tue,
|
||||||
|
Tue => Wed,
|
||||||
|
Wed => Thu,
|
||||||
|
Thu => Fri,
|
||||||
|
Fri => Sat,
|
||||||
|
Sat => Sun,
|
||||||
|
Sun => Mon,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The previous day in the week.
|
||||||
|
#[inline]
|
||||||
|
pub fn pred(&self) -> Weekday {
|
||||||
|
match *self {
|
||||||
|
Mon => Sun,
|
||||||
|
Tue => Mon,
|
||||||
|
Wed => Tue,
|
||||||
|
Thu => Wed,
|
||||||
|
Fri => Thu,
|
||||||
|
Sat => Fri,
|
||||||
|
Sun => Sat,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a DOW number starting from Monday = 1. (ISO 8601 weekday number)
|
||||||
|
#[inline]
|
||||||
|
pub fn number_from_monday(&self) -> u32 {
|
||||||
|
match *self {
|
||||||
|
Mon => 1,
|
||||||
|
Tue => 2,
|
||||||
|
Wed => 3,
|
||||||
|
Thu => 4,
|
||||||
|
Fri => 5,
|
||||||
|
Sat => 6,
|
||||||
|
Sun => 7,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a DOW number starting from Sunday = 1.
|
||||||
|
#[inline]
|
||||||
|
pub fn number_from_sunday(&self) -> u32 {
|
||||||
|
match *self {
|
||||||
|
Mon => 2,
|
||||||
|
Tue => 3,
|
||||||
|
Wed => 4,
|
||||||
|
Thu => 5,
|
||||||
|
Fri => 6,
|
||||||
|
Sat => 7,
|
||||||
|
Sun => 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a DOW number starting from Monday = 0.
|
||||||
|
#[inline]
|
||||||
|
pub fn num_days_from_monday(&self) -> u32 {
|
||||||
|
match *self {
|
||||||
|
Mon => 0,
|
||||||
|
Tue => 1,
|
||||||
|
Wed => 2,
|
||||||
|
Thu => 3,
|
||||||
|
Fri => 4,
|
||||||
|
Sat => 5,
|
||||||
|
Sun => 6,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a DOW number starting from Sunday = 0.
|
||||||
|
#[inline]
|
||||||
|
pub fn num_days_from_sunday(&self) -> u32 {
|
||||||
|
match *self {
|
||||||
|
Mon => 1,
|
||||||
|
Tue => 2,
|
||||||
|
Wed => 3,
|
||||||
|
Thu => 4,
|
||||||
|
Fri => 5,
|
||||||
|
Sat => 6,
|
||||||
|
Sun => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The common set of methods for date component.
|
||||||
|
pub trait Datelike {
|
||||||
|
/// Returns the year number.
|
||||||
|
fn year(&self) -> i32;
|
||||||
|
|
||||||
|
/// Returns the absolute year number starting from 1 with a boolean flag,
|
||||||
|
/// which is false when the year predates the epoch (BCE/BC) and true otherwise (CE/AD).
|
||||||
|
#[inline]
|
||||||
|
fn year_ce(&self) -> (bool, u32) {
|
||||||
|
let year = self.year();
|
||||||
|
if year < 1 {
|
||||||
|
(false, (1 - year) as u32)
|
||||||
|
} else {
|
||||||
|
(true, year as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the month number starting from 1.
|
||||||
|
fn month(&self) -> u32;
|
||||||
|
|
||||||
|
/// Returns the month number starting from 0.
|
||||||
|
fn month0(&self) -> u32;
|
||||||
|
|
||||||
|
/// Returns the day of month starting from 1.
|
||||||
|
fn day(&self) -> u32;
|
||||||
|
|
||||||
|
/// Returns the day of month starting from 0.
|
||||||
|
fn day0(&self) -> u32;
|
||||||
|
|
||||||
|
/// Returns the day of year starting from 1.
|
||||||
|
fn ordinal(&self) -> u32;
|
||||||
|
|
||||||
|
/// Returns the day of year starting from 0.
|
||||||
|
fn ordinal0(&self) -> u32;
|
||||||
|
|
||||||
|
/// Returns the day of week.
|
||||||
|
fn weekday(&self) -> Weekday;
|
||||||
|
|
||||||
|
/// Returns the ISO week date: an adjusted year, week number and day of week.
|
||||||
|
/// The adjusted year may differ from that of the calendar date.
|
||||||
|
fn isoweekdate(&self) -> (i32, u32, Weekday);
|
||||||
|
|
||||||
|
/// Makes a new value with the year number changed.
|
||||||
|
///
|
||||||
|
/// Returns `None` when the resulting value would be invalid.
|
||||||
|
fn with_year(&self, year: i32) -> Option<Self>;
|
||||||
|
|
||||||
|
/// Makes a new value with the month number (starting from 1) changed.
|
||||||
|
///
|
||||||
|
/// Returns `None` when the resulting value would be invalid.
|
||||||
|
fn with_month(&self, month: u32) -> Option<Self>;
|
||||||
|
|
||||||
|
/// Makes a new value with the month number (starting from 0) changed.
|
||||||
|
///
|
||||||
|
/// Returns `None` when the resulting value would be invalid.
|
||||||
|
fn with_month0(&self, month0: u32) -> Option<Self>;
|
||||||
|
|
||||||
|
/// Makes a new value with the day of month (starting from 1) changed.
|
||||||
|
///
|
||||||
|
/// Returns `None` when the resulting value would be invalid.
|
||||||
|
fn with_day(&self, day: u32) -> Option<Self>;
|
||||||
|
|
||||||
|
/// Makes a new value with the day of month (starting from 0) changed.
|
||||||
|
///
|
||||||
|
/// Returns `None` when the resulting value would be invalid.
|
||||||
|
fn with_day0(&self, day0: u32) -> Option<Self>;
|
||||||
|
|
||||||
|
/// Makes a new value with the day of year (starting from 1) changed.
|
||||||
|
///
|
||||||
|
/// Returns `None` when the resulting value would be invalid.
|
||||||
|
fn with_ordinal(&self, ordinal: u32) -> Option<Self>;
|
||||||
|
|
||||||
|
/// Makes a new value with the day of year (starting from 0) changed.
|
||||||
|
///
|
||||||
|
/// Returns `None` when the resulting value would be invalid.
|
||||||
|
fn with_ordinal0(&self, ordinal0: u32) -> Option<Self>;
|
||||||
|
|
||||||
|
/// Returns the number of days since January 1, 1 (Day 1) in the proleptic Gregorian calendar.
|
||||||
|
fn num_days_from_ce(&self) -> i32 {
|
||||||
|
// we know this wouldn't overflow since year is limited to 1/2^13 of i32's full range.
|
||||||
|
let mut year = self.year() - 1;
|
||||||
|
let mut ndays = 0;
|
||||||
|
if year < 0 {
|
||||||
|
let excess = 1 + (-year) / 400;
|
||||||
|
year += excess * 400;
|
||||||
|
ndays -= excess * 146097;
|
||||||
|
}
|
||||||
|
let div_100 = year / 100;
|
||||||
|
ndays += ((year * 1461) >> 2) - div_100 + (div_100 >> 2);
|
||||||
|
ndays + self.ordinal() as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The common set of methods for time component.
|
||||||
|
pub trait Timelike {
|
||||||
|
/// Returns the hour number from 0 to 23.
|
||||||
|
fn hour(&self) -> u32;
|
||||||
|
|
||||||
|
/// Returns the hour number from 1 to 12 with a boolean flag,
|
||||||
|
/// which is false for AM and true for PM.
|
||||||
|
#[inline]
|
||||||
|
fn hour12(&self) -> (bool, u32) {
|
||||||
|
let hour = self.hour();
|
||||||
|
let mut hour12 = hour % 12;
|
||||||
|
if hour12 == 0 { hour12 = 12; }
|
||||||
|
(hour >= 12, hour12)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the minute number from 0 to 59.
|
||||||
|
fn minute(&self) -> u32;
|
||||||
|
|
||||||
|
/// Returns the second number from 0 to 59.
|
||||||
|
fn second(&self) -> u32;
|
||||||
|
|
||||||
|
/// Returns the number of nanoseconds since the whole non-leap second.
|
||||||
|
/// The range from 1,000,000,000 to 1,999,999,999 represents the leap second.
|
||||||
|
fn nanosecond(&self) -> u32;
|
||||||
|
|
||||||
|
/// Makes a new value with the hour number changed.
|
||||||
|
///
|
||||||
|
/// Returns `None` when the resulting value would be invalid.
|
||||||
|
fn with_hour(&self, hour: u32) -> Option<Self>;
|
||||||
|
|
||||||
|
/// Makes a new value with the minute number changed.
|
||||||
|
///
|
||||||
|
/// Returns `None` when the resulting value would be invalid.
|
||||||
|
fn with_minute(&self, min: u32) -> Option<Self>;
|
||||||
|
|
||||||
|
/// Makes a new value with the second number changed.
|
||||||
|
///
|
||||||
|
/// Returns `None` when the resulting value would be invalid.
|
||||||
|
fn with_second(&self, sec: u32) -> Option<Self>;
|
||||||
|
|
||||||
|
/// Makes a new value with nanoseconds since the whole non-leap second changed.
|
||||||
|
///
|
||||||
|
/// Returns `None` when the resulting value would be invalid.
|
||||||
|
fn with_nanosecond(&self, nano: u32) -> Option<Self>;
|
||||||
|
|
||||||
|
/// Returns the number of non-leap seconds past the last midnight.
|
||||||
|
#[inline]
|
||||||
|
fn num_seconds_from_midnight(&self) -> u32 {
|
||||||
|
self.hour() * 3600 + self.minute() * 60 + self.second()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_readme_doomsday() {
|
fn test_readme_doomsday() {
|
||||||
use std::iter::range_inclusive;
|
use std::iter::range_inclusive;
|
||||||
|
|
||||||
for y in range_inclusive(date::MIN_NAIVE.year(), date::MAX_NAIVE.year()) {
|
for y in range_inclusive(naive::date::MIN.year(), naive::date::MAX.year()) {
|
||||||
// even months
|
// even months
|
||||||
let d4 = NaiveDate::from_ymd(y, 4, 4);
|
let d4 = NaiveDate::from_ymd(y, 4, 4);
|
||||||
let d6 = NaiveDate::from_ymd(y, 6, 6);
|
let d6 = NaiveDate::from_ymd(y, 6, 6);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,207 @@
|
||||||
|
// This is a part of rust-chrono.
|
||||||
|
// Copyright (c) 2014, Kang Seonghoon.
|
||||||
|
// See README.md and LICENSE.txt for details.
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* ISO 8601 date and time without timezone.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use {Weekday, Timelike, Datelike};
|
||||||
|
use duration::Duration;
|
||||||
|
use naive::time::NaiveTime;
|
||||||
|
use naive::date::NaiveDate;
|
||||||
|
|
||||||
|
/// ISO 8601 combined date and time without timezone.
|
||||||
|
#[deriving(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
|
||||||
|
pub struct NaiveDateTime {
|
||||||
|
date: NaiveDate,
|
||||||
|
time: NaiveTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NaiveDateTime {
|
||||||
|
/// Makes a new `NaiveDateTime` from date and time components.
|
||||||
|
/// Equivalent to `date.and_time(time)` and many other helper constructors on `NaiveDate`.
|
||||||
|
#[inline]
|
||||||
|
pub fn new(date: NaiveDate, time: NaiveTime) -> NaiveDateTime {
|
||||||
|
NaiveDateTime { date: date, time: time }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves a date component.
|
||||||
|
#[inline]
|
||||||
|
pub fn date(&self) -> NaiveDate {
|
||||||
|
self.date
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves a time component.
|
||||||
|
#[inline]
|
||||||
|
pub fn time(&self) -> NaiveTime {
|
||||||
|
self.time
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of non-leap seconds since January 1, 1970 0:00:00 UTC.
|
||||||
|
/// Note that this does *not* account for the timezone!
|
||||||
|
#[inline]
|
||||||
|
pub fn num_seconds_from_unix_epoch(&self) -> i64 {
|
||||||
|
let ndays = self.date.num_days_from_ce() as i64;
|
||||||
|
let nseconds = self.time.num_seconds_from_midnight() as i64;
|
||||||
|
(ndays - 719163) * 86400 + nseconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Datelike for NaiveDateTime {
|
||||||
|
#[inline] fn year(&self) -> i32 { self.date.year() }
|
||||||
|
#[inline] fn month(&self) -> u32 { self.date.month() }
|
||||||
|
#[inline] fn month0(&self) -> u32 { self.date.month0() }
|
||||||
|
#[inline] fn day(&self) -> u32 { self.date.day() }
|
||||||
|
#[inline] fn day0(&self) -> u32 { self.date.day0() }
|
||||||
|
#[inline] fn ordinal(&self) -> u32 { self.date.ordinal() }
|
||||||
|
#[inline] fn ordinal0(&self) -> u32 { self.date.ordinal0() }
|
||||||
|
#[inline] fn weekday(&self) -> Weekday { self.date.weekday() }
|
||||||
|
#[inline] fn isoweekdate(&self) -> (i32, u32, Weekday) { self.date.isoweekdate() }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_year(&self, year: i32) -> Option<NaiveDateTime> {
|
||||||
|
self.date.with_year(year).map(|d| NaiveDateTime { date: d, ..*self })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_month(&self, month: u32) -> Option<NaiveDateTime> {
|
||||||
|
self.date.with_month(month).map(|d| NaiveDateTime { date: d, ..*self })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_month0(&self, month0: u32) -> Option<NaiveDateTime> {
|
||||||
|
self.date.with_month0(month0).map(|d| NaiveDateTime { date: d, ..*self })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_day(&self, day: u32) -> Option<NaiveDateTime> {
|
||||||
|
self.date.with_day(day).map(|d| NaiveDateTime { date: d, ..*self })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_day0(&self, day0: u32) -> Option<NaiveDateTime> {
|
||||||
|
self.date.with_day0(day0).map(|d| NaiveDateTime { date: d, ..*self })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_ordinal(&self, ordinal: u32) -> Option<NaiveDateTime> {
|
||||||
|
self.date.with_ordinal(ordinal).map(|d| NaiveDateTime { date: d, ..*self })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_ordinal0(&self, ordinal0: u32) -> Option<NaiveDateTime> {
|
||||||
|
self.date.with_ordinal0(ordinal0).map(|d| NaiveDateTime { date: d, ..*self })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Timelike for NaiveDateTime {
|
||||||
|
#[inline] fn hour(&self) -> u32 { self.time.hour() }
|
||||||
|
#[inline] fn minute(&self) -> u32 { self.time.minute() }
|
||||||
|
#[inline] fn second(&self) -> u32 { self.time.second() }
|
||||||
|
#[inline] fn nanosecond(&self) -> u32 { self.time.nanosecond() }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_hour(&self, hour: u32) -> Option<NaiveDateTime> {
|
||||||
|
self.time.with_hour(hour).map(|t| NaiveDateTime { time: t, ..*self })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_minute(&self, min: u32) -> Option<NaiveDateTime> {
|
||||||
|
self.time.with_minute(min).map(|t| NaiveDateTime { time: t, ..*self })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_second(&self, sec: u32) -> Option<NaiveDateTime> {
|
||||||
|
self.time.with_second(sec).map(|t| NaiveDateTime { time: t, ..*self })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_nanosecond(&self, nano: u32) -> Option<NaiveDateTime> {
|
||||||
|
self.time.with_nanosecond(nano).map(|t| NaiveDateTime { time: t, ..*self })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<Duration,NaiveDateTime> for NaiveDateTime {
|
||||||
|
fn add(&self, rhs: &Duration) -> NaiveDateTime {
|
||||||
|
// we want `(NaiveDate + days in Duration) + (NaiveTime + secs/nanos in Duration)`
|
||||||
|
// to be equal to `NaiveDateTime + Duration`, but `NaiveDate + 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,
|
||||||
|
// this condition always means that the time part has been overflowed.
|
||||||
|
date = date.succ();
|
||||||
|
}
|
||||||
|
NaiveDateTime { date: date, time: time }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Rust issue #7590, the current coherence checker can't handle multiple Add impls
|
||||||
|
impl Add<NaiveDateTime,NaiveDateTime> for Duration {
|
||||||
|
#[inline]
|
||||||
|
fn add(&self, rhs: &NaiveDateTime) -> NaiveDateTime { rhs.add(self) }
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
impl Sub<NaiveDateTime,Duration> for NaiveDateTime {
|
||||||
|
fn sub(&self, rhs: &NaiveDateTime) -> Duration {
|
||||||
|
(self.date - rhs.date) + (self.time - rhs.time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Show for NaiveDateTime {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}T{}", self.date, self.time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use duration::Duration;
|
||||||
|
use naive::date::NaiveDate;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_datetime_add() {
|
||||||
|
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) + 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),
|
||||||
|
ymdhms(2014, 5, 16, 7, 8, 9));
|
||||||
|
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) + Duration::seconds(-86400 * 10),
|
||||||
|
ymdhms(2014, 4, 26, 7, 8, 9));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_datetime_sub() {
|
||||||
|
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, 10) - ymdhms(2014, 5, 6, 7, 8, 9),
|
||||||
|
Duration::seconds(1));
|
||||||
|
assert_eq!(ymdhms(2014, 5, 6, 7, 8, 9) - ymdhms(2014, 5, 6, 7, 8, 10),
|
||||||
|
Duration::seconds(-1));
|
||||||
|
assert_eq!(ymdhms(2014, 5, 7, 7, 8, 9) - ymdhms(2014, 5, 6, 7, 8, 10),
|
||||||
|
Duration::seconds(86399));
|
||||||
|
assert_eq!(ymdhms(2001, 9, 9, 1, 46, 39) - ymdhms(1970, 1, 1, 0, 0, 0),
|
||||||
|
Duration::seconds(999_999_999));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_datetime_num_seconds_from_unix_epoch() {
|
||||||
|
let to_timestamp =
|
||||||
|
|y,m,d,h,n,s| NaiveDate::from_ymd(y,m,d).and_hms(h,n,s).num_seconds_from_unix_epoch();
|
||||||
|
assert_eq!(to_timestamp(1969, 12, 31, 23, 59, 59), -1);
|
||||||
|
assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 0), 0);
|
||||||
|
assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 1), 1);
|
||||||
|
assert_eq!(to_timestamp(2001, 9, 9, 1, 46, 40), 1_000_000_000);
|
||||||
|
assert_eq!(to_timestamp(2038, 1, 19, 3, 14, 7), 0x7fffffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,334 @@
|
||||||
|
// This is a part of rust-chrono.
|
||||||
|
// Copyright (c) 2014, Kang Seonghoon.
|
||||||
|
// See README.md and LICENSE.txt for details.
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* ISO 8601 time without timezone.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use num::Integer;
|
||||||
|
|
||||||
|
use Timelike;
|
||||||
|
use offset::Offset;
|
||||||
|
use duration::Duration;
|
||||||
|
|
||||||
|
/// ISO 8601 time without timezone.
|
||||||
|
/// Allows for the nanosecond precision and optional leap second representation.
|
||||||
|
#[deriving(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
|
||||||
|
pub struct NaiveTime {
|
||||||
|
secs: u32,
|
||||||
|
frac: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NaiveTime {
|
||||||
|
/// Makes a new `NaiveTime` from hour, minute and second.
|
||||||
|
///
|
||||||
|
/// Fails on invalid hour, minute and/or second.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_hms(hour: u32, min: u32, sec: u32) -> NaiveTime {
|
||||||
|
NaiveTime::from_hms_opt(hour, min, sec).expect("invalid time")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes a new `NaiveTime` from hour, minute and second.
|
||||||
|
///
|
||||||
|
/// Returns `None` on invalid hour, minute and/or second.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_hms_opt(hour: u32, min: u32, sec: u32) -> Option<NaiveTime> {
|
||||||
|
NaiveTime::from_hms_nano_opt(hour, min, sec, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes a new `NaiveTime` from hour, minute, second and millisecond.
|
||||||
|
/// The millisecond part can exceed 1,000 in order to represent the leap second.
|
||||||
|
///
|
||||||
|
/// Fails on invalid hour, minute, second and/or millisecond.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_hms_milli(hour: u32, min: u32, sec: u32, milli: u32) -> NaiveTime {
|
||||||
|
NaiveTime::from_hms_milli_opt(hour, min, sec, milli).expect("invalid time")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes a new `NaiveTime` from hour, minute, second and millisecond.
|
||||||
|
/// The millisecond part can exceed 1,000 in order to represent the leap second.
|
||||||
|
///
|
||||||
|
/// Returns `None` on invalid hour, minute, second and/or millisecond.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_hms_milli_opt(hour: u32, min: u32, sec: u32, milli: u32) -> Option<NaiveTime> {
|
||||||
|
milli.checked_mul(&1_000_000)
|
||||||
|
.and_then(|nano| NaiveTime::from_hms_nano_opt(hour, min, sec, nano))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes a new `NaiveTime` from hour, minute, second and microsecond.
|
||||||
|
/// The microsecond part can exceed 1,000,000 in order to represent the leap second.
|
||||||
|
///
|
||||||
|
/// Fails on invalid hour, minute, second and/or microsecond.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_hms_micro(hour: u32, min: u32, sec: u32, micro: u32) -> NaiveTime {
|
||||||
|
NaiveTime::from_hms_micro_opt(hour, min, sec, micro).expect("invalid time")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes a new `NaiveTime` from hour, minute, second and microsecond.
|
||||||
|
/// The microsecond part can exceed 1,000,000 in order to represent the leap second.
|
||||||
|
///
|
||||||
|
/// Returns `None` on invalid hour, minute, second and/or microsecond.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_hms_micro_opt(hour: u32, min: u32, sec: u32, micro: u32) -> Option<NaiveTime> {
|
||||||
|
micro.checked_mul(&1_000)
|
||||||
|
.and_then(|nano| NaiveTime::from_hms_nano_opt(hour, min, sec, nano))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes a new `NaiveTime` from hour, minute, second and nanosecond.
|
||||||
|
/// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second.
|
||||||
|
///
|
||||||
|
/// Fails on invalid hour, minute, second and/or nanosecond.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_hms_nano(hour: u32, min: u32, sec: u32, nano: u32) -> NaiveTime {
|
||||||
|
NaiveTime::from_hms_nano_opt(hour, min, sec, nano).expect("invalid time")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes a new `NaiveTime` from hour, minute, second and nanosecond.
|
||||||
|
/// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second.
|
||||||
|
///
|
||||||
|
/// Returns `None` on invalid hour, minute, second and/or nanosecond.
|
||||||
|
pub fn from_hms_nano_opt(hour: u32, min: u32, sec: u32, nano: u32) -> Option<NaiveTime> {
|
||||||
|
if hour >= 24 || min >= 60 || sec >= 60 || nano >= 2_000_000_000 { return None; }
|
||||||
|
let secs = hour * 3600 + min * 60 + sec;
|
||||||
|
Some(NaiveTime { secs: secs, frac: nano })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a triple of the hour, minute and second numbers.
|
||||||
|
fn hms(&self) -> (u32, u32, u32) {
|
||||||
|
let (mins, sec) = self.secs.div_mod_floor(&60);
|
||||||
|
let (hour, min) = mins.div_mod_floor(&60);
|
||||||
|
(hour, min, sec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Timelike for NaiveTime {
|
||||||
|
#[inline] fn hour(&self) -> u32 { self.hms().val0() }
|
||||||
|
#[inline] fn minute(&self) -> u32 { self.hms().val1() }
|
||||||
|
#[inline] fn second(&self) -> u32 { self.hms().val2() }
|
||||||
|
#[inline] fn nanosecond(&self) -> u32 { self.frac }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_hour(&self, hour: u32) -> Option<NaiveTime> {
|
||||||
|
if hour >= 24 { return None; }
|
||||||
|
let secs = hour * 3600 + self.secs % 3600;
|
||||||
|
Some(NaiveTime { secs: secs, ..*self })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_minute(&self, min: u32) -> Option<NaiveTime> {
|
||||||
|
if min >= 60 { return None; }
|
||||||
|
let secs = self.secs / 3600 * 3600 + min * 60 + self.secs % 60;
|
||||||
|
Some(NaiveTime { secs: secs, ..*self })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_second(&self, sec: u32) -> Option<NaiveTime> {
|
||||||
|
if sec >= 60 { return None; }
|
||||||
|
let secs = self.secs / 60 * 60 + sec;
|
||||||
|
Some(NaiveTime { secs: secs, ..*self })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_nanosecond(&self, nano: u32) -> Option<NaiveTime> {
|
||||||
|
if nano >= 2_000_000_000 { return None; }
|
||||||
|
Some(NaiveTime { frac: nano, ..*self })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn num_seconds_from_midnight(&self) -> u32 {
|
||||||
|
self.secs // do not repeat the calculation!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<Duration,NaiveTime> for NaiveTime {
|
||||||
|
fn add(&self, rhs: &Duration) -> NaiveTime {
|
||||||
|
let (_, rhssecs, rhsnanos) = rhs.to_tuple();
|
||||||
|
let mut secs = self.secs + rhssecs;
|
||||||
|
let mut nanos = self.frac + rhsnanos;
|
||||||
|
|
||||||
|
// 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};
|
||||||
|
|
||||||
|
if nanos >= maxnanos {
|
||||||
|
nanos -= maxnanos;
|
||||||
|
secs += 1;
|
||||||
|
}
|
||||||
|
NaiveTime { secs: secs % 86400, frac: nanos }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Rust issue #7590, the current coherence checker can't handle multiple Add impls
|
||||||
|
impl Add<NaiveTime,NaiveTime> for Duration {
|
||||||
|
#[inline]
|
||||||
|
fn add(&self, rhs: &NaiveTime) -> NaiveTime { rhs.add(self) }
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
impl Sub<NaiveTime,Duration> for NaiveTime {
|
||||||
|
fn sub(&self, rhs: &NaiveTime) -> Duration {
|
||||||
|
// the number of whole non-leap seconds
|
||||||
|
let secs = self.secs as i32 - rhs.secs as i32 - 1;
|
||||||
|
|
||||||
|
// 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 nanos1 = maxnanos - rhs.frac;
|
||||||
|
|
||||||
|
// the fractional second from the last leap or non-leap second to the lhs
|
||||||
|
let lastfrac = if self.frac >= 1_000_000_000 {1_000_000_000} else {0};
|
||||||
|
let nanos2 = self.frac - lastfrac;
|
||||||
|
|
||||||
|
Duration::seconds(secs) + Duration::nanoseconds(nanos1 as i32 + nanos2 as i32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Show for NaiveTime {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let (hour, min, sec) = self.hms();
|
||||||
|
let (sec, nano) = if self.frac >= 1_000_000_000 {
|
||||||
|
(sec + 1, self.frac - 1_000_000_000)
|
||||||
|
} else {
|
||||||
|
(sec, self.frac)
|
||||||
|
};
|
||||||
|
|
||||||
|
try!(write!(f, "{:02}:{:02}:{:02}", hour, min, sec));
|
||||||
|
if nano == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else if nano % 1_000_000 == 0 {
|
||||||
|
write!(f, ",{:03}", nano / 1_000_000)
|
||||||
|
} else if nano % 1_000 == 0 {
|
||||||
|
write!(f, ",{:06}", nano / 1_000)
|
||||||
|
} else {
|
||||||
|
write!(f, ",{:09}", nano)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::NaiveTime;
|
||||||
|
use Timelike;
|
||||||
|
use duration::Duration;
|
||||||
|
use std::u32;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_time_from_hms_milli() {
|
||||||
|
assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 0),
|
||||||
|
Some(NaiveTime::from_hms_nano(3, 5, 7, 0)));
|
||||||
|
assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 777),
|
||||||
|
Some(NaiveTime::from_hms_nano(3, 5, 7, 777_000_000)));
|
||||||
|
assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 1_999),
|
||||||
|
Some(NaiveTime::from_hms_nano(3, 5, 7, 1_999_000_000)));
|
||||||
|
assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 2_000), None);
|
||||||
|
assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 5_000), None); // overflow check
|
||||||
|
assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, u32::MAX), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_time_from_hms_micro() {
|
||||||
|
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 0),
|
||||||
|
Some(NaiveTime::from_hms_nano(3, 5, 7, 0)));
|
||||||
|
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 333),
|
||||||
|
Some(NaiveTime::from_hms_nano(3, 5, 7, 333_000)));
|
||||||
|
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 777_777),
|
||||||
|
Some(NaiveTime::from_hms_nano(3, 5, 7, 777_777_000)));
|
||||||
|
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 1_999_999),
|
||||||
|
Some(NaiveTime::from_hms_nano(3, 5, 7, 1_999_999_000)));
|
||||||
|
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 2_000_000), None);
|
||||||
|
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 5_000_000), None); // overflow check
|
||||||
|
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, u32::MAX), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_time_hms() {
|
||||||
|
assert_eq!(NaiveTime::from_hms(3, 5, 7).hour(), 3);
|
||||||
|
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(0),
|
||||||
|
Some(NaiveTime::from_hms(0, 5, 7)));
|
||||||
|
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(23),
|
||||||
|
Some(NaiveTime::from_hms(23, 5, 7)));
|
||||||
|
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(24), None);
|
||||||
|
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(u32::MAX), None);
|
||||||
|
|
||||||
|
assert_eq!(NaiveTime::from_hms(3, 5, 7).minute(), 5);
|
||||||
|
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(0),
|
||||||
|
Some(NaiveTime::from_hms(3, 0, 7)));
|
||||||
|
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(59),
|
||||||
|
Some(NaiveTime::from_hms(3, 59, 7)));
|
||||||
|
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(60), None);
|
||||||
|
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(u32::MAX), None);
|
||||||
|
|
||||||
|
assert_eq!(NaiveTime::from_hms(3, 5, 7).second(), 7);
|
||||||
|
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(0),
|
||||||
|
Some(NaiveTime::from_hms(3, 5, 0)));
|
||||||
|
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(59),
|
||||||
|
Some(NaiveTime::from_hms(3, 5, 59)));
|
||||||
|
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(60), None);
|
||||||
|
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(u32::MAX), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_time_add() {
|
||||||
|
fn check(lhs: NaiveTime, rhs: Duration, sum: NaiveTime) {
|
||||||
|
assert_eq!(lhs + rhs, sum);
|
||||||
|
//assert_eq!(rhs + lhs, sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
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), 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, 900), Duration::seconds(86399), hmsm(3, 5, 6, 900)); // overwrap
|
||||||
|
check(hmsm(3, 5, 7, 900), Duration::seconds(-86399), hmsm(3, 5, 8, 900));
|
||||||
|
check(hmsm(3, 5, 7, 900), Duration::days(12345), hmsm(3, 5, 7, 900));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_time_sub() {
|
||||||
|
fn check(lhs: NaiveTime, rhs: NaiveTime, diff: Duration) {
|
||||||
|
// `time1 - time2 = duration` is equivalent to `time2 - time1 = -duration`
|
||||||
|
assert_eq!(lhs - rhs, diff);
|
||||||
|
assert_eq!(rhs - lhs, -diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
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, 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, 300),
|
||||||
|
Duration::seconds(3600 + 60) + Duration::milliseconds(900));
|
||||||
|
|
||||||
|
// treats the leap second as if it coincides with the prior non-leap second,
|
||||||
|
// as required by `time1 - time2 = duration` and `time2 - time1 = -duration` equivalence.
|
||||||
|
check(hmsm(3, 5, 7, 200), hmsm(3, 5, 6, 1_800), Duration::milliseconds(400));
|
||||||
|
check(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 1_800), Duration::milliseconds(400));
|
||||||
|
check(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 800), Duration::milliseconds(400));
|
||||||
|
|
||||||
|
// additional equality: `time1 + duration = time2` is equivalent to
|
||||||
|
// `time2 - time1 = duration` IF AND ONLY IF `time2` represents a non-leap second.
|
||||||
|
assert_eq!(hmsm(3, 5, 6, 800) + Duration::milliseconds(400), hmsm(3, 5, 7, 200));
|
||||||
|
assert_eq!(hmsm(3, 5, 6, 1_800) + Duration::milliseconds(400), hmsm(3, 5, 7, 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_time_fmt() {
|
||||||
|
assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 999).to_string(),
|
||||||
|
"23:59:59,999".to_string());
|
||||||
|
assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_000).to_string(),
|
||||||
|
"23:59:60".to_string());
|
||||||
|
assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_001).to_string(),
|
||||||
|
"23:59:60,001".to_string());
|
||||||
|
assert_eq!(NaiveTime::from_hms_micro(0, 0, 0, 43210).to_string(),
|
||||||
|
"00:00:00,043210".to_string());
|
||||||
|
assert_eq!(NaiveTime::from_hms_nano(0, 0, 0, 6543210).to_string(),
|
||||||
|
"00:00:00,006543210".to_string());
|
||||||
|
|
||||||
|
// the format specifier should have no effect on `NaiveTime`
|
||||||
|
assert_eq!(format!("{:30}", NaiveTime::from_hms_milli(3, 5, 7, 9)),
|
||||||
|
"03:05:07,009".to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,10 +8,15 @@
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use num::Integer;
|
use num::Integer;
|
||||||
|
|
||||||
|
use Weekday;
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
use date::{NaiveDate, Date, Weekday};
|
use naive::date::NaiveDate;
|
||||||
use time::{NaiveTime, Time};
|
use naive::time::NaiveTime;
|
||||||
use datetime::{NaiveDateTime, DateTime};
|
use naive::datetime::NaiveDateTime;
|
||||||
|
use date::Date;
|
||||||
|
use time::Time;
|
||||||
|
use datetime::DateTime;
|
||||||
|
|
||||||
/// The conversion result from the local time to the timezone-aware datetime types.
|
/// The conversion result from the local time to the timezone-aware datetime types.
|
||||||
pub enum LocalResult<T> {
|
pub enum LocalResult<T> {
|
||||||
|
|
376
src/time.rs
376
src/time.rs
|
@ -3,258 +3,15 @@
|
||||||
// See README.md and LICENSE.txt for details.
|
// See README.md and LICENSE.txt for details.
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* ISO 8601 time.
|
* ISO 8601 time with timezone.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::{fmt, hash};
|
use std::{fmt, hash};
|
||||||
use num::Integer;
|
|
||||||
|
use Timelike;
|
||||||
use offset::Offset;
|
use offset::Offset;
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
|
use naive::time::NaiveTime;
|
||||||
/// The common set of methods for time component.
|
|
||||||
pub trait Timelike {
|
|
||||||
/// Returns the hour number from 0 to 23.
|
|
||||||
fn hour(&self) -> u32;
|
|
||||||
|
|
||||||
/// Returns the hour number from 1 to 12 with a boolean flag,
|
|
||||||
/// which is false for AM and true for PM.
|
|
||||||
#[inline]
|
|
||||||
fn hour12(&self) -> (bool, u32) {
|
|
||||||
let hour = self.hour();
|
|
||||||
let mut hour12 = hour % 12;
|
|
||||||
if hour12 == 0 { hour12 = 12; }
|
|
||||||
(hour >= 12, hour12)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the minute number from 0 to 59.
|
|
||||||
fn minute(&self) -> u32;
|
|
||||||
|
|
||||||
/// Returns the second number from 0 to 59.
|
|
||||||
fn second(&self) -> u32;
|
|
||||||
|
|
||||||
/// Returns the number of nanoseconds since the whole non-leap second.
|
|
||||||
/// The range from 1,000,000,000 to 1,999,999,999 represents the leap second.
|
|
||||||
fn nanosecond(&self) -> u32;
|
|
||||||
|
|
||||||
/// Makes a new value with the hour number changed.
|
|
||||||
///
|
|
||||||
/// Returns `None` when the resulting value would be invalid.
|
|
||||||
fn with_hour(&self, hour: u32) -> Option<Self>;
|
|
||||||
|
|
||||||
/// Makes a new value with the minute number changed.
|
|
||||||
///
|
|
||||||
/// Returns `None` when the resulting value would be invalid.
|
|
||||||
fn with_minute(&self, min: u32) -> Option<Self>;
|
|
||||||
|
|
||||||
/// Makes a new value with the second number changed.
|
|
||||||
///
|
|
||||||
/// Returns `None` when the resulting value would be invalid.
|
|
||||||
fn with_second(&self, sec: u32) -> Option<Self>;
|
|
||||||
|
|
||||||
/// Makes a new value with nanoseconds since the whole non-leap second changed.
|
|
||||||
///
|
|
||||||
/// Returns `None` when the resulting value would be invalid.
|
|
||||||
fn with_nanosecond(&self, nano: u32) -> Option<Self>;
|
|
||||||
|
|
||||||
/// Returns the number of non-leap seconds past the last midnight.
|
|
||||||
#[inline]
|
|
||||||
fn num_seconds_from_midnight(&self) -> u32 {
|
|
||||||
self.hour() * 3600 + self.minute() * 60 + self.second()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ISO 8601 time without timezone.
|
|
||||||
/// Allows for the nanosecond precision and optional leap second representation.
|
|
||||||
#[deriving(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
|
|
||||||
pub struct NaiveTime {
|
|
||||||
secs: u32,
|
|
||||||
frac: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NaiveTime {
|
|
||||||
/// Makes a new `NaiveTime` from hour, minute and second.
|
|
||||||
///
|
|
||||||
/// Fails on invalid hour, minute and/or second.
|
|
||||||
#[inline]
|
|
||||||
pub fn from_hms(hour: u32, min: u32, sec: u32) -> NaiveTime {
|
|
||||||
NaiveTime::from_hms_opt(hour, min, sec).expect("invalid time")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a new `NaiveTime` from hour, minute and second.
|
|
||||||
///
|
|
||||||
/// Returns `None` on invalid hour, minute and/or second.
|
|
||||||
#[inline]
|
|
||||||
pub fn from_hms_opt(hour: u32, min: u32, sec: u32) -> Option<NaiveTime> {
|
|
||||||
NaiveTime::from_hms_nano_opt(hour, min, sec, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a new `NaiveTime` from hour, minute, second and millisecond.
|
|
||||||
/// The millisecond part can exceed 1,000 in order to represent the leap second.
|
|
||||||
///
|
|
||||||
/// Fails on invalid hour, minute, second and/or millisecond.
|
|
||||||
#[inline]
|
|
||||||
pub fn from_hms_milli(hour: u32, min: u32, sec: u32, milli: u32) -> NaiveTime {
|
|
||||||
NaiveTime::from_hms_milli_opt(hour, min, sec, milli).expect("invalid time")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a new `NaiveTime` from hour, minute, second and millisecond.
|
|
||||||
/// The millisecond part can exceed 1,000 in order to represent the leap second.
|
|
||||||
///
|
|
||||||
/// Returns `None` on invalid hour, minute, second and/or millisecond.
|
|
||||||
#[inline]
|
|
||||||
pub fn from_hms_milli_opt(hour: u32, min: u32, sec: u32, milli: u32) -> Option<NaiveTime> {
|
|
||||||
milli.checked_mul(&1_000_000)
|
|
||||||
.and_then(|nano| NaiveTime::from_hms_nano_opt(hour, min, sec, nano))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a new `NaiveTime` from hour, minute, second and microsecond.
|
|
||||||
/// The microsecond part can exceed 1,000,000 in order to represent the leap second.
|
|
||||||
///
|
|
||||||
/// Fails on invalid hour, minute, second and/or microsecond.
|
|
||||||
#[inline]
|
|
||||||
pub fn from_hms_micro(hour: u32, min: u32, sec: u32, micro: u32) -> NaiveTime {
|
|
||||||
NaiveTime::from_hms_micro_opt(hour, min, sec, micro).expect("invalid time")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a new `NaiveTime` from hour, minute, second and microsecond.
|
|
||||||
/// The microsecond part can exceed 1,000,000 in order to represent the leap second.
|
|
||||||
///
|
|
||||||
/// Returns `None` on invalid hour, minute, second and/or microsecond.
|
|
||||||
#[inline]
|
|
||||||
pub fn from_hms_micro_opt(hour: u32, min: u32, sec: u32, micro: u32) -> Option<NaiveTime> {
|
|
||||||
micro.checked_mul(&1_000)
|
|
||||||
.and_then(|nano| NaiveTime::from_hms_nano_opt(hour, min, sec, nano))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a new `NaiveTime` from hour, minute, second and nanosecond.
|
|
||||||
/// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second.
|
|
||||||
///
|
|
||||||
/// Fails on invalid hour, minute, second and/or nanosecond.
|
|
||||||
#[inline]
|
|
||||||
pub fn from_hms_nano(hour: u32, min: u32, sec: u32, nano: u32) -> NaiveTime {
|
|
||||||
NaiveTime::from_hms_nano_opt(hour, min, sec, nano).expect("invalid time")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a new `NaiveTime` from hour, minute, second and nanosecond.
|
|
||||||
/// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second.
|
|
||||||
///
|
|
||||||
/// Returns `None` on invalid hour, minute, second and/or nanosecond.
|
|
||||||
pub fn from_hms_nano_opt(hour: u32, min: u32, sec: u32, nano: u32) -> Option<NaiveTime> {
|
|
||||||
if hour >= 24 || min >= 60 || sec >= 60 || nano >= 2_000_000_000 { return None; }
|
|
||||||
let secs = hour * 3600 + min * 60 + sec;
|
|
||||||
Some(NaiveTime { secs: secs, frac: nano })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a triple of the hour, minute and second numbers.
|
|
||||||
fn hms(&self) -> (u32, u32, u32) {
|
|
||||||
let (mins, sec) = self.secs.div_mod_floor(&60);
|
|
||||||
let (hour, min) = mins.div_mod_floor(&60);
|
|
||||||
(hour, min, sec)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Timelike for NaiveTime {
|
|
||||||
#[inline] fn hour(&self) -> u32 { self.hms().val0() }
|
|
||||||
#[inline] fn minute(&self) -> u32 { self.hms().val1() }
|
|
||||||
#[inline] fn second(&self) -> u32 { self.hms().val2() }
|
|
||||||
#[inline] fn nanosecond(&self) -> u32 { self.frac }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_hour(&self, hour: u32) -> Option<NaiveTime> {
|
|
||||||
if hour >= 24 { return None; }
|
|
||||||
let secs = hour * 3600 + self.secs % 3600;
|
|
||||||
Some(NaiveTime { secs: secs, ..*self })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_minute(&self, min: u32) -> Option<NaiveTime> {
|
|
||||||
if min >= 60 { return None; }
|
|
||||||
let secs = self.secs / 3600 * 3600 + min * 60 + self.secs % 60;
|
|
||||||
Some(NaiveTime { secs: secs, ..*self })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_second(&self, sec: u32) -> Option<NaiveTime> {
|
|
||||||
if sec >= 60 { return None; }
|
|
||||||
let secs = self.secs / 60 * 60 + sec;
|
|
||||||
Some(NaiveTime { secs: secs, ..*self })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn with_nanosecond(&self, nano: u32) -> Option<NaiveTime> {
|
|
||||||
if nano >= 2_000_000_000 { return None; }
|
|
||||||
Some(NaiveTime { frac: nano, ..*self })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn num_seconds_from_midnight(&self) -> u32 {
|
|
||||||
self.secs // do not repeat the calculation!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<Duration,NaiveTime> for NaiveTime {
|
|
||||||
fn add(&self, rhs: &Duration) -> NaiveTime {
|
|
||||||
let (_, rhssecs, rhsnanos) = rhs.to_tuple();
|
|
||||||
let mut secs = self.secs + rhssecs;
|
|
||||||
let mut nanos = self.frac + rhsnanos;
|
|
||||||
|
|
||||||
// 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};
|
|
||||||
|
|
||||||
if nanos >= maxnanos {
|
|
||||||
nanos -= maxnanos;
|
|
||||||
secs += 1;
|
|
||||||
}
|
|
||||||
NaiveTime { secs: secs % 86400, frac: nanos }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// Rust issue #7590, the current coherence checker can't handle multiple Add impls
|
|
||||||
impl Add<NaiveTime,NaiveTime> for Duration {
|
|
||||||
#[inline]
|
|
||||||
fn add(&self, rhs: &NaiveTime) -> NaiveTime { rhs.add(self) }
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
impl Sub<NaiveTime,Duration> for NaiveTime {
|
|
||||||
fn sub(&self, rhs: &NaiveTime) -> Duration {
|
|
||||||
// the number of whole non-leap seconds
|
|
||||||
let secs = self.secs as i32 - rhs.secs as i32 - 1;
|
|
||||||
|
|
||||||
// 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 nanos1 = maxnanos - rhs.frac;
|
|
||||||
|
|
||||||
// the fractional second from the last leap or non-leap second to the lhs
|
|
||||||
let lastfrac = if self.frac >= 1_000_000_000 {1_000_000_000} else {0};
|
|
||||||
let nanos2 = self.frac - lastfrac;
|
|
||||||
|
|
||||||
Duration::seconds(secs) + Duration::nanoseconds(nanos1 as i32 + nanos2 as i32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Show for NaiveTime {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
let (hour, min, sec) = self.hms();
|
|
||||||
let (sec, nano) = if self.frac >= 1_000_000_000 {
|
|
||||||
(sec + 1, self.frac - 1_000_000_000)
|
|
||||||
} else {
|
|
||||||
(sec, self.frac)
|
|
||||||
};
|
|
||||||
|
|
||||||
try!(write!(f, "{:02}:{:02}:{:02}", hour, min, sec));
|
|
||||||
if nano == 0 {
|
|
||||||
Ok(())
|
|
||||||
} else if nano % 1_000_000 == 0 {
|
|
||||||
write!(f, ",{:03}", nano / 1_000_000)
|
|
||||||
} else if nano % 1_000 == 0 {
|
|
||||||
write!(f, ",{:06}", nano / 1_000)
|
|
||||||
} else {
|
|
||||||
write!(f, ",{:09}", nano)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ISO 8601 time with timezone.
|
/// ISO 8601 time with timezone.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
|
@ -362,128 +119,3 @@ impl<Off:Offset> fmt::Show for Time<Off> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::{Timelike, NaiveTime};
|
|
||||||
use duration::Duration;
|
|
||||||
use std::u32;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_time_from_hms_milli() {
|
|
||||||
assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 0),
|
|
||||||
Some(NaiveTime::from_hms_nano(3, 5, 7, 0)));
|
|
||||||
assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 777),
|
|
||||||
Some(NaiveTime::from_hms_nano(3, 5, 7, 777_000_000)));
|
|
||||||
assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 1_999),
|
|
||||||
Some(NaiveTime::from_hms_nano(3, 5, 7, 1_999_000_000)));
|
|
||||||
assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 2_000), None);
|
|
||||||
assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 5_000), None); // overflow check
|
|
||||||
assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, u32::MAX), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_time_from_hms_micro() {
|
|
||||||
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 0),
|
|
||||||
Some(NaiveTime::from_hms_nano(3, 5, 7, 0)));
|
|
||||||
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 333),
|
|
||||||
Some(NaiveTime::from_hms_nano(3, 5, 7, 333_000)));
|
|
||||||
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 777_777),
|
|
||||||
Some(NaiveTime::from_hms_nano(3, 5, 7, 777_777_000)));
|
|
||||||
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 1_999_999),
|
|
||||||
Some(NaiveTime::from_hms_nano(3, 5, 7, 1_999_999_000)));
|
|
||||||
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 2_000_000), None);
|
|
||||||
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 5_000_000), None); // overflow check
|
|
||||||
assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, u32::MAX), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_time_hms() {
|
|
||||||
assert_eq!(NaiveTime::from_hms(3, 5, 7).hour(), 3);
|
|
||||||
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(0),
|
|
||||||
Some(NaiveTime::from_hms(0, 5, 7)));
|
|
||||||
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(23),
|
|
||||||
Some(NaiveTime::from_hms(23, 5, 7)));
|
|
||||||
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(24), None);
|
|
||||||
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(u32::MAX), None);
|
|
||||||
|
|
||||||
assert_eq!(NaiveTime::from_hms(3, 5, 7).minute(), 5);
|
|
||||||
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(0),
|
|
||||||
Some(NaiveTime::from_hms(3, 0, 7)));
|
|
||||||
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(59),
|
|
||||||
Some(NaiveTime::from_hms(3, 59, 7)));
|
|
||||||
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(60), None);
|
|
||||||
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(u32::MAX), None);
|
|
||||||
|
|
||||||
assert_eq!(NaiveTime::from_hms(3, 5, 7).second(), 7);
|
|
||||||
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(0),
|
|
||||||
Some(NaiveTime::from_hms(3, 5, 0)));
|
|
||||||
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(59),
|
|
||||||
Some(NaiveTime::from_hms(3, 5, 59)));
|
|
||||||
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(60), None);
|
|
||||||
assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(u32::MAX), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_time_add() {
|
|
||||||
fn check(lhs: NaiveTime, rhs: Duration, sum: NaiveTime) {
|
|
||||||
assert_eq!(lhs + rhs, sum);
|
|
||||||
//assert_eq!(rhs + lhs, sum);
|
|
||||||
}
|
|
||||||
|
|
||||||
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), 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, 900), Duration::seconds(86399), hmsm(3, 5, 6, 900)); // overwrap
|
|
||||||
check(hmsm(3, 5, 7, 900), Duration::seconds(-86399), hmsm(3, 5, 8, 900));
|
|
||||||
check(hmsm(3, 5, 7, 900), Duration::days(12345), hmsm(3, 5, 7, 900));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_time_sub() {
|
|
||||||
fn check(lhs: NaiveTime, rhs: NaiveTime, diff: Duration) {
|
|
||||||
// `time1 - time2 = duration` is equivalent to `time2 - time1 = -duration`
|
|
||||||
assert_eq!(lhs - rhs, diff);
|
|
||||||
assert_eq!(rhs - lhs, -diff);
|
|
||||||
}
|
|
||||||
|
|
||||||
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, 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, 300),
|
|
||||||
Duration::seconds(3600 + 60) + Duration::milliseconds(900));
|
|
||||||
|
|
||||||
// treats the leap second as if it coincides with the prior non-leap second,
|
|
||||||
// as required by `time1 - time2 = duration` and `time2 - time1 = -duration` equivalence.
|
|
||||||
check(hmsm(3, 5, 7, 200), hmsm(3, 5, 6, 1_800), Duration::milliseconds(400));
|
|
||||||
check(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 1_800), Duration::milliseconds(400));
|
|
||||||
check(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 800), Duration::milliseconds(400));
|
|
||||||
|
|
||||||
// additional equality: `time1 + duration = time2` is equivalent to
|
|
||||||
// `time2 - time1 = duration` IF AND ONLY IF `time2` represents a non-leap second.
|
|
||||||
assert_eq!(hmsm(3, 5, 6, 800) + Duration::milliseconds(400), hmsm(3, 5, 7, 200));
|
|
||||||
assert_eq!(hmsm(3, 5, 6, 1_800) + Duration::milliseconds(400), hmsm(3, 5, 7, 200));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_time_fmt() {
|
|
||||||
assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 999).to_string(),
|
|
||||||
"23:59:59,999".to_string());
|
|
||||||
assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_000).to_string(),
|
|
||||||
"23:59:60".to_string());
|
|
||||||
assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_001).to_string(),
|
|
||||||
"23:59:60,001".to_string());
|
|
||||||
assert_eq!(NaiveTime::from_hms_micro(0, 0, 0, 43210).to_string(),
|
|
||||||
"00:00:00,043210".to_string());
|
|
||||||
assert_eq!(NaiveTime::from_hms_nano(0, 0, 0, 6543210).to_string(),
|
|
||||||
"00:00:00,006543210".to_string());
|
|
||||||
|
|
||||||
// the format specifier should have no effect on `NaiveTime`
|
|
||||||
assert_eq!(format!("{:30}", NaiveTime::from_hms_milli(3, 5, 7, 9)),
|
|
||||||
"03:05:07,009".to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue