added constructors from timestamp; added `UTC::{today,now}`.
This commit is contained in:
parent
55d5d49f1c
commit
9d52c6d2f1
|
@ -442,12 +442,13 @@ mod tests {
|
||||||
assert_eq!(Duration::zero(), Duration::zero());
|
assert_eq!(Duration::zero(), Duration::zero());
|
||||||
assert!(Duration::zero() != Duration::seconds(1));
|
assert!(Duration::zero() != Duration::seconds(1));
|
||||||
assert_eq!(Duration::seconds(1) + Duration::seconds(2), Duration::seconds(3));
|
assert_eq!(Duration::seconds(1) + Duration::seconds(2), Duration::seconds(3));
|
||||||
assert_eq!(Duration::seconds(86399) + Duration::seconds(4),
|
assert_eq!(Duration::milliseconds(997) + Duration::milliseconds(15),
|
||||||
Duration::days(1) + Duration::seconds(3));
|
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(1000), Duration::seconds(863000));
|
||||||
assert_eq!(Duration::days(10) - Duration::seconds(1000000), Duration::seconds(-136000));
|
assert_eq!(Duration::days(10) - Duration::seconds(1000000), Duration::seconds(-136000));
|
||||||
assert_eq!(Duration::days(2) + Duration::seconds(86399) + Duration::nanoseconds(1234567890),
|
assert_eq!(Duration::days(2) + Duration::seconds(86399) + Duration::nanoseconds(1234567890),
|
||||||
Duration::days(3) + Duration::nanoseconds(234567890));
|
Duration::new(3, 0, 234567890));
|
||||||
assert_eq!(-Duration::days(3), Duration::days(-3));
|
assert_eq!(-Duration::days(3), Duration::days(-3));
|
||||||
assert_eq!(-(Duration::days(3) + Duration::seconds(70)),
|
assert_eq!(-(Duration::days(3) + Duration::seconds(70)),
|
||||||
Duration::days(-4) + Duration::seconds(86400-70));
|
Duration::days(-4) + Duration::seconds(86400-70));
|
||||||
|
|
|
@ -13,6 +13,7 @@ Experimental date and time handling for Rust.
|
||||||
#![deny(missing_doc)]
|
#![deny(missing_doc)]
|
||||||
|
|
||||||
extern crate num;
|
extern crate num;
|
||||||
|
extern crate stdtime = "time";
|
||||||
|
|
||||||
pub use duration::Duration;
|
pub use duration::Duration;
|
||||||
pub use offset::{Offset, LocalResult};
|
pub use offset::{Offset, LocalResult};
|
||||||
|
|
|
@ -131,6 +131,28 @@ impl NaiveDate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a new `NaiveDate` from the number of days since January 1, 1 (Day 1)
|
||||||
|
/// in the proleptic Gregorian calendar.
|
||||||
|
///
|
||||||
|
/// Fails on the out-of-range date.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_num_days_from_ce(days: i32) -> NaiveDate {
|
||||||
|
NaiveDate::from_num_days_from_ce_opt(days).expect("out-of-range date")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes a new `NaiveDate` from the number of days since January 1, 1 (Day 1)
|
||||||
|
/// in the proleptic Gregorian calendar.
|
||||||
|
///
|
||||||
|
/// Returns `None` on the out-of-range date.
|
||||||
|
pub fn from_num_days_from_ce_opt(days: i32) -> Option<NaiveDate> {
|
||||||
|
let days = days + 365; // make January 1, 1 BCE equal to day 0
|
||||||
|
let (year_div_400, cycle) = days.div_mod_floor(&146097);
|
||||||
|
let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32);
|
||||||
|
let flags = unsafe { YearFlags::from_year_mod_400(year_mod_400 as i32) };
|
||||||
|
NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32,
|
||||||
|
Of::new(ordinal, flags))
|
||||||
|
}
|
||||||
|
|
||||||
/// Makes a new `NaiveDateTime` from the current date and given `NaiveTime`.
|
/// Makes a new `NaiveDateTime` from the current date and given `NaiveTime`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn and_time(&self, time: NaiveTime) -> NaiveDateTime {
|
pub fn and_time(&self, time: NaiveTime) -> NaiveDateTime {
|
||||||
|
@ -409,7 +431,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::iter::range_inclusive;
|
use std::iter::{range_inclusive, range_step_inclusive};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date_from_ymd() {
|
fn test_date_from_ymd() {
|
||||||
|
@ -519,6 +541,37 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_date_from_num_days_from_ce() {
|
||||||
|
let from_ndays_from_ce = |days| NaiveDate::from_num_days_from_ce_opt(days);
|
||||||
|
assert_eq!(from_ndays_from_ce(1), Some(NaiveDate::from_ymd(1, 1, 1)));
|
||||||
|
assert_eq!(from_ndays_from_ce(2), Some(NaiveDate::from_ymd(1, 1, 2)));
|
||||||
|
assert_eq!(from_ndays_from_ce(31), Some(NaiveDate::from_ymd(1, 1, 31)));
|
||||||
|
assert_eq!(from_ndays_from_ce(32), Some(NaiveDate::from_ymd(1, 2, 1)));
|
||||||
|
assert_eq!(from_ndays_from_ce(59), Some(NaiveDate::from_ymd(1, 2, 28)));
|
||||||
|
assert_eq!(from_ndays_from_ce(60), Some(NaiveDate::from_ymd(1, 3, 1)));
|
||||||
|
assert_eq!(from_ndays_from_ce(365), Some(NaiveDate::from_ymd(1, 12, 31)));
|
||||||
|
assert_eq!(from_ndays_from_ce(365*1 + 1), Some(NaiveDate::from_ymd(2, 1, 1)));
|
||||||
|
assert_eq!(from_ndays_from_ce(365*2 + 1), Some(NaiveDate::from_ymd(3, 1, 1)));
|
||||||
|
assert_eq!(from_ndays_from_ce(365*3 + 1), Some(NaiveDate::from_ymd(4, 1, 1)));
|
||||||
|
assert_eq!(from_ndays_from_ce(365*4 + 2), Some(NaiveDate::from_ymd(5, 1, 1)));
|
||||||
|
assert_eq!(from_ndays_from_ce(146097 + 1), Some(NaiveDate::from_ymd(401, 1, 1)));
|
||||||
|
assert_eq!(from_ndays_from_ce(146097*5 + 1), Some(NaiveDate::from_ymd(2001, 1, 1)));
|
||||||
|
assert_eq!(from_ndays_from_ce(719163), Some(NaiveDate::from_ymd(1970, 1, 1)));
|
||||||
|
assert_eq!(from_ndays_from_ce(0), Some(NaiveDate::from_ymd(0, 12, 31))); // 1 BCE
|
||||||
|
assert_eq!(from_ndays_from_ce(-365), Some(NaiveDate::from_ymd(0, 1, 1)));
|
||||||
|
assert_eq!(from_ndays_from_ce(-366), Some(NaiveDate::from_ymd(-1, 12, 31))); // 2 BCE
|
||||||
|
|
||||||
|
for days in range_step_inclusive(-999900i32, 1000000, 100) {
|
||||||
|
assert_eq!(from_ndays_from_ce(days).map(|d| d.num_days_from_ce()), Some(days));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(from_ndays_from_ce(MIN.num_days_from_ce()), Some(MIN));
|
||||||
|
assert_eq!(from_ndays_from_ce(MIN.num_days_from_ce() - 1), None);
|
||||||
|
assert_eq!(from_ndays_from_ce(MAX.num_days_from_ce()), Some(MAX));
|
||||||
|
assert_eq!(from_ndays_from_ce(MAX.num_days_from_ce() + 1), None);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date_fields() {
|
fn test_date_fields() {
|
||||||
fn check(year: i32, month: u32, day: u32, ordinal: u32) {
|
fn check(year: i32, month: u32, day: u32, ordinal: u32) {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use num::Integer;
|
||||||
|
|
||||||
use {Weekday, Timelike, Datelike};
|
use {Weekday, Timelike, Datelike};
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
|
@ -28,6 +29,34 @@ impl NaiveDateTime {
|
||||||
NaiveDateTime { date: date, time: time }
|
NaiveDateTime { date: date, time: time }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a new `NaiveDateTime` from the number of non-leap seconds
|
||||||
|
/// since January 1, 1970 0:00:00 UTC and the number of nanoseconds
|
||||||
|
/// since the last whole non-leap second.
|
||||||
|
///
|
||||||
|
/// Fails on the out-of-range number of seconds and/or invalid nanosecond.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_num_seconds_from_unix_epoch(secs: i64, nsecs: u32) -> NaiveDateTime {
|
||||||
|
let datetime = NaiveDateTime::from_num_seconds_from_unix_epoch_opt(secs, nsecs);
|
||||||
|
datetime.expect("invalid or out-of-range datetime")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes a new `NaiveDateTime` from the number of non-leap seconds
|
||||||
|
/// since January 1, 1970 0:00:00 UTC and the number of nanoseconds
|
||||||
|
/// since the last whole non-leap second.
|
||||||
|
///
|
||||||
|
/// Returns `None` on the out-of-range number of seconds and/or invalid nanosecond.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_num_seconds_from_unix_epoch_opt(secs: i64, nsecs: u32) -> Option<NaiveDateTime> {
|
||||||
|
let (days, secs) = secs.div_mod_floor(&86400);
|
||||||
|
let date = days.to_i32().and_then(|days| days.checked_add(&719163))
|
||||||
|
.and_then(|days_ce| NaiveDate::from_num_days_from_ce_opt(days_ce));
|
||||||
|
let time = NaiveTime::from_num_seconds_from_midnight_opt(secs as u32, nsecs);
|
||||||
|
match (date, time) {
|
||||||
|
(Some(date), Some(time)) => Some(NaiveDateTime { date: date, time: time }),
|
||||||
|
(_, _) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieves a date component.
|
/// Retrieves a date component.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn date(&self) -> NaiveDate {
|
pub fn date(&self) -> NaiveDate {
|
||||||
|
@ -161,8 +190,23 @@ impl fmt::Show for NaiveDateTime {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use super::NaiveDateTime;
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
use naive::date::NaiveDate;
|
use naive::date::NaiveDate;
|
||||||
|
use std::i64;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_datetime_from_num_seconds_from_unix_epoch() {
|
||||||
|
let from_timestamp = |secs| NaiveDateTime::from_num_seconds_from_unix_epoch_opt(secs, 0);
|
||||||
|
let ymdhms = |y,m,d,h,n,s| NaiveDate::from_ymd(y,m,d).and_hms(h,n,s);
|
||||||
|
assert_eq!(from_timestamp(-1), Some(ymdhms(1969, 12, 31, 23, 59, 59)));
|
||||||
|
assert_eq!(from_timestamp(0), Some(ymdhms(1970, 1, 1, 0, 0, 0)));
|
||||||
|
assert_eq!(from_timestamp(1), Some(ymdhms(1970, 1, 1, 0, 0, 1)));
|
||||||
|
assert_eq!(from_timestamp(1_000_000_000), Some(ymdhms(2001, 9, 9, 1, 46, 40)));
|
||||||
|
assert_eq!(from_timestamp(0x7fffffff), Some(ymdhms(2038, 1, 19, 3, 14, 7)));
|
||||||
|
assert_eq!(from_timestamp(i64::MIN), None);
|
||||||
|
assert_eq!(from_timestamp(i64::MAX), None);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_datetime_add() {
|
fn test_datetime_add() {
|
||||||
|
|
|
@ -89,12 +89,32 @@ impl NaiveTime {
|
||||||
/// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second.
|
/// 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.
|
/// Returns `None` on invalid hour, minute, second and/or nanosecond.
|
||||||
|
#[inline]
|
||||||
pub fn from_hms_nano_opt(hour: u32, min: u32, sec: u32, nano: u32) -> Option<NaiveTime> {
|
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; }
|
if hour >= 24 || min >= 60 || sec >= 60 || nano >= 2_000_000_000 { return None; }
|
||||||
let secs = hour * 3600 + min * 60 + sec;
|
let secs = hour * 3600 + min * 60 + sec;
|
||||||
Some(NaiveTime { secs: secs, frac: nano })
|
Some(NaiveTime { secs: secs, frac: nano })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes a new `NaiveTime` from the number of seconds since midnight and nanosecond.
|
||||||
|
/// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second.
|
||||||
|
///
|
||||||
|
/// Fails on invalid number of seconds and/or nanosecond.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_num_seconds_from_midnight(secs: u32, nano: u32) -> NaiveTime {
|
||||||
|
NaiveTime::from_num_seconds_from_midnight_opt(secs, nano).expect("invalid time")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes a new `NaiveTime` from the number of seconds since midnight and nanosecond.
|
||||||
|
/// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second.
|
||||||
|
///
|
||||||
|
/// Returns `None` on invalid number of seconds and/or nanosecond.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_num_seconds_from_midnight_opt(secs: u32, nano: u32) -> Option<NaiveTime> {
|
||||||
|
if secs >= 86400 || nano >= 2_000_000_000 { return None; }
|
||||||
|
Some(NaiveTime { secs: secs, frac: nano })
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a triple of the hour, minute and second numbers.
|
/// Returns a triple of the hour, minute and second numbers.
|
||||||
fn hms(&self) -> (u32, u32, u32) {
|
fn hms(&self) -> (u32, u32, u32) {
|
||||||
let (mins, sec) = self.secs.div_mod_floor(&60);
|
let (mins, sec) = self.secs.div_mod_floor(&60);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use stdtime;
|
||||||
use num::Integer;
|
use num::Integer;
|
||||||
|
|
||||||
use Weekday;
|
use Weekday;
|
||||||
|
@ -239,6 +240,18 @@ pub trait Offset: Clone + fmt::Show {
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
pub struct UTC;
|
pub struct UTC;
|
||||||
|
|
||||||
|
impl UTC {
|
||||||
|
/// Returns a `Date` which corresponds to the current date.
|
||||||
|
pub fn today() -> Date<UTC> { UTC::now().date() }
|
||||||
|
|
||||||
|
/// Returns a `DateTime` which corresponds to the current date.
|
||||||
|
pub fn now() -> DateTime<UTC> {
|
||||||
|
let spec = stdtime::get_time();
|
||||||
|
let naive = NaiveDateTime::from_num_seconds_from_unix_epoch(spec.sec, spec.nsec as u32);
|
||||||
|
DateTime::from_utc(naive, UTC)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Offset for UTC {
|
impl Offset for UTC {
|
||||||
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))
|
||||||
|
|
Loading…
Reference in New Issue