added constructors from timestamp; added `UTC::{today,now}`.

This commit is contained in:
Kang Seonghoon 2014-07-31 10:09:54 +09:00
parent 55d5d49f1c
commit 9d52c6d2f1
6 changed files with 136 additions and 4 deletions

View File

@ -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));

View File

@ -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};

View File

@ -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) {

View File

@ -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() {

View File

@ -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);

View File

@ -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))