use chrono::{DateTime, Duration, Utc};
const TIME_THRESHOLD: f64 = 268_435_456.0;
pub fn convert_senml_time(seconds: f64, now: DateTime<Utc>) -> Option<DateTime<Utc>> {
if !seconds.is_finite() {
return None;
}
let whole_seconds = seconds.trunc() as i64;
let frac_seconds = seconds.fract();
let nanoseconds = if frac_seconds != 0.0 {
(seconds.fract() * 1_000_000_000_f64).trunc() as i64
} else {
0_i64
};
if seconds >= TIME_THRESHOLD {
return DateTime::<Utc>::from_timestamp(whole_seconds, nanoseconds as u32);
}
Some(now + Duration::seconds(whole_seconds) + Duration::nanoseconds(nanoseconds))
}
pub fn datetime_to_timestamp(datetime: &DateTime<Utc>) -> (i64, Option<f64>) {
let timestamp = datetime.timestamp();
let nanos = datetime.timestamp_subsec_nanos();
if nanos > 0 {
let nanos = nanos as f64 / 1_000_000_000f64; (timestamp, Some(timestamp as f64 + nanos))
} else {
(timestamp, None)
}
}
#[cfg(test)]
mod tests {
use super::convert_senml_time;
use chrono::{DateTime, Utc};
#[test]
fn test_absolute_time() {
let time = 1320078429;
let expected = DateTime::<Utc>::from_timestamp(time, 0);
let result = convert_senml_time(time as f64, Utc::now());
assert!(result.is_some());
assert_eq!(result.unwrap(), expected.unwrap());
}
#[test]
fn test_absolute_subseconds_time() {
let time = 1_234_567_890.123_456_7_f64;
let expected = DateTime::<Utc>::from_timestamp(1234567890, 123456716);
let result = convert_senml_time(time, Utc::now());
assert!(result.is_some());
assert_eq!(result.unwrap(), expected.unwrap());
}
#[test]
fn test_relative_time() {
let time = 10;
let now = DateTime::<Utc>::from_timestamp(10_0000, 0).unwrap();
let expected = now + chrono::Duration::seconds(time);
let result = convert_senml_time(time as f64, now);
assert!(result.is_some());
assert_eq!(result.unwrap(), expected);
}
#[test]
fn test_negative_relative_time() {
let time = -10;
let now = Utc::now();
let expected = now - chrono::Duration::seconds(-time);
let result = convert_senml_time(time as f64, now);
assert!(result.is_some());
assert_eq!(result.unwrap(), expected);
}
#[test]
fn test_relative_subseconds_time() {
let time = -10.1234567890f64;
let now = DateTime::<Utc>::from_timestamp(10_0000, 0).unwrap();
let expected =
now - chrono::Duration::seconds(10) - chrono::Duration::nanoseconds(123456789);
let result = convert_senml_time(time, now);
assert!(result.is_some());
assert_eq!(result.unwrap(), expected);
}
#[test]
fn test_datetime_to_timestamp() {
let datetime = DateTime::<Utc>::from_timestamp(1234567890, 123456789).unwrap();
let result = super::datetime_to_timestamp(&datetime);
let (timestamp, precise_timestamp) = result;
assert_eq!(timestamp, 1234567890);
assert_eq!(precise_timestamp, Some(timestamp as f64 + 0.1234567890f64));
let result = convert_senml_time(1_234_567_890.123_456_7, Utc::now());
let unprecise_datetime = DateTime::<Utc>::from_timestamp(1234567890, 123456716).unwrap();
assert_eq!(result.unwrap(), unprecise_datetime);
}
}