Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chrono types for Timestamp #41

Merged
merged 14 commits into from
Oct 31, 2019
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ tokio = "0.1.20"
failure = "0.1.5"
serde = { version = "1.0.92", optional = true }
serde_json = { version = "1.0", optional = true }
chrono = { version = "0.4.9", optional = true }

[dev-dependencies]
chrono = { version = "0.4.9" }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you always enable the chrono feature in test by all those any(test, feature = "chrono_timestamp")? We test with cargo test --all-features so I guess it's fine to only enable the test when the feature is enabled

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
chrono = { version = "0.4.9" }

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@durangatan this one and we're ready to merge ;)


[features]
use-serde = ["serde", "serde_json"]
chrono_timestamps = ["chrono"]
default = ["use-serde"]
109 changes: 108 additions & 1 deletion src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,21 @@
//! assert!(read_query.is_ok());
//! ```

#[cfg(any(test, feature = "chrono_timestamps"))]
extern crate chrono;
#[cfg(any(test, feature = "chrono_timestamps"))]
use chrono::prelude::{DateTime, TimeZone, Utc};
#[cfg(any(test, feature = "chrono_timestamps"))]
use std::convert::TryInto;

pub mod read_query;
pub mod write_query;

use std::fmt;

use crate::{Error, ReadQuery, WriteQuery};

#[derive(PartialEq)]
#[derive(PartialEq, Debug)]
pub enum Timestamp {
Now,
Nanoseconds(usize),
Expand All @@ -48,6 +55,43 @@ impl fmt::Display for Timestamp {
}
}

#[cfg(any(test, feature = "chrono_timestamps"))]
impl Into<DateTime<Utc>> for Timestamp {
fn into(self) -> DateTime<Utc> {
match self {
Timestamp::Now => Utc::now(),
Timestamp::Hours(h) => {
let millis = h * 60 * 60 * 1000;
Utc.timestamp_millis(millis.try_into().unwrap())
}
Timestamp::Minutes(m) => {
let millis = m * 60 * 1000;
Utc.timestamp_millis(millis.try_into().unwrap())
}
Timestamp::Seconds(m) => {
let millis = m * 1000;
Utc.timestamp_millis(millis.try_into().unwrap())
}
Timestamp::Milliseconds(millis) => Utc.timestamp_millis(millis.try_into().unwrap()),
Timestamp::Nanoseconds(ns) => Utc.timestamp_nanos(ns.try_into().unwrap()),
Timestamp::Microseconds(mis) => {
let nanos = mis / 10000;
Utc.timestamp_nanos(nanos.try_into().unwrap())
}
}
}
}

#[cfg(any(test, feature = "chrono_timestamps"))]
impl<T> From<DateTime<T>> for Timestamp
where
T: TimeZone,
{
fn from(date_time: DateTime<T>) -> Self {
Timestamp::Milliseconds(date_time.timestamp_millis() as usize)
}
}

/// Internal enum used to represent either type of query.
pub enum QueryTypes<'a> {
Read(&'a ReadQuery),
Expand Down Expand Up @@ -157,7 +201,14 @@ pub enum QueryType {

#[cfg(test)]
mod tests {
extern crate chrono;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be feature-gated (see above)

use crate::query::{Timestamp, ValidQuery};
use chrono::prelude::{DateTime, TimeZone, Utc};

const MINUTES_PER_HOUR: i64 = 60;
const SECONDS_PER_MINUTE: i64 = 60;
const MILLIS_PER_SECOND: i64 = 1000;
const MICROS_PER_NANO: i64 = 1000;

#[test]
fn test_equality_str() {
Expand All @@ -181,4 +232,60 @@ mod tests {
fn test_format_for_timestamp_else() {
assert!(format!("{}", Timestamp::Nanoseconds(100)) == "100");
}

#[test]
fn test_chrono_datetime_from_timestamp_now() {
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Now.into();
assert_eq!(Utc::now().date(), datetime_from_timestamp.date())
}
#[test]
fn test_chrono_datetime_from_timestamp_hours() {
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Hours(2).into();
assert_eq!(
Utc.timestamp_millis(2 * MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MILLIS_PER_SECOND),
datetime_from_timestamp
)
}
#[test]
fn test_chrono_datetime_from_timestamp_minutes() {
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Minutes(2).into();
assert_eq!(
Utc.timestamp_millis(2 * SECONDS_PER_MINUTE * MILLIS_PER_SECOND),
datetime_from_timestamp
)
}
#[test]
fn test_chrono_datetime_from_timestamp_seconds() {
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Seconds(2).into();
assert_eq!(
Utc.timestamp_millis(2 * MILLIS_PER_SECOND),
datetime_from_timestamp
)
}
#[test]
fn test_chrono_datetime_from_timestamp_millis() {
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Milliseconds(2).into();
assert_eq!(Utc.timestamp_millis(2), datetime_from_timestamp)
}

#[test]
fn test_chrono_datetime_from_timestamp_nanos() {
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Nanoseconds(1).into();
assert_eq!(Utc.timestamp_nanos(1), datetime_from_timestamp)
}

#[test]
fn test_chrono_datetime_from_timestamp_micros() {
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Microseconds(1).into();
assert_eq!(
Utc.timestamp_nanos(1 / MICROS_PER_NANO),
datetime_from_timestamp
)
}

#[test]
fn test_timestamp_from_chrono_date() {
let timestamp_from_datetime: Timestamp = Utc.ymd(1970, 1, 1).and_hms(0, 0, 1).into();
assert_eq!(Timestamp::Milliseconds(1000), timestamp_from_datetime)
}
}