Skip to content

Commit 9174a4f

Browse files
pbzweihanderEmpty2k12msrd0
authored
Add time crate support for Timestamp (#151)
* Add time crate support * Make time and chrono optional * adapt ci script * more fixes * add missing variable * add PR template and regen README.md * bump MSRV to 1.67.1 due to time-core v0.1.4 * fix and simplify CI * simplify chrono "imports" * Add support for `time::UtcDateTime` This was not a thing at the time this PR was opened, but was added in time 0.3.38 * fix syntax error in CI --------- Co-authored-by: Gero Gerke <[email protected]> Co-authored-by: Dominic <[email protected]>
1 parent 4bb0580 commit 9174a4f

File tree

6 files changed

+90
-54
lines changed

6 files changed

+90
-54
lines changed

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
### Checklist
66
- [ ] Formatted code using `cargo fmt --all`
77
- [ ] Linted code using clippy
8-
- [ ] with reqwest feature: `cargo clippy --manifest-path influxdb/Cargo.toml --all-targets --no-default-features --features serde,derive,reqwest-client-rustls -- -D warnings`
9-
- [ ] with surf feature: `cargo clippy --manifest-path influxdb/Cargo.toml --all-targets --no-default-features --features serde,derive,hyper-client -- -D warnings`
8+
- [ ] with reqwest feature: `cargo clippy --manifest-path influxdb/Cargo.toml --all-targets --no-default-features --features chrono,time,serde,derive,reqwest-client-rustls -- -D warnings`
9+
- [ ] with surf feature: `cargo clippy --manifest-path influxdb/Cargo.toml --all-targets --no-default-features --features chrono,time,serde,derive,hyper-client -- -D warnings`
1010
- [ ] Updated README.md using `cargo doc2readme -p influxdb --expand-macros`
1111
- [ ] Reviewed the diff. Did you leave any print statements or unnecessary comments?
1212
- [ ] Any unfinished work that warrants a separate issue captured in an issue with a TODO code comment

.github/workflows/rust.yml

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ jobs:
3030
- name: Update Cargo.lock
3131
run: cargo --config 'resolver.incompatible-rust-versions="fallback"' update
3232
- name: Check Clippy lints (reqwest)
33-
run: cargo clippy --manifest-path influxdb/Cargo.toml --locked --all-targets --no-default-features --features serde,derive,reqwest-client-rustls -- -D warnings
33+
run: cargo clippy --manifest-path influxdb/Cargo.toml --locked --all-targets --no-default-features --features chrono,time,serde,derive,reqwest-client-rustls -- -D warnings
3434
- name: Check Clippy lints (surf)
35-
run: cargo clippy --manifest-path influxdb/Cargo.toml --locked --all-targets --no-default-features --features serde,derive,hyper-client -- -D warnings
35+
run: cargo clippy --manifest-path influxdb/Cargo.toml --locked --all-targets --no-default-features --features chrono,time,serde,derive,hyper-client -- -D warnings
3636

3737
# this checks that the code is formatted with rustfmt
3838
rustfmt:
@@ -108,8 +108,8 @@ jobs:
108108
key: "${{runner.os}} Rust ${{steps.msrv-toolchain.outputs.cachekey}}"
109109
if: matrix.rust.name == 'MSRV'
110110
# finally we can run tests
111-
- run: cargo test --lib --locked
112-
- run: cargo test --doc --locked
111+
- run: cargo test --lib --locked --features 'chrono time serde derive'
112+
- run: cargo test --doc --locked --features 'chrono time serde derive'
113113

114114
# this tests that all integration tests are successful
115115
integration_tests:
@@ -124,10 +124,6 @@ jobs:
124124
toolchain: stable
125125
nightly: false
126126
http-backend:
127-
- curl-client
128-
- h1-client
129-
- h1-client-rustls
130-
- hyper-client
131127
- reqwest-client-rustls
132128
- reqwest-client-native-tls
133129
- reqwest-client-native-tls-vendored
@@ -172,10 +168,12 @@ jobs:
172168
key: "${{runner.os}} Rust ${{steps.rust-toolchain.outputs.cachekey}}"
173169
- name: Run tests
174170
run: |
175-
for test in integration_tests{,_v2}
176-
do
177-
cargo test -p influxdb --no-default-features --features 'serde derive ${{matrix.http-backend}}' --no-fail-fast --test $test
178-
done
171+
cargo test -p influxdb \
172+
--no-default-features \
173+
--features "serde derive chrono time ${{matrix.http-backend}}" \
174+
--no-fail-fast \
175+
--test integration_tests \
176+
--test integration_tests_v2
179177
180178
# this uses cargo-tarpaulin to inspect the code coverage
181179
coverage:
@@ -221,7 +219,7 @@ jobs:
221219
cargo tarpaulin -v \
222220
--target-dir target/tarpaulin \
223221
--workspace \
224-
--features serde,derive \
222+
--features chrono,time,serde,derive \
225223
--exclude-files 'derive/*' \
226224
--exclude-files 'target/*' \
227225
--ignore-panics --ignore-tests \

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ resolver = "2"
77
[workspace.package]
88
authors = ["Gero Gerke <[email protected]>", "Dominic <[email protected]>"]
99
edition = "2018"
10-
rust-version = "1.65"
10+
rust-version = "1.67.1"
1111
license = "MIT"
1212
repository = "https://github.com/influxdb-rs/influxdb-rust"
1313

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
<a href="https://www.rust-lang.org/en-US/">
2626
<img src="https://img.shields.io/badge/Made%20with-Rust-orange.svg" alt='Build with Rust' />
2727
</a>
28-
<a href="https://github.com/rust-lang/rust/releases/tag/1.65.0">
29-
<img src="https://img.shields.io/badge/rustc-1.65.0+-yellow.svg" alt='Minimum Rust Version: 1.65.0' />
28+
<a href="https://github.com/rust-lang/rust/releases/tag/1.67.1">
29+
<img src="https://img.shields.io/badge/rustc-1.67.1+-yellow.svg" alt='Minimum Rust Version: 1.67.1' />
3030
</a>
3131
</p>
3232

@@ -155,7 +155,7 @@ To communicate with InfluxDB, you can choose the HTTP backend to be used configu
155155
@ 2020-2024 Gero Gerke, msrd0 and [contributors].
156156

157157
[contributors]: https://github.com/influxdb-rs/influxdb-rust/graphs/contributors
158-
[__cargo_doc2readme_dependencies_info]: ggGkYW0BYXSEGzJ_QpW55zB1G0S-TER-rIfLG2gXv8EYBG3jG1nuXXn-kdx-YXKEG1LaAVLASZMqG5J2qfpyCvbMG_Rohh5BobOmG0DqLv5454SZYWSBgmhpbmZsdXhkYmUwLjcuMg
158+
[__cargo_doc2readme_dependencies_info]: ggGkYW0CYXSEGzJ_QpW55zB1G0S-TER-rIfLG2gXv8EYBG3jG1nuXXn-kdx-YXKEG1LaAVLASZMqG5J2qfpyCvbMG_Rohh5BobOmG0DqLv5454SZYWSBgmhpbmZsdXhkYmUwLjcuMg
159159
[__link0]: https://github.com/influxdb-rs/influxdb-rust/blob/main/CONTRIBUTING.md
160160
[__link1]: https://github.com/influxdb-rs/influxdb-rust/blob/main/CODE_OF_CONDUCT.md
161161
[__link10]: https://github.com/alexcrichton/curl-rust

influxdb/Cargo.toml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,18 @@ repository.workspace = true
1717
workspace = true
1818

1919
[dependencies]
20-
chrono = { version = "0.4.23", features = ["serde"], default-features = false }
20+
chrono = { version = "0.4.23", features = ["serde"], default-features = false, optional = true }
2121
futures-util = "0.3.17"
2222
http = "0.2.4"
2323
influxdb_derive = { version = "0.5.1", optional = true }
2424
lazy-regex = "3.1"
2525
reqwest = { version = "0.11.4", default-features = false, optional = true }
26-
surf = { version = "2.2.0", default-features = false, optional = true }
2726
serde = { version = "1.0.186", optional = true }
2827
serde_derive = { version = "1.0.186", optional = true }
2928
serde_json = { version = "1.0.48", optional = true }
29+
surf = { version = "2.2.0", default-features = false, optional = true }
3030
thiserror = "1.0"
31+
time = { version = "0.3.39", optional = true }
3132

3233
[features]
3334
default = ["serde", "reqwest-client-rustls"]
@@ -44,6 +45,10 @@ reqwest-client-native-tls = ["reqwest", "reqwest/native-tls-alpn"]
4445
reqwest-client-native-tls-vendored = ["reqwest", "reqwest/native-tls-vendored"]
4546
wasm-client = ["surf", "surf/wasm-client"]
4647

48+
# etc
49+
time = ["dep:time"]
50+
chrono = ["dep:chrono"]
51+
4752
[dev-dependencies]
4853
async-std = { version = "1.6.5", features = ["attributes", "tokio02", "tokio1"] }
4954
indoc = "1.0"

influxdb/src/query/mod.rs

Lines changed: 66 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@
2020
//! assert!(read_query.is_ok());
2121
//! ```
2222
23-
use chrono::prelude::{DateTime, TimeZone, Utc};
24-
use std::convert::TryInto;
25-
2623
pub mod consts;
2724
mod line_proto_term;
2825
pub mod read_query;
@@ -47,6 +44,21 @@ pub enum Timestamp {
4744
Hours(u128),
4845
}
4946

47+
impl Timestamp {
48+
pub fn nanos(&self) -> u128 {
49+
match self {
50+
Timestamp::Hours(h) => {
51+
h * MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MILLIS_PER_SECOND * NANOS_PER_MILLI
52+
}
53+
Timestamp::Minutes(m) => m * SECONDS_PER_MINUTE * MILLIS_PER_SECOND * NANOS_PER_MILLI,
54+
Timestamp::Seconds(s) => s * MILLIS_PER_SECOND * NANOS_PER_MILLI,
55+
Timestamp::Milliseconds(millis) => millis * NANOS_PER_MILLI,
56+
Timestamp::Microseconds(micros) => micros * NANOS_PER_MICRO,
57+
Timestamp::Nanoseconds(nanos) => *nanos,
58+
}
59+
}
60+
}
61+
5062
impl fmt::Display for Timestamp {
5163
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5264
use Timestamp::*;
@@ -57,44 +69,52 @@ impl fmt::Display for Timestamp {
5769
}
5870
}
5971

60-
impl From<Timestamp> for DateTime<Utc> {
61-
fn from(ts: Timestamp) -> DateTime<Utc> {
62-
match ts {
63-
Timestamp::Hours(h) => {
64-
let nanos =
65-
h * MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MILLIS_PER_SECOND * NANOS_PER_MILLI;
66-
Utc.timestamp_nanos(nanos.try_into().unwrap())
67-
}
68-
Timestamp::Minutes(m) => {
69-
let nanos = m * SECONDS_PER_MINUTE * MILLIS_PER_SECOND * NANOS_PER_MILLI;
70-
Utc.timestamp_nanos(nanos.try_into().unwrap())
71-
}
72-
Timestamp::Seconds(s) => {
73-
let nanos = s * MILLIS_PER_SECOND * NANOS_PER_MILLI;
74-
Utc.timestamp_nanos(nanos.try_into().unwrap())
75-
}
76-
Timestamp::Milliseconds(millis) => {
77-
let nanos = millis * NANOS_PER_MILLI;
78-
Utc.timestamp_nanos(nanos.try_into().unwrap())
79-
}
80-
Timestamp::Nanoseconds(nanos) => Utc.timestamp_nanos(nanos.try_into().unwrap()),
81-
Timestamp::Microseconds(micros) => {
82-
let nanos = micros * NANOS_PER_MICRO;
83-
Utc.timestamp_nanos(nanos.try_into().unwrap())
84-
}
85-
}
72+
#[cfg(feature = "chrono")]
73+
impl From<Timestamp> for chrono::DateTime<chrono::Utc> {
74+
fn from(ts: Timestamp) -> chrono::DateTime<chrono::Utc> {
75+
use chrono::TimeZone as _;
76+
chrono::Utc.timestamp_nanos(ts.nanos() as i64)
8677
}
8778
}
8879

89-
impl<T> From<DateTime<T>> for Timestamp
80+
#[cfg(feature = "chrono")]
81+
impl<T> From<chrono::DateTime<T>> for Timestamp
9082
where
91-
T: TimeZone,
83+
T: chrono::TimeZone,
9284
{
93-
fn from(date_time: DateTime<T>) -> Self {
85+
fn from(date_time: chrono::DateTime<T>) -> Self {
9486
Timestamp::Nanoseconds(date_time.timestamp_nanos_opt().unwrap() as u128)
9587
}
9688
}
9789

90+
#[cfg(feature = "time")]
91+
impl From<Timestamp> for time::UtcDateTime {
92+
fn from(value: Timestamp) -> Self {
93+
time::UtcDateTime::from_unix_timestamp_nanos(value.nanos() as i128).unwrap()
94+
}
95+
}
96+
97+
#[cfg(feature = "time")]
98+
impl From<time::UtcDateTime> for Timestamp {
99+
fn from(value: time::UtcDateTime) -> Self {
100+
Timestamp::Nanoseconds(value.unix_timestamp_nanos() as u128)
101+
}
102+
}
103+
104+
#[cfg(feature = "time")]
105+
impl From<Timestamp> for time::OffsetDateTime {
106+
fn from(value: Timestamp) -> Self {
107+
time::OffsetDateTime::from_unix_timestamp_nanos(value.nanos() as i128).unwrap()
108+
}
109+
}
110+
111+
#[cfg(feature = "time")]
112+
impl From<time::OffsetDateTime> for Timestamp {
113+
fn from(value: time::OffsetDateTime) -> Self {
114+
Timestamp::Nanoseconds(value.unix_timestamp_nanos() as u128)
115+
}
116+
}
117+
98118
pub trait Query {
99119
/// Builds valid InfluxSQL which can be run against the Database.
100120
/// In case no fields have been specified, it will return an error,
@@ -235,7 +255,6 @@ mod tests {
235255
MILLIS_PER_SECOND, MINUTES_PER_HOUR, NANOS_PER_MICRO, NANOS_PER_MILLI, SECONDS_PER_MINUTE,
236256
};
237257
use crate::query::{Timestamp, ValidQuery};
238-
use chrono::prelude::{DateTime, TimeZone, Utc};
239258
use std::convert::TryInto;
240259
#[test]
241260
fn test_equality_str() {
@@ -252,8 +271,10 @@ mod tests {
252271
fn test_format_for_timestamp_else() {
253272
assert!(format!("{}", Timestamp::Nanoseconds(100)) == "100");
254273
}
274+
#[cfg(feature = "chrono")]
255275
#[test]
256276
fn test_chrono_datetime_from_timestamp_hours() {
277+
use chrono::prelude::*;
257278
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Hours(2).into();
258279
assert_eq!(
259280
Utc.timestamp_nanos(
@@ -264,8 +285,10 @@ mod tests {
264285
datetime_from_timestamp
265286
)
266287
}
288+
#[cfg(feature = "chrono")]
267289
#[test]
268290
fn test_chrono_datetime_from_timestamp_minutes() {
291+
use chrono::prelude::*;
269292
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Minutes(2).into();
270293
assert_eq!(
271294
Utc.timestamp_nanos(
@@ -276,8 +299,10 @@ mod tests {
276299
datetime_from_timestamp
277300
)
278301
}
302+
#[cfg(feature = "chrono")]
279303
#[test]
280304
fn test_chrono_datetime_from_timestamp_seconds() {
305+
use chrono::prelude::*;
281306
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Seconds(2).into();
282307
assert_eq!(
283308
Utc.timestamp_nanos(
@@ -288,29 +313,37 @@ mod tests {
288313
datetime_from_timestamp
289314
)
290315
}
316+
#[cfg(feature = "chrono")]
291317
#[test]
292318
fn test_chrono_datetime_from_timestamp_millis() {
319+
use chrono::prelude::*;
293320
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Milliseconds(2).into();
294321
assert_eq!(
295322
Utc.timestamp_nanos((2 * NANOS_PER_MILLI).try_into().unwrap()),
296323
datetime_from_timestamp
297324
)
298325
}
326+
#[cfg(feature = "chrono")]
299327
#[test]
300328
fn test_chrono_datetime_from_timestamp_nanos() {
329+
use chrono::prelude::*;
301330
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Nanoseconds(1).into();
302331
assert_eq!(Utc.timestamp_nanos(1), datetime_from_timestamp)
303332
}
333+
#[cfg(feature = "chrono")]
304334
#[test]
305335
fn test_chrono_datetime_from_timestamp_micros() {
336+
use chrono::prelude::*;
306337
let datetime_from_timestamp: DateTime<Utc> = Timestamp::Microseconds(2).into();
307338
assert_eq!(
308339
Utc.timestamp_nanos((2 * NANOS_PER_MICRO).try_into().unwrap()),
309340
datetime_from_timestamp
310341
)
311342
}
343+
#[cfg(feature = "chrono")]
312344
#[test]
313345
fn test_timestamp_from_chrono_date() {
346+
use chrono::prelude::*;
314347
let timestamp_from_datetime: Timestamp = Utc
315348
.with_ymd_and_hms(1970, 1, 1, 0, 0, 1)
316349
.single()

0 commit comments

Comments
 (0)