summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorConrad Ludgate <conradludgate@gmail.com>2023-09-11 09:26:05 +0100
committerGitHub <noreply@github.com>2023-09-11 09:26:05 +0100
commitf90c01f702f6a98b041f766b6a1d857bc1b9afef (patch)
tree04a4755bd632abdcf398d0ce903163ed60a5a212
parent2342a3392349c0ae9d742e9da9833590e6567d08 (diff)
replace chrono with time (#806)
* replace chrono with time * Fix test chrono usage --------- Co-authored-by: Ellie Huxtable <ellie@elliehuxtable.com>
-rw-r--r--Cargo.lock131
-rw-r--r--Cargo.toml13
-rw-r--r--atuin-client/Cargo.toml3
-rw-r--r--atuin-client/src/api_client.rs11
-rw-r--r--atuin-client/src/database.rs63
-rw-r--r--atuin-client/src/encryption.rs54
-rw-r--r--atuin-client/src/history.rs33
-rw-r--r--atuin-client/src/history/builder.rs9
-rw-r--r--atuin-client/src/import/bash.rs13
-rw-r--r--atuin-client/src/import/fish.rs10
-rw-r--r--atuin-client/src/import/nu.rs5
-rw-r--r--atuin-client/src/import/nu_histdb.rs10
-rw-r--r--atuin-client/src/import/resh.rs14
-rw-r--r--atuin-client/src/import/zsh.rs37
-rw-r--r--atuin-client/src/import/zsh_histdb.rs6
-rw-r--r--atuin-client/src/settings.rs30
-rw-r--r--atuin-client/src/sync.rs14
-rw-r--r--atuin-common/Cargo.toml5
-rw-r--r--atuin-common/src/api.rs11
-rw-r--r--atuin-common/src/record.rs2
-rw-r--r--atuin-common/src/utils.rs44
-rw-r--r--atuin-server-database/Cargo.toml3
-rw-r--r--atuin-server-database/src/lib.rs98
-rw-r--r--atuin-server-database/src/models.rs8
-rw-r--r--atuin-server-postgres/Cargo.toml2
-rw-r--r--atuin-server-postgres/src/lib.rs11
-rw-r--r--atuin-server/Cargo.toml4
-rw-r--r--atuin-server/src/handlers/history.rs27
-rw-r--r--atuin/Cargo.toml4
-rw-r--r--atuin/src/command/client/history.rs27
-rw-r--r--atuin/src/command/client/search.rs2
-rw-r--r--atuin/src/command/client/search/engines/skim.rs6
-rw-r--r--atuin/src/command/client/search/history_list.rs5
-rw-r--r--atuin/src/command/client/stats.rs26
-rw-r--r--deny.toml2
35 files changed, 358 insertions, 385 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b7f287a5..38af009d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -55,15 +55,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]]
-name = "android_system_properties"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
-dependencies = [
- "libc",
-]
-
-[[package]]
name = "anstream"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -160,7 +151,6 @@ dependencies = [
"atuin-server",
"atuin-server-postgres",
"base64 0.21.2",
- "chrono",
"clap",
"clap_complete",
"colored",
@@ -181,6 +171,7 @@ dependencies = [
"semver",
"serde",
"serde_json",
+ "time",
"tiny-bip39",
"tokio",
"tracing",
@@ -197,7 +188,6 @@ dependencies = [
"async-trait",
"atuin-common",
"base64 0.21.2",
- "chrono",
"clap",
"config",
"crypto_secretbox",
@@ -229,6 +219,7 @@ dependencies = [
"shellexpand",
"sql-builder",
"sqlx",
+ "time",
"tokio",
"typed-builder",
"urlencoding",
@@ -240,12 +231,12 @@ dependencies = [
name = "atuin-common"
version = "16.0.0"
dependencies = [
- "chrono",
"eyre",
"pretty_assertions",
"rand 0.8.5",
"serde",
"sqlx",
+ "time",
"typed-builder",
"uuid",
]
@@ -260,8 +251,6 @@ dependencies = [
"atuin-server-database",
"axum",
"base64 0.21.2",
- "chrono",
- "chronoutil",
"config",
"eyre",
"fs-err",
@@ -271,6 +260,7 @@ dependencies = [
"semver",
"serde",
"serde_json",
+ "time",
"tokio",
"tower",
"tower-http",
@@ -284,10 +274,9 @@ version = "16.0.0"
dependencies = [
"async-trait",
"atuin-common",
- "chrono",
- "chronoutil",
"eyre",
"serde",
+ "time",
"tracing",
"uuid",
]
@@ -299,10 +288,10 @@ dependencies = [
"async-trait",
"atuin-common",
"atuin-server-database",
- "chrono",
"futures-util",
"serde",
"sqlx",
+ "time",
"tracing",
"uuid",
]
@@ -516,31 +505,6 @@ dependencies = [
]
[[package]]
-name = "chrono"
-version = "0.4.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
-dependencies = [
- "iana-time-zone",
- "js-sys",
- "num-integer",
- "num-traits",
- "serde",
- "time 0.1.45",
- "wasm-bindgen",
- "winapi",
-]
-
-[[package]]
-name = "chronoutil"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43a58c924bb772aa201da3acf5308c46b60275c64e6d3bc89c23dd63d71e83fd"
-dependencies = [
- "chrono",
-]
-
-[[package]]
name = "cipher"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -838,6 +802,9 @@ name = "deranged"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929"
+dependencies = [
+ "serde",
+]
[[package]]
name = "diff"
@@ -1420,29 +1387,6 @@ dependencies = [
]
[[package]]
-name = "iana-time-zone"
-version = "0.1.57"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
-dependencies = [
- "android_system_properties",
- "core-foundation-sys",
- "iana-time-zone-haiku",
- "js-sys",
- "wasm-bindgen",
- "windows",
-]
-
-[[package]]
-name = "iana-time-zone-haiku"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
-dependencies = [
- "cc",
-]
-
-[[package]]
name = "idna"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1521,8 +1465,8 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ffd2ac8397b9574daa4ffa7ede4427dd249cadaa900719d4b01154a5631d38b"
dependencies = [
- "chrono",
"logos",
+ "time",
]
[[package]]
@@ -1847,6 +1791,15 @@ dependencies = [
]
[[package]]
+name = "num_threads"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "number_prefix"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2478,7 +2431,7 @@ dependencies = [
"iso8601",
"ring",
"thiserror",
- "time 0.3.25",
+ "time",
"zeroize",
]
@@ -2817,7 +2770,6 @@ dependencies = [
"atoi",
"byteorder",
"bytes",
- "chrono",
"crc",
"crossbeam-queue",
"dotenvy",
@@ -2844,6 +2796,7 @@ dependencies = [
"smallvec",
"sqlformat",
"thiserror",
+ "time",
"tokio",
"tokio-stream",
"tracing",
@@ -2902,7 +2855,6 @@ dependencies = [
"bitflags 2.4.0",
"byteorder",
"bytes",
- "chrono",
"crc",
"digest 0.10.7",
"dotenvy",
@@ -2930,6 +2882,7 @@ dependencies = [
"sqlx-core",
"stringprep",
"thiserror",
+ "time",
"tracing",
"uuid",
"whoami",
@@ -2945,7 +2898,6 @@ dependencies = [
"base64 0.21.2",
"bitflags 2.4.0",
"byteorder",
- "chrono",
"crc",
"dotenvy",
"etcetera",
@@ -2971,6 +2923,7 @@ dependencies = [
"sqlx-core",
"stringprep",
"thiserror",
+ "time",
"tracing",
"uuid",
"whoami",
@@ -2983,7 +2936,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4c21bf34c7cae5b283efb3ac1bcc7670df7561124dc2f8bdc0b59be40f79a2"
dependencies = [
"atoi",
- "chrono",
"flume",
"futures-channel",
"futures-core",
@@ -2995,6 +2947,7 @@ dependencies = [
"percent-encoding",
"serde",
"sqlx-core",
+ "time",
"tracing",
"url",
"uuid",
@@ -3104,23 +3057,14 @@ dependencies = [
[[package]]
name = "time"
-version = "0.1.45"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
-dependencies = [
- "libc",
- "wasi 0.10.0+wasi-snapshot-preview1",
- "winapi",
-]
-
-[[package]]
-name = "time"
-version = "0.3.25"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea"
+checksum = "a79d09ac6b08c1ab3906a2f7cc2e81a0e27c7ae89c63812df75e52bef0751e07"
dependencies = [
"deranged",
"itoa",
+ "libc",
+ "num_threads",
"serde",
"time-core",
"time-macros",
@@ -3134,9 +3078,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
[[package]]
name = "time-macros"
-version = "0.2.11"
+version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd"
+checksum = "75c65469ed6b3a4809d987a41eb1dc918e9bc1d92211cbad7ae82931846f7451"
dependencies = [
"time-core",
]
@@ -3525,12 +3469,6 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
-version = "0.10.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
-
-[[package]]
-name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
@@ -3662,15 +3600,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
-name = "windows"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
-dependencies = [
- "windows-targets 0.48.5",
-]
-
-[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 9b9bfc01..1a8e1d0d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,7 +12,7 @@ members = [
name = "atuin"
version = "16.0.0"
authors = ["Ellie Huxtable <ellie@elliehuxtable.com>"]
-rust-version = "1.59"
+rust-version = "1.67"
license = "MIT"
homepage = "https://atuin.sh"
repository = "https://github.com/atuinsh/atuin"
@@ -22,13 +22,13 @@ readme = "README.md"
async-trait = "0.1.58"
base64 = "0.21"
log = "0.4"
-chrono = { version = "0.4", features = ["serde"] }
+time = { version = "0.3", features = ["serde-human-readable", "macros", "local-offset"] }
clap = { version = "4.0.18", features = ["derive"] }
config = { version = "0.13", default-features = false, features = ["toml"] }
directories = "4"
eyre = "0.6"
fs-err = "2.9"
-interim = { version = "0.1.0", features = ["chrono"] }
+interim = { version = "0.1.0", features = ["time"] }
itertools = "0.10.5"
rand = { version = "0.8.5", features = ["std"] }
semver = "1.0.14"
@@ -50,4 +50,9 @@ default-features = false
[workspace.dependencies.sqlx]
version = "0.7.1"
-features = ["runtime-tokio-rustls", "chrono", "postgres", "uuid"]
+features = [
+ "runtime-tokio-rustls",
+ "time",
+ "postgres",
+ "uuid",
+]
diff --git a/atuin-client/Cargo.toml b/atuin-client/Cargo.toml
index 732b6a74..9e8a050d 100644
--- a/atuin-client/Cargo.toml
+++ b/atuin-client/Cargo.toml
@@ -3,6 +3,7 @@ name = "atuin-client"
edition = "2021"
description = "client library for atuin"
+rust-version = { workspace = true }
version = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
@@ -20,7 +21,7 @@ atuin-common = { path = "../atuin-common", version = "16.0.0" }
log = { workspace = true }
base64 = { workspace = true }
-chrono = { workspace = true }
+time = { workspace = true }
clap = { workspace = true }
eyre = { workspace = true }
directories = { workspace = true }
diff --git a/atuin-client/src/api_client.rs b/atuin-client/src/api_client.rs
index 5ae1ed0a..d2ca339f 100644
--- a/atuin-client/src/api_client.rs
+++ b/atuin-client/src/api_client.rs
@@ -1,7 +1,6 @@
use std::collections::HashMap;
use std::env;
-use chrono::Utc;
use eyre::{bail, Result};
use reqwest::{
header::{HeaderMap, AUTHORIZATION, USER_AGENT},
@@ -17,6 +16,8 @@ use atuin_common::{
record::RecordIndex,
};
use semver::Version;
+use time::format_description::well_known::Rfc3339;
+use time::OffsetDateTime;
use crate::{history::History, sync::hash_str};
@@ -150,8 +151,8 @@ impl<'a> Client<'a> {
pub async fn get_history(
&self,
- sync_ts: chrono::DateTime<Utc>,
- history_ts: chrono::DateTime<Utc>,
+ sync_ts: OffsetDateTime,
+ history_ts: OffsetDateTime,
host: Option<String>,
) -> Result<SyncHistoryResponse> {
let host = host.unwrap_or_else(|| {
@@ -165,8 +166,8 @@ impl<'a> Client<'a> {
let url = format!(
"{}/sync/history?sync_ts={}&history_ts={}&host={}",
self.sync_addr,
- urlencoding::encode(sync_ts.to_rfc3339().as_str()),
- urlencoding::encode(history_ts.to_rfc3339().as_str()),
+ urlencoding::encode(sync_ts.format(&Rfc3339)?.as_str()),
+ urlencoding::encode(history_ts.format(&Rfc3339)?.as_str()),
host,
);
diff --git a/atuin-client/src/database.rs b/atuin-client/src/database.rs
index b69c7cb2..16a4a43f 100644
--- a/atuin-client/src/database.rs
+++ b/atuin-client/src/database.rs
@@ -6,7 +6,6 @@ use std::{
use async_trait::async_trait;
use atuin_common::utils;
-use chrono::{prelude::*, Utc};
use fs_err as fs;
use itertools::Itertools;
use lazy_static::lazy_static;
@@ -17,6 +16,7 @@ use sqlx::{
sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePool, SqlitePoolOptions, SqliteRow},
Result, Row,
};
+use time::OffsetDateTime;
use super::{
history::History,
@@ -81,18 +81,14 @@ pub trait Database: Send + Sync + 'static {
max: Option<usize>,
unique: bool,
) -> Result<Vec<History>>;
- async fn range(
- &self,
- from: chrono::DateTime<Utc>,
- to: chrono::DateTime<Utc>,
- ) -> Result<Vec<History>>;
+ async fn range(&self, from: OffsetDateTime, to: OffsetDateTime) -> Result<Vec<History>>;
async fn update(&self, h: &History) -> Result<()>;
async fn history_count(&self) -> Result<i64>;
async fn first(&self) -> Result<History>;
async fn last(&self) -> Result<History>;
- async fn before(&self, timestamp: chrono::DateTime<Utc>, count: i64) -> Result<Vec<History>>;
+ async fn before(&self, timestamp: OffsetDateTime, count: i64) -> Result<Vec<History>>;
async fn delete(&self, mut h: History) -> Result<()>;
async fn deleted(&self) -> Result<Vec<History>>;
@@ -158,14 +154,14 @@ impl Sqlite {
values(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)",
)
.bind(h.id.as_str())
- .bind(h.timestamp.timestamp_nanos())
+ .bind(h.timestamp.unix_timestamp_nanos() as i64)
.bind(h.duration)
.bind(h.exit)
.bind(h.command.as_str())
.bind(h.cwd.as_str())
.bind(h.session.as_str())
.bind(h.hostname.as_str())
- .bind(h.deleted_at.map(|t|t.timestamp_nanos()))
+ .bind(h.deleted_at.map(|t|t.unix_timestamp_nanos() as i64))
.execute(&mut **tx)
.await?;
@@ -177,14 +173,19 @@ impl Sqlite {
History::from_db()
.id(row.get("id"))
- .timestamp(Utc.timestamp_nanos(row.get("timestamp")))
+ .timestamp(
+ OffsetDateTime::from_unix_timestamp_nanos(row.get::<i64, _>("timestamp") as i128)
+ .unwrap(),
+ )
.duration(row.get("duration"))
.exit(row.get("exit"))
.command(row.get("command"))
.cwd(row.get("cwd"))
.session(row.get("session"))
.hostname(row.get("hostname"))
- .deleted_at(deleted_at.map(|t| Utc.timestamp_nanos(t)))
+ .deleted_at(
+ deleted_at.and_then(|t| OffsetDateTime::from_unix_timestamp_nanos(t as i128).ok()),
+ )
.build()
.into()
}
@@ -236,14 +237,14 @@ impl Database for Sqlite {
where id = ?1",
)
.bind(h.id.as_str())
- .bind(h.timestamp.timestamp_nanos())
+ .bind(h.timestamp.unix_timestamp_nanos() as i64)
.bind(h.duration)
.bind(h.exit)
.bind(h.command.as_str())
.bind(h.cwd.as_str())
.bind(h.session.as_str())
.bind(h.hostname.as_str())
- .bind(h.deleted_at.map(|t|t.timestamp_nanos()))
+ .bind(h.deleted_at.map(|t|t.unix_timestamp_nanos() as i64))
.execute(&self.pool)
.await?;
@@ -292,18 +293,14 @@ impl Database for Sqlite {
Ok(res)
}
- async fn range(
- &self,
- from: chrono::DateTime<Utc>,
- to: chrono::DateTime<Utc>,
- ) -> Result<Vec<History>> {
+ async fn range(&self, from: OffsetDateTime, to: OffsetDateTime) -> Result<Vec<History>> {
debug!("listing history from {:?} to {:?}", from, to);
let res = sqlx::query(
"select * from history where timestamp >= ?1 and timestamp <= ?2 order by timestamp asc",
)
- .bind(from.timestamp_nanos())
- .bind(to.timestamp_nanos())
+ .bind(from.unix_timestamp_nanos() as i64)
+ .bind(to.unix_timestamp_nanos() as i64)
.map(Self::query_history)
.fetch_all(&self.pool)
.await?;
@@ -332,11 +329,11 @@ impl Database for Sqlite {
Ok(res)
}
- async fn before(&self, timestamp: chrono::DateTime<Utc>, count: i64) -> Result<Vec<History>> {
+ async fn before(&self, timestamp: OffsetDateTime, count: i64) -> Result<Vec<History>> {
let res = sqlx::query(
"select * from history where timestamp < ?1 order by timestamp desc limit ?2",
)
- .bind(timestamp.timestamp_nanos())
+ .bind(timestamp.unix_timestamp_nanos() as i64)
.bind(count)
.map(Self::query_history)
.fetch_all(&self.pool)
@@ -471,13 +468,23 @@ impl Database for Sqlite {
.map(|exclude_cwd| sql.and_where_ne("cwd", quote(exclude_cwd)));
filter_options.before.map(|before| {
- interim::parse_date_string(before.as_str(), Utc::now(), interim::Dialect::Uk)
- .map(|before| sql.and_where_lt("timestamp", quote(before.timestamp_nanos())))
+ interim::parse_date_string(
+ before.as_str(),
+ OffsetDateTime::now_utc(),
+ interim::Dialect::Uk,
+ )
+ .map(|before| {
+ sql.and_where_lt("timestamp", quote(before.unix_timestamp_nanos() as i64))
+ })
});
filter_options.after.map(|after| {
- interim::parse_date_string(after.as_str(), Utc::now(), interim::Dialect::Uk)
- .map(|after| sql.and_where_gt("timestamp", quote(after.timestamp_nanos())))
+ interim::parse_date_string(
+ after.as_str(),
+ OffsetDateTime::now_utc(),
+ interim::Dialect::Uk,
+ )
+ .map(|after| sql.and_where_gt("timestamp", quote(after.unix_timestamp_nanos() as i64)))
});
sql.and_where_is_null("deleted_at");
@@ -540,7 +547,7 @@ impl Database for Sqlite {
// deleted_at doesn't mean the actual time that the user deleted it,
// but the time that the system marks it as deleted
async fn delete(&self, mut h: History) -> Result<()> {
- let now = chrono::Utc::now();
+ let now = OffsetDateTime::now_utc();
h.command = rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(32)
@@ -612,7 +619,7 @@ mod test {
async fn new_history_item(db: &mut impl Database, cmd: &str) -> Result<()> {
let mut captured: History = History::capture()
- .timestamp(chrono::Utc::now())
+ .timestamp(OffsetDateTime::now_utc())
.command(cmd)
.cwd("/home/ellie")
.build()
diff --git a/atuin-client/src/encryption.rs b/atuin-client/src/encryption.rs
index 056c56d7..f9f8bcb3 100644
--- a/atuin-client/src/encryption.rs
+++ b/atuin-client/src/encryption.rs
@@ -11,7 +11,6 @@
use std::{io::prelude::*, path::PathBuf};
use base64::prelude::{Engine, BASE64_STANDARD};
-use chrono::{DateTime, Utc};
pub use crypto_secretbox::Key;
use crypto_secretbox::{
aead::{Nonce, OsRng},
@@ -21,6 +20,7 @@ use eyre::{bail, ensure, eyre, Context, Result};
use fs_err as fs;
use rmp::{decode::Bytes, Marker};
use serde::{Deserialize, Serialize};
+use time::{format_description::well_known::Rfc3339, macros::format_description, OffsetDateTime};
use crate::{history::History, settings::Settings};
@@ -137,6 +137,28 @@ pub fn decrypt(mut encrypted_history: EncryptedHistory, key: &Key) -> Result<His
Ok(history)
}
+fn format_rfc3339(ts: OffsetDateTime) -> Result<String> {
+ // horrible hack. chrono AutoSI limits to 0, 3, 6, or 9 decimal places for nanoseconds.
+ // time does not have this functionality.
+ static PARTIAL_RFC3339_0: &[time::format_description::FormatItem<'static>] =
+ format_description!("[year]-[month]-[day]T[hour]:[minute]:[second]Z");
+ static PARTIAL_RFC3339_3: &[time::format_description::FormatItem<'static>] =
+ format_description!("[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:3]Z");
+ static PARTIAL_RFC3339_6: &[time::format_description::FormatItem<'static>] =
+ format_description!("[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:6]Z");
+ static PARTIAL_RFC3339_9: &[time::format_description::FormatItem<'static>] =
+ format_description!("[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:9]Z");
+
+ let fmt = match ts.nanosecond() {
+ 0 => PARTIAL_RFC3339_0,
+ ns if ns % 1_000_000 == 0 => PARTIAL_RFC3339_3,
+ ns if ns % 1_000 == 0 => PARTIAL_RFC3339_6,
+ _ => PARTIAL_RFC3339_9,
+ };
+
+ Ok(ts.format(fmt)?)
+}
+
fn encode(h: &History) -> Result<Vec<u8>> {
use rmp::encode;
@@ -145,11 +167,7 @@ fn encode(h: &History) -> Result<Vec<u8>> {
encode::write_array_len(&mut output, 9)?;
encode::write_str(&mut output, &h.id)?;
- encode::write_str(
- &mut output,
- &(h.timestamp
- .to_rfc3339_opts(chrono::SecondsFormat::AutoSi, true)),
- )?;
+ encode::write_str(&mut output, &(format_rfc3339(h.timestamp)?))?;
encode::write_sint(&mut output, h.duration)?;
encode::write_sint(&mut output, h.exit)?;
encode::write_str(&mut output, &h.command)?;
@@ -157,10 +175,7 @@ fn encode(h: &History) -> Result<Vec<u8>> {
encode::write_str(&mut output, &h.session)?;
encode::write_str(&mut output, &h.hostname)?;
match h.deleted_at {
- Some(d) => encode::write_str(
- &mut output,
- &d.to_rfc3339_opts(chrono::SecondsFormat::AutoSi, true),
- )?,
+ Some(d) => encode::write_str(&mut output, &format_rfc3339(d)?)?,
None => encode::write_nil(&mut output)?,
}
@@ -220,7 +235,7 @@ fn decode(bytes: &[u8]) -> Result<History> {
Ok(History {
id: id.to_owned(),
- timestamp: DateTime::parse_from_rfc3339(timestamp)?.with_timezone(&Utc),
+ timestamp: OffsetDateTime::parse(timestamp, &Rfc3339)?,
duration,
exit,
command: command.to_owned(),
@@ -228,9 +243,8 @@ fn decode(bytes: &[u8]) -> Result<History> {
session: session.to_owned(),
hostname: hostname.to_owned(),
deleted_at: deleted_at
- .map(DateTime::parse_from_rfc3339)
- .transpose()?
- .map(|dt| dt.with_timezone(&Utc)),
+ .map(|t| OffsetDateTime::parse(t, &Rfc3339))
+ .transpose()?,
})
}
@@ -241,6 +255,8 @@ fn error_report<E: std::fmt::Debug>(err: E) -> eyre::Report {
#[cfg(test)]
mod test {
use crypto_secretbox::{aead::OsRng, KeyInit, XSalsa20Poly1305};
+ use pretty_assertions::assert_eq;
+ use time::{macros::datetime, OffsetDateTime};
use crate::history::History;
@@ -253,7 +269,7 @@ mod test {
let history = History::from_db()
.id("1".into())
- .timestamp(chrono::Utc::now())
+ .timestamp(OffsetDateTime::now_utc())
.command("ls".into())