Added `From` implementations between `SystemTime` and `DateTime`.

Due to the obvious lack of time zone information in `SystemTime`,
`SystemTime` can only be converted to `DateTime<Utc>` (in UTC) or
`DateTime<Local>` (in the local time zone), while any `DateTime<Tz>`
can be converted to `SystemTime`.
This commit is contained in:
Kang Seonghoon 2017-06-22 01:48:06 +09:00
parent 8ea2d3f236
commit 136302cc04
No known key found for this signature in database
GPG Key ID: 82440FABA6709020
1 changed files with 67 additions and 0 deletions

View File

@ -8,6 +8,7 @@ use std::cmp::Ordering;
use std::ops::{Add, Sub};
#[cfg(feature = "rustc-serialize")]
use std::ops::Deref;
use std::time::{SystemTime, UNIX_EPOCH};
use oldtime::Duration as OldDuration;
use {Weekday, Timelike, Datelike};
@ -421,6 +422,45 @@ impl str::FromStr for DateTime<Local> {
}
}
impl From<SystemTime> for DateTime<Utc> {
fn from(t: SystemTime) -> DateTime<Utc> {
let (sec, nsec) = match t.duration_since(UNIX_EPOCH) {
Ok(dur) => (dur.as_secs() as i64, dur.subsec_nanos()),
Err(e) => { // unlikely but should be handled
let dur = e.duration();
let (sec, nsec) = (dur.as_secs() as i64, dur.subsec_nanos());
if nsec == 0 {
(-sec, 0)
} else {
(-sec - 1, 1_000_000_000 - nsec)
}
},
};
Utc.timestamp(sec, nsec)
}
}
impl From<SystemTime> for DateTime<Local> {
fn from(t: SystemTime) -> DateTime<Local> {
DateTime::<Utc>::from(t).with_timezone(&Local)
}
}
impl<Tz: TimeZone> From<DateTime<Tz>> for SystemTime {
fn from(dt: DateTime<Tz>) -> SystemTime {
use std::time::Duration;
let sec = dt.timestamp();
let nsec = dt.timestamp_subsec_nanos();
if sec < 0 {
// unlikely but should be handled
UNIX_EPOCH - Duration::new(-sec as u64, 0) + Duration::new(0, nsec)
} else {
UNIX_EPOCH + Duration::new(sec as u64, nsec)
}
}
}
#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
fn test_encodable_json<FUtc, FFixed, E>(to_string_utc: FUtc, to_string_fixed: FFixed)
where FUtc: Fn(&DateTime<Utc>) -> Result<String, E>,
@ -875,6 +915,7 @@ mod tests {
use naive::{NaiveTime, NaiveDate};
use offset::{TimeZone, Utc, Local, FixedOffset};
use oldtime::Duration;
use std::time::{SystemTime, UNIX_EPOCH};
#[test]
#[allow(non_snake_case)]
@ -1044,4 +1085,30 @@ mod tests {
assert_eq!(1234, datetime.timestamp_subsec_micros());
assert_eq!(1234567, datetime.timestamp_subsec_nanos());
}
#[test]
fn test_from_system_time() {
use std::time::Duration;
let epoch = Utc.ymd(1970, 1, 1).and_hms(0, 0, 0);
// SystemTime -> DateTime<Utc>
assert_eq!(DateTime::<Utc>::from(UNIX_EPOCH), epoch);
assert_eq!(DateTime::<Utc>::from(UNIX_EPOCH + Duration::new(999_999_999, 999_999_999)),
Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, 999_999_999));
assert_eq!(DateTime::<Utc>::from(UNIX_EPOCH - Duration::new(999_999_999, 999_999_999)),
Utc.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1));
// DateTime<Utc> -> SystemTime
assert_eq!(SystemTime::from(epoch), UNIX_EPOCH);
assert_eq!(SystemTime::from(Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, 999_999_999)),
UNIX_EPOCH + Duration::new(999_999_999, 999_999_999));
assert_eq!(SystemTime::from(Utc.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1)),
UNIX_EPOCH - Duration::new(999_999_999, 999_999_999));
// DateTime<any tz> -> SystemTime (via `with_timezone`)
assert_eq!(SystemTime::from(epoch.with_timezone(&Local)), UNIX_EPOCH);
assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400))), UNIX_EPOCH);
assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800))), UNIX_EPOCH);
}
}