Skip to content

Commit 45e0bdb

Browse files
committed
Use chrono instead of time.
1 parent d190391 commit 45e0bdb

File tree

5 files changed

+83
-103
lines changed

5 files changed

+83
-103
lines changed

Cargo.lock

+25-28
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jaq-core/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ std = []
1616
format = ["aho-corasick", "base64", "urlencoding"]
1717
math = ["libm"]
1818
parse_json = ["hifijson"]
19+
time = ["chrono"]
1920

2021
[dependencies]
2122
jaq-interpret = { version = "1.5.0", path = "../jaq-interpret" }
2223
hifijson = { version = "0.2.0", optional = true }
23-
time = { version = "0.3.20", optional = true, features = ["formatting", "parsing"] }
24+
chrono = { version = "0.4.38", default-features = false, features = ["alloc"], optional = true }
2425
regex = { version = "1.9", optional = true }
2526
log = { version = "0.4.17", optional = true }
2627
libm = { version = "0.2.7", optional = true }

jaq-core/src/time.rs

+17-31
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,36 @@
11
use crate::{ValR2, ValT};
22
use alloc::string::{String, ToString};
3+
use chrono::DateTime;
34
use jaq_interpret::Error;
45

5-
/// Parse an ISO-8601 timestamp string to a number holding the equivalent UNIX timestamp
6+
/// Parse an ISO 8601 timestamp string to a number holding the equivalent UNIX timestamp
67
/// (seconds elapsed since 1970/01/01).
8+
///
9+
/// Actually, this parses RFC 3339; see
10+
/// <https://ijmacd.github.io/rfc3339-iso8601/> for differences.
11+
/// jq also only parses a very restricted subset of ISO 8601.
712
pub fn from_iso8601<V: ValT>(s: &str) -> ValR2<V> {
8-
use time::format_description::well_known::Iso8601;
9-
use time::OffsetDateTime;
10-
let datetime = OffsetDateTime::parse(s, &Iso8601::DEFAULT)
13+
let dt = DateTime::parse_from_rfc3339(s)
1114
.map_err(|e| Error::str(format_args!("cannot parse {s} as ISO-8601 timestamp: {e}")))?;
12-
let epoch_s = datetime.unix_timestamp();
1315
if s.contains('.') {
14-
let seconds = epoch_s as f64 + (f64::from(datetime.nanosecond()) * 1e-9_f64);
15-
Ok(seconds.into())
16+
Ok((dt.timestamp_micros() as f64 * 1e-6_f64).into())
1617
} else {
17-
isize::try_from(epoch_s)
18+
let seconds = dt.timestamp();
19+
isize::try_from(seconds)
1820
.map(V::from)
19-
.or_else(|_| V::from_num(&epoch_s.to_string()))
21+
.or_else(|_| V::from_num(&seconds.to_string()))
2022
}
2123
}
2224

23-
/// Format a number as an ISO-8601 timestamp string.
25+
/// Format a number as an ISO 8601 timestamp string.
2426
pub fn to_iso8601<V: ValT>(v: &V) -> Result<String, Error<V>> {
25-
use time::format_description::well_known::iso8601;
26-
use time::OffsetDateTime;
27-
const SECONDS_CONFIG: iso8601::EncodedConfig = iso8601::Config::DEFAULT
28-
.set_time_precision(iso8601::TimePrecision::Second {
29-
decimal_digits: None,
30-
})
31-
.encode();
32-
33-
let fail1 = |e| Error::str(format_args!("cannot format {v} as ISO-8601 timestamp: {e}"));
34-
let fail2 = |e| Error::str(format_args!("cannot format {v} as ISO-8601 timestamp: {e}"));
35-
27+
let fail = || Error::str(format_args!("cannot format {v} as ISO-8601 timestamp"));
3628
if let Some(i) = v.as_isize() {
37-
let iso8601_fmt_s = iso8601::Iso8601::<SECONDS_CONFIG>;
38-
OffsetDateTime::from_unix_timestamp(i as i64)
39-
.map_err(fail1)?
40-
.format(&iso8601_fmt_s)
41-
.map_err(fail2)
29+
let dt = DateTime::from_timestamp(i as i64, 0).ok_or_else(fail)?;
30+
Ok(dt.format("%Y-%m-%dT%H:%M:%SZ").to_string())
4231
} else {
4332
let f = v.as_f64()?;
44-
let f_ns = (f * 1_000_000_000_f64).round() as i128;
45-
OffsetDateTime::from_unix_timestamp_nanos(f_ns)
46-
.map_err(fail1)?
47-
.format(&iso8601::Iso8601::DEFAULT)
48-
.map_err(fail2)
33+
let dt = DateTime::from_timestamp_micros((f * 1e6_f64) as i64).ok_or_else(fail)?;
34+
Ok(dt.format("%Y-%m-%dT%H:%M:%S%.fZ").to_string())
4935
}
5036
}

jaq-core/tests/tests.rs

+16-19
Original file line numberDiff line numberDiff line change
@@ -37,25 +37,22 @@ fn ascii() {
3737
give(json!("aAaAäの"), "ascii_downcase", json!("aaaaäの"));
3838
}
3939

40-
#[test]
41-
fn dateiso8601() {
42-
give(
43-
json!("1970-01-02T00:00:00Z"),
44-
"fromdateiso8601",
45-
json!(86400),
46-
);
47-
give(
48-
json!("1970-01-02T00:00:00.123456789Z"),
49-
"fromdateiso8601",
50-
json!(86400.123456789),
51-
);
52-
give(json!(86400), "todateiso8601", json!("1970-01-02T00:00:00Z"));
53-
give(
54-
json!(86400.123456789),
55-
"todateiso8601",
56-
json!("1970-01-02T00:00:00.123456789Z"),
57-
);
58-
}
40+
yields!(
41+
fromdate,
42+
r#""1970-01-02T00:00:00Z" | fromdateiso8601"#,
43+
86400
44+
);
45+
yields!(
46+
fromdate_micros,
47+
r#""1970-01-02T00:00:00.123456Z" | fromdateiso8601"#,
48+
86400.123456
49+
);
50+
yields!(todate, r#"86400 | todateiso8601"#, "1970-01-02T00:00:00Z");
51+
yields!(
52+
todate_micros,
53+
r#"86400.123456 | todateiso8601"#,
54+
"1970-01-02T00:00:00.123456Z"
55+
);
5956

6057
#[test]
6158
fn explode_implode() {

jaq-std/tests/std.rs

+23-24
Original file line numberDiff line numberDiff line change
@@ -25,34 +25,33 @@ fn any() {
2525
give(json!({"a": false, "b": true}), "any", json!(true));
2626
}
2727

28-
#[test]
29-
fn date() {
30-
// aliases for fromdateiso8601 and todateiso8601
31-
give(json!("1970-01-02T00:00:00Z"), "fromdate", json!(86400));
32-
give(
33-
json!("1970-01-02T00:00:00.123456789Z"),
34-
"fromdate",
35-
json!(86400.123456789),
36-
);
37-
give(json!(86400), "todate", json!("1970-01-02T00:00:00Z"));
38-
give(
39-
json!(86400.123456789),
40-
"todate",
41-
json!("1970-01-02T00:00:00.123456789Z"),
42-
);
43-
}
28+
// aliases for fromdateiso8601 and todateiso8601
29+
yields!(fromdate, r#""1970-01-02T00:00:00Z" | fromdate"#, 86400);
30+
yields!(
31+
fromdate_mu,
32+
r#""1970-01-02T00:00:00.123456Z" | fromdate"#,
33+
86400.123456
34+
);
35+
yields!(todate, r#"86400 | todate"#, "1970-01-02T00:00:00Z");
36+
yields!(
37+
todate_mu,
38+
r#"86400.123456 | todate"#,
39+
"1970-01-02T00:00:00.123456Z"
40+
);
4441

45-
#[test]
46-
fn date_roundtrip() {
47-
let epoch = 946684800;
48-
give(json!(epoch), "todate|fromdate", json!(epoch));
49-
let epoch_ns = 946684800.123456;
50-
give(json!(epoch_ns), "todate|fromdate", json!(epoch_ns));
42+
yields!(tofromdate, "946684800|todate|fromdate", 946684800);
43+
yields!(
44+
tofromdate_mu,
45+
"946684800.123456|todate|fromdate",
46+
946684800.123456
47+
);
5148

49+
#[test]
50+
fn fromtodate() {
5251
let iso = "2000-01-01T00:00:00Z";
5352
give(json!(iso), "fromdate|todate", json!(iso));
54-
let iso_ns = "2000-01-01T00:00:00.123456000Z";
55-
give(json!(iso_ns), "fromdate|todate", json!(iso_ns));
53+
let iso_mu = "2000-01-01T00:00:00.123456Z";
54+
give(json!(iso_mu), "fromdate|todate", json!(iso_mu));
5655
}
5756

5857
yields!(

0 commit comments

Comments
 (0)