From bd69769dc7a80dd8f15fc75c53b022324f543442 Mon Sep 17 00:00:00 2001
From: pbzweihander <pbzweihander@protonmail.com>
Date: Mon, 25 Mar 2024 10:49:31 +0900
Subject: [PATCH 1/2] Add time crate support

---
 influxdb/Cargo.toml       |  1 +
 influxdb/src/query/mod.rs | 53 +++++++++++++++++++++------------------
 2 files changed, 29 insertions(+), 25 deletions(-)

diff --git a/influxdb/Cargo.toml b/influxdb/Cargo.toml
index fec3c09..ffca9ae 100644
--- a/influxdb/Cargo.toml
+++ b/influxdb/Cargo.toml
@@ -24,6 +24,7 @@ serde = { version = "1.0.186", optional = true }
 serde_derive = { version = "1.0.186", optional = true }
 serde_json = { version = "1.0.48", optional = true }
 thiserror = "1.0"
+time = "0.3.34"
 
 [features]
 default = ["serde", "reqwest-client-rustls"]
diff --git a/influxdb/src/query/mod.rs b/influxdb/src/query/mod.rs
index 02163c7..0dcdf49 100644
--- a/influxdb/src/query/mod.rs
+++ b/influxdb/src/query/mod.rs
@@ -21,7 +21,6 @@
 //! ```
 
 use chrono::prelude::{DateTime, TimeZone, Utc};
-use std::convert::TryInto;
 
 pub mod consts;
 mod line_proto_term;
@@ -47,6 +46,21 @@ pub enum Timestamp {
     Hours(u128),
 }
 
+impl Timestamp {
+    pub fn nanos(&self) -> u128 {
+        match self {
+            Timestamp::Hours(h) => {
+                h * MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MILLIS_PER_SECOND * NANOS_PER_MILLI
+            }
+            Timestamp::Minutes(m) => m * SECONDS_PER_MINUTE * MILLIS_PER_SECOND * NANOS_PER_MILLI,
+            Timestamp::Seconds(s) => s * MILLIS_PER_SECOND * NANOS_PER_MILLI,
+            Timestamp::Milliseconds(millis) => millis * NANOS_PER_MILLI,
+            Timestamp::Microseconds(micros) => micros * NANOS_PER_MICRO,
+            Timestamp::Nanoseconds(nanos) => *nanos,
+        }
+    }
+}
+
 impl fmt::Display for Timestamp {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use Timestamp::*;
@@ -59,30 +73,7 @@ impl fmt::Display for Timestamp {
 
 impl From<Timestamp> for DateTime<Utc> {
     fn from(ts: Timestamp) -> DateTime<Utc> {
-        match ts {
-            Timestamp::Hours(h) => {
-                let nanos =
-                    h * MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MILLIS_PER_SECOND * NANOS_PER_MILLI;
-                Utc.timestamp_nanos(nanos.try_into().unwrap())
-            }
-            Timestamp::Minutes(m) => {
-                let nanos = m * SECONDS_PER_MINUTE * MILLIS_PER_SECOND * NANOS_PER_MILLI;
-                Utc.timestamp_nanos(nanos.try_into().unwrap())
-            }
-            Timestamp::Seconds(s) => {
-                let nanos = s * MILLIS_PER_SECOND * NANOS_PER_MILLI;
-                Utc.timestamp_nanos(nanos.try_into().unwrap())
-            }
-            Timestamp::Milliseconds(millis) => {
-                let nanos = millis * NANOS_PER_MILLI;
-                Utc.timestamp_nanos(nanos.try_into().unwrap())
-            }
-            Timestamp::Nanoseconds(nanos) => Utc.timestamp_nanos(nanos.try_into().unwrap()),
-            Timestamp::Microseconds(micros) => {
-                let nanos = micros * NANOS_PER_MICRO;
-                Utc.timestamp_nanos(nanos.try_into().unwrap())
-            }
-        }
+        Utc.timestamp_nanos(ts.nanos() as i64)
     }
 }
 
@@ -95,6 +86,18 @@ where
     }
 }
 
+impl From<Timestamp> for time::OffsetDateTime {
+    fn from(value: Timestamp) -> Self {
+        time::OffsetDateTime::from_unix_timestamp_nanos(value.nanos() as i128).unwrap()
+    }
+}
+
+impl From<time::OffsetDateTime> for Timestamp {
+    fn from(value: time::OffsetDateTime) -> Self {
+        Timestamp::Nanoseconds(value.unix_timestamp_nanos() as u128)
+    }
+}
+
 pub trait Query {
     /// Builds valid InfluxSQL which can be run against the Database.
     /// In case no fields have been specified, it will return an error,

From 945867d6b2559bc5687caf268c19198cb48eb905 Mon Sep 17 00:00:00 2001
From: pbzweihander <pbzweihander@protonmail.com>
Date: Fri, 29 Mar 2024 16:41:52 +0900
Subject: [PATCH 2/2] Make time and chrono optional

---
 .github/workflows/rust.yml |  8 ++++----
 influxdb/Cargo.toml        | 10 +++++++---
 influxdb/src/query/mod.rs  | 34 +++++++++++++++++++++++++---------
 3 files changed, 36 insertions(+), 16 deletions(-)

diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 1e44302..9bf0234 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -28,9 +28,9 @@ jobs:
         with:
           components: clippy
       - name: Check Clippy lints (reqwest)
-        run: cargo clippy --manifest-path influxdb/Cargo.toml --all-targets --no-default-features --features serde,derive,reqwest-client-rustls -- -D warnings
+        run: cargo clippy --manifest-path influxdb/Cargo.toml --all-targets --no-default-features --features chrono,time,serde,derive,reqwest-client-rustls -- -D warnings
       - name: Check Clippy lints (surf)
-        run: cargo clippy --manifest-path influxdb/Cargo.toml --all-targets --no-default-features --features serde,derive,hyper-client -- -D warnings
+        run: cargo clippy --manifest-path influxdb/Cargo.toml --all-targets --no-default-features --features chrono,time,serde,derive,hyper-client -- -D warnings
 
   # this checks that the code is formatted with rustfmt
   rustfmt:
@@ -145,7 +145,7 @@ jobs:
         run: |
           for test in integration_tests{,_v2}
           do
-            cargo test -p influxdb --no-default-features --features 'serde derive ${{matrix.http-backend}}' --no-fail-fast --test $test
+            cargo test -p influxdb --no-default-features --features 'chrono time serde derive ${{matrix.http-backend}}' --no-fail-fast --test $test
           done
 
   # this uses cargo-tarpaulin to inspect the code coverage
@@ -192,7 +192,7 @@ jobs:
           cargo tarpaulin -v \
             --target-dir target/tarpaulin \
             --workspace \
-            --features serde,derive \
+            --features chrono,time,serde,derive \
             --exclude-files 'derive/*' \
             --exclude-files 'target/*' \
             --ignore-panics --ignore-tests \
diff --git a/influxdb/Cargo.toml b/influxdb/Cargo.toml
index ffca9ae..6202960 100644
--- a/influxdb/Cargo.toml
+++ b/influxdb/Cargo.toml
@@ -13,18 +13,18 @@ include = ["src/**/*", "tests/**/*", "Cargo.toml", "LICENSE"]
 repository = "https://github.com/influxdb-rs/influxdb-rust"
 
 [dependencies]
-chrono = { version = "0.4.23", features = ["serde"], default-features = false }
+chrono = { version = "0.4.23", features = ["serde"], default-features = false, optional = true }
 futures-util = "0.3.17"
 http = "0.2.4"
 influxdb_derive = { version = "0.5.1", optional = true }
 lazy-regex = "3.1"
 reqwest = { version = "0.11.4", default-features = false, optional = true }
-surf = { version = "2.2.0", default-features = false, optional = true }
 serde = { version = "1.0.186", optional = true }
 serde_derive = { version = "1.0.186", optional = true }
 serde_json = { version = "1.0.48", optional = true }
+surf = { version = "2.2.0", default-features = false, optional = true }
 thiserror = "1.0"
-time = "0.3.34"
+time = { version = "0.3.34", optional = true }
 
 [features]
 default = ["serde", "reqwest-client-rustls"]
@@ -41,6 +41,10 @@ reqwest-client-native-tls = ["reqwest", "reqwest/native-tls-alpn"]
 reqwest-client-native-tls-vendored = ["reqwest", "reqwest/native-tls-vendored"]
 wasm-client = ["surf", "surf/wasm-client"]
 
+# etc
+time = ["dep:time"]
+chrono = ["dep:chrono"]
+
 [dev-dependencies]
 async-std = { version = "1.6.5", features = ["attributes", "tokio02", "tokio1"] }
 indoc = "1.0"
diff --git a/influxdb/src/query/mod.rs b/influxdb/src/query/mod.rs
index 0dcdf49..9ef1c9b 100644
--- a/influxdb/src/query/mod.rs
+++ b/influxdb/src/query/mod.rs
@@ -20,8 +20,6 @@
 //! assert!(read_query.is_ok());
 //! ```
 
-use chrono::prelude::{DateTime, TimeZone, Utc};
-
 pub mod consts;
 mod line_proto_term;
 pub mod read_query;
@@ -71,27 +69,32 @@ impl fmt::Display for Timestamp {
     }
 }
 
-impl From<Timestamp> for DateTime<Utc> {
-    fn from(ts: Timestamp) -> DateTime<Utc> {
-        Utc.timestamp_nanos(ts.nanos() as i64)
+#[cfg(feature = "chrono")]
+impl From<Timestamp> for chrono::prelude::DateTime<chrono::prelude::Utc> {
+    fn from(ts: Timestamp) -> chrono::prelude::DateTime<chrono::prelude::Utc> {
+        use chrono::prelude::TimeZone;
+        chrono::prelude::Utc.timestamp_nanos(ts.nanos() as i64)
     }
 }
 
-impl<T> From<DateTime<T>> for Timestamp
+#[cfg(feature = "chrono")]
+impl<T> From<chrono::prelude::DateTime<T>> for Timestamp
 where
-    T: TimeZone,
+    T: chrono::prelude::TimeZone,
 {
-    fn from(date_time: DateTime<T>) -> Self {
+    fn from(date_time: chrono::prelude::DateTime<T>) -> Self {
         Timestamp::Nanoseconds(date_time.timestamp_nanos_opt().unwrap() as u128)
     }
 }
 
+#[cfg(feature = "time")]
 impl From<Timestamp> for time::OffsetDateTime {
     fn from(value: Timestamp) -> Self {
         time::OffsetDateTime::from_unix_timestamp_nanos(value.nanos() as i128).unwrap()
     }
 }
 
+#[cfg(feature = "time")]
 impl From<time::OffsetDateTime> for Timestamp {
     fn from(value: time::OffsetDateTime) -> Self {
         Timestamp::Nanoseconds(value.unix_timestamp_nanos() as u128)
@@ -238,7 +241,6 @@ mod tests {
         MILLIS_PER_SECOND, MINUTES_PER_HOUR, NANOS_PER_MICRO, NANOS_PER_MILLI, SECONDS_PER_MINUTE,
     };
     use crate::query::{Timestamp, ValidQuery};
-    use chrono::prelude::{DateTime, TimeZone, Utc};
     use std::convert::TryInto;
     #[test]
     fn test_equality_str() {
@@ -255,8 +257,10 @@ mod tests {
     fn test_format_for_timestamp_else() {
         assert!(format!("{}", Timestamp::Nanoseconds(100)) == "100");
     }
+    #[cfg(feature = "chrono")]
     #[test]
     fn test_chrono_datetime_from_timestamp_hours() {
+        use chrono::prelude::*;
         let datetime_from_timestamp: DateTime<Utc> = Timestamp::Hours(2).into();
         assert_eq!(
             Utc.timestamp_nanos(
@@ -267,8 +271,10 @@ mod tests {
             datetime_from_timestamp
         )
     }
+    #[cfg(feature = "chrono")]
     #[test]
     fn test_chrono_datetime_from_timestamp_minutes() {
+        use chrono::prelude::*;
         let datetime_from_timestamp: DateTime<Utc> = Timestamp::Minutes(2).into();
         assert_eq!(
             Utc.timestamp_nanos(
@@ -279,8 +285,10 @@ mod tests {
             datetime_from_timestamp
         )
     }
+    #[cfg(feature = "chrono")]
     #[test]
     fn test_chrono_datetime_from_timestamp_seconds() {
+        use chrono::prelude::*;
         let datetime_from_timestamp: DateTime<Utc> = Timestamp::Seconds(2).into();
         assert_eq!(
             Utc.timestamp_nanos(
@@ -291,29 +299,37 @@ mod tests {
             datetime_from_timestamp
         )
     }
+    #[cfg(feature = "chrono")]
     #[test]
     fn test_chrono_datetime_from_timestamp_millis() {
+        use chrono::prelude::*;
         let datetime_from_timestamp: DateTime<Utc> = Timestamp::Milliseconds(2).into();
         assert_eq!(
             Utc.timestamp_nanos((2 * NANOS_PER_MILLI).try_into().unwrap()),
             datetime_from_timestamp
         )
     }
+    #[cfg(feature = "chrono")]
     #[test]
     fn test_chrono_datetime_from_timestamp_nanos() {
+        use chrono::prelude::*;
         let datetime_from_timestamp: DateTime<Utc> = Timestamp::Nanoseconds(1).into();
         assert_eq!(Utc.timestamp_nanos(1), datetime_from_timestamp)
     }
+    #[cfg(feature = "chrono")]
     #[test]
     fn test_chrono_datetime_from_timestamp_micros() {
+        use chrono::prelude::*;
         let datetime_from_timestamp: DateTime<Utc> = Timestamp::Microseconds(2).into();
         assert_eq!(
             Utc.timestamp_nanos((2 * NANOS_PER_MICRO).try_into().unwrap()),
             datetime_from_timestamp
         )
     }
+    #[cfg(feature = "chrono")]
     #[test]
     fn test_timestamp_from_chrono_date() {
+        use chrono::prelude::*;
         let timestamp_from_datetime: Timestamp = Utc
             .with_ymd_and_hms(1970, 1, 1, 0, 0, 1)
             .single()