131 lines
3.7 KiB
Rust
131 lines
3.7 KiB
Rust
|
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
|
||
|
// file at the top-level directory of this distribution.
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||
|
// option. This file may not be copied, modified, or distributed
|
||
|
// except according to those terms.
|
||
|
|
||
|
//! Core Foundation date objects.
|
||
|
|
||
|
pub use core_foundation_sys::date::*;
|
||
|
use core_foundation_sys::base::kCFAllocatorDefault;
|
||
|
|
||
|
use base::TCFType;
|
||
|
|
||
|
#[cfg(feature = "with-chrono")]
|
||
|
use chrono::NaiveDateTime;
|
||
|
|
||
|
|
||
|
declare_TCFType!{
|
||
|
/// A date.
|
||
|
CFDate, CFDateRef
|
||
|
}
|
||
|
impl_TCFType!(CFDate, CFDateRef, CFDateGetTypeID);
|
||
|
impl_CFTypeDescription!(CFDate);
|
||
|
impl_CFComparison!(CFDate, CFDateCompare);
|
||
|
|
||
|
impl CFDate {
|
||
|
#[inline]
|
||
|
pub fn new(time: CFAbsoluteTime) -> CFDate {
|
||
|
unsafe {
|
||
|
let date_ref = CFDateCreate(kCFAllocatorDefault, time);
|
||
|
TCFType::wrap_under_create_rule(date_ref)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[inline]
|
||
|
pub fn now() -> CFDate {
|
||
|
CFDate::new(unsafe { CFAbsoluteTimeGetCurrent() })
|
||
|
}
|
||
|
|
||
|
#[inline]
|
||
|
pub fn abs_time(&self) -> CFAbsoluteTime {
|
||
|
unsafe {
|
||
|
CFDateGetAbsoluteTime(self.0)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[cfg(feature = "with-chrono")]
|
||
|
pub fn naive_utc(&self) -> NaiveDateTime {
|
||
|
let ts = unsafe {
|
||
|
self.abs_time() + kCFAbsoluteTimeIntervalSince1970
|
||
|
};
|
||
|
let (secs, nanos) = if ts.is_sign_positive() {
|
||
|
(ts.trunc() as i64, ts.fract())
|
||
|
} else {
|
||
|
// nanoseconds can't be negative in NaiveDateTime
|
||
|
(ts.trunc() as i64 - 1, 1.0 - ts.fract().abs())
|
||
|
};
|
||
|
NaiveDateTime::from_timestamp(secs, (nanos * 1e9).floor() as u32)
|
||
|
}
|
||
|
|
||
|
#[cfg(feature = "with-chrono")]
|
||
|
pub fn from_naive_utc(time: NaiveDateTime) -> CFDate {
|
||
|
let secs = time.timestamp();
|
||
|
let nanos = time.timestamp_subsec_nanos();
|
||
|
let ts = unsafe {
|
||
|
secs as f64 + (nanos as f64 / 1e9) - kCFAbsoluteTimeIntervalSince1970
|
||
|
};
|
||
|
CFDate::new(ts)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[cfg(test)]
|
||
|
mod test {
|
||
|
use super::CFDate;
|
||
|
use std::cmp::Ordering;
|
||
|
|
||
|
#[cfg(feature = "with-chrono")]
|
||
|
use chrono::NaiveDateTime;
|
||
|
|
||
|
#[cfg(feature = "with-chrono")]
|
||
|
fn approx_eq(a: f64, b: f64) -> bool {
|
||
|
use std::f64;
|
||
|
|
||
|
let same_sign = a.is_sign_positive() == b.is_sign_positive();
|
||
|
let equal = ((a - b).abs() / f64::min(a.abs() + b.abs(), f64::MAX)) < f64::EPSILON;
|
||
|
(same_sign && equal)
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn date_comparison() {
|
||
|
let now = CFDate::now();
|
||
|
let past = CFDate::new(now.abs_time() - 1.0);
|
||
|
assert_eq!(now.cmp(&past), Ordering::Greater);
|
||
|
assert_eq!(now.cmp(&now), Ordering::Equal);
|
||
|
assert_eq!(past.cmp(&now), Ordering::Less);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn date_equality() {
|
||
|
let now = CFDate::now();
|
||
|
let same_time = CFDate::new(now.abs_time());
|
||
|
assert_eq!(now, same_time);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
#[cfg(feature = "with-chrono")]
|
||
|
fn date_chrono_conversion_positive() {
|
||
|
let date = CFDate::now();
|
||
|
let datetime = date.naive_utc();
|
||
|
let converted = CFDate::from_naive_utc(datetime);
|
||
|
assert!(approx_eq(date.abs_time(), converted.abs_time()));
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
#[cfg(feature = "with-chrono")]
|
||
|
fn date_chrono_conversion_negative() {
|
||
|
use super::kCFAbsoluteTimeIntervalSince1970;
|
||
|
|
||
|
let ts = unsafe {
|
||
|
kCFAbsoluteTimeIntervalSince1970 - 420.0
|
||
|
};
|
||
|
let date = CFDate::new(ts);
|
||
|
let datetime: NaiveDateTime = date.naive_utc();
|
||
|
let converted = CFDate::from_naive_utc(datetime);
|
||
|
assert!(approx_eq(date.abs_time(), converted.abs_time()));
|
||
|
}
|
||
|
}
|