mirror of
https://github.com/eza-community/eza
synced 2024-10-14 20:03:50 +00:00
commit
e074aa8f67
204
Cargo.lock
generated
204
Cargo.lock
generated
|
@ -2,6 +2,21 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[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 = "ansiterm"
|
||||
version = "0.12.2"
|
||||
|
@ -29,6 +44,12 @@ version = "2.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
|
@ -44,6 +65,33 @@ dependencies = [
|
|||
"jobserver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f56b4c72906975ca04becb8a30e102dfecddd0c06181e3e95ddc444be28881f8"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"time",
|
||||
"wasm-bindgen",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||
|
||||
[[package]]
|
||||
name = "datetime"
|
||||
version = "0.5.2"
|
||||
|
@ -51,8 +99,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "44c3f7a77f3e57fedf80e09136f2d8777ebf621207306f6d96d610af048354bc"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"locale",
|
||||
"pad",
|
||||
"redox_syscall",
|
||||
"winapi",
|
||||
]
|
||||
|
@ -83,7 +129,7 @@ name = "eza"
|
|||
version = "0.11.0"
|
||||
dependencies = [
|
||||
"ansiterm",
|
||||
"datetime",
|
||||
"chrono",
|
||||
"gethostname",
|
||||
"git2",
|
||||
"glob",
|
||||
|
@ -142,9 +188,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
|
@ -152,6 +198,29 @@ version = "0.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
|
||||
|
||||
[[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.2.3"
|
||||
|
@ -183,6 +252,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -253,6 +331,15 @@ version = "1.0.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308d96db8debc727c3fd9744aac51751243420e46edf401010908da7f8d5e57c"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
|
@ -269,6 +356,12 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-src"
|
||||
version = "111.26.0+1.1.1u"
|
||||
|
@ -292,15 +385,6 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pad"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2ad9b889f1b12e0b9ee24db044b5129150d5eada288edc800f789928dc8c0e3"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "partition-identity"
|
||||
version = "0.3.0"
|
||||
|
@ -440,9 +524,9 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.31"
|
||||
version = "2.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
|
||||
checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -470,24 +554,35 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.47"
|
||||
version = "1.0.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
|
||||
checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.47"
|
||||
version = "1.0.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
|
||||
checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "timeago"
|
||||
version = "0.4.1"
|
||||
|
@ -573,6 +668,66 @@ version = "0.2.12"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbdbff6266a24120518560b5dc983096efb98462e51d0d68169895b237be3e5d"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
@ -595,6 +750,15 @@ version = "0.4.0"
|
|||
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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -38,6 +38,7 @@ name = "eza"
|
|||
[dependencies]
|
||||
ansiterm = "0.12.2"
|
||||
gethostname = "0.4.3"
|
||||
chrono = "0.4"
|
||||
glob = "0.3"
|
||||
lazy_static = "1.3"
|
||||
libc = "0.2"
|
||||
|
@ -55,11 +56,6 @@ unicode-width = "0.1"
|
|||
urlencoding = "2.1.3"
|
||||
zoneinfo_compiled = "0.5.1"
|
||||
|
||||
[dependencies.datetime]
|
||||
version = "0.5.2"
|
||||
default-features = false
|
||||
features = ["format"]
|
||||
|
||||
[dependencies.git2]
|
||||
version = "0.18"
|
||||
optional = true
|
||||
|
@ -71,9 +67,8 @@ proc-mounts = "0.3"
|
|||
[target.'cfg(unix)'.dependencies]
|
||||
uzers = "0.11.2"
|
||||
|
||||
[build-dependencies.datetime]
|
||||
version = "0.5.2"
|
||||
default-features = false
|
||||
[build-dependencies]
|
||||
chrono = "0.4"
|
||||
|
||||
[features]
|
||||
default = [ "git" ]
|
||||
|
|
6
build.rs
6
build.rs
|
@ -15,7 +15,7 @@ use std::fs::File;
|
|||
use std::io::{self, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use datetime::{LocalDateTime, ISO};
|
||||
use chrono::prelude::*;
|
||||
|
||||
|
||||
/// The build script entry point.
|
||||
|
@ -118,6 +118,6 @@ fn nonstandard_features_string() -> String {
|
|||
|
||||
/// Formats the current date as an ISO 8601 string.
|
||||
fn build_date() -> String {
|
||||
let now = LocalDateTime::now();
|
||||
format!("{}", now.date().iso())
|
||||
let now = Local::now();
|
||||
now.date_naive().format("%Y-%m-%d").to_string()
|
||||
}
|
||||
|
|
|
@ -6,9 +6,8 @@ use std::os::unix::fs::{FileTypeExt, MetadataExt, PermissionsExt};
|
|||
#[cfg(windows)]
|
||||
use std::os::windows::fs::MetadataExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::SystemTime;
|
||||
#[cfg(unix)]
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
|
||||
use chrono::prelude::*;
|
||||
|
||||
use log::*;
|
||||
|
||||
|
@ -536,71 +535,56 @@ impl<'dir> File<'dir> {
|
|||
}
|
||||
|
||||
/// This file’s last modified timestamp, if available on this platform.
|
||||
pub fn modified_time(&self) -> Option<SystemTime> {
|
||||
pub fn modified_time(&self) -> Option<NaiveDateTime> {
|
||||
if self.is_link() && self.deref_links {
|
||||
match self.link_target_recurse() {
|
||||
FileTarget::Ok(f) => f.metadata.modified().ok(),
|
||||
return match self.link_target_recurse() {
|
||||
FileTarget::Ok(f) => f.modified_time(),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
self.metadata.modified().ok()
|
||||
};
|
||||
}
|
||||
self.metadata.modified().map(|st| DateTime::<Utc>::from(st).naive_utc()).ok()
|
||||
}
|
||||
|
||||
/// This file’s last changed timestamp, if available on this platform.
|
||||
#[cfg(unix)]
|
||||
pub fn changed_time(&self) -> Option<SystemTime> {
|
||||
pub fn changed_time(&self) -> Option<NaiveDateTime> {
|
||||
if self.is_link() && self.deref_links {
|
||||
match self.link_target_recurse() {
|
||||
FileTarget::Ok(f) => return f.changed_time(),
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
|
||||
let (mut sec, mut nanosec) = (self.metadata.ctime(), self.metadata.ctime_nsec());
|
||||
|
||||
if sec < 0 {
|
||||
if nanosec > 0 {
|
||||
sec += 1;
|
||||
nanosec -= 1_000_000_000;
|
||||
}
|
||||
|
||||
let duration = Duration::new(sec.unsigned_abs(), nanosec.unsigned_abs() as u32);
|
||||
Some(UNIX_EPOCH - duration)
|
||||
}
|
||||
else {
|
||||
let duration = Duration::new(sec as u64, nanosec as u32);
|
||||
Some(UNIX_EPOCH + duration)
|
||||
return match self.link_target_recurse() {
|
||||
FileTarget::Ok(f) => f.changed_time(),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
NaiveDateTime::from_timestamp_opt(
|
||||
self.metadata.ctime(),
|
||||
self.metadata.ctime_nsec() as u32,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn changed_time(&self) -> Option<SystemTime> {
|
||||
pub fn changed_time(&self) -> Option<NaiveDateTime> {
|
||||
self.modified_time()
|
||||
}
|
||||
|
||||
/// This file’s last accessed timestamp, if available on this platform.
|
||||
pub fn accessed_time(&self) -> Option<SystemTime> {
|
||||
pub fn accessed_time(&self) -> Option<NaiveDateTime> {
|
||||
if self.is_link() && self.deref_links {
|
||||
match self.link_target_recurse() {
|
||||
FileTarget::Ok(f) => f.metadata.accessed().ok(),
|
||||
return match self.link_target_recurse() {
|
||||
FileTarget::Ok(f) => f.accessed_time(),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
self.metadata.accessed().ok()
|
||||
};
|
||||
}
|
||||
self.metadata.accessed().map(|st| DateTime::<Utc>::from(st).naive_utc()).ok()
|
||||
}
|
||||
|
||||
/// This file’s created timestamp, if available on this platform.
|
||||
pub fn created_time(&self) -> Option<SystemTime> {
|
||||
pub fn created_time(&self) -> Option<NaiveDateTime> {
|
||||
if self.is_link() && self.deref_links {
|
||||
match self.link_target_recurse() {
|
||||
FileTarget::Ok(f) => f.metadata.created().ok(),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
self.metadata.created().ok()
|
||||
return match self.link_target_recurse() {
|
||||
FileTarget::Ok(f) => f.created_time(),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
self.metadata.created().map(|st| DateTime::<Utc>::from(st).naive_utc()).ok()
|
||||
}
|
||||
|
||||
/// This file’s ‘type’.
|
||||
|
|
|
@ -1,27 +1,19 @@
|
|||
use std::time::SystemTime;
|
||||
|
||||
use datetime::TimeZone;
|
||||
use ansiterm::Style;
|
||||
|
||||
use crate::output::cell::TextCell;
|
||||
use crate::output::time::TimeFormat;
|
||||
|
||||
use ansiterm::Style;
|
||||
use chrono::prelude::*;
|
||||
|
||||
|
||||
pub trait Render {
|
||||
fn render(self, style: Style, tz: &Option<TimeZone>, format: TimeFormat) -> TextCell;
|
||||
fn render(self, style: Style, time_offset: FixedOffset, time_format: TimeFormat) -> TextCell;
|
||||
}
|
||||
|
||||
impl Render for Option<SystemTime> {
|
||||
fn render(self, style: Style, tz: &Option<TimeZone>, format: TimeFormat) -> TextCell {
|
||||
impl Render for Option<NaiveDateTime> {
|
||||
fn render(self, style: Style, time_offset: FixedOffset, time_format: TimeFormat) -> TextCell {
|
||||
let datestamp = if let Some(time) = self {
|
||||
if let Some(ref tz) = tz {
|
||||
format.format_zoned(time, tz)
|
||||
}
|
||||
else {
|
||||
format.format_local(time)
|
||||
}
|
||||
}
|
||||
else {
|
||||
time_format.format(&DateTime::<FixedOffset>::from_naive_utc_and_offset(time, time_offset))
|
||||
} else {
|
||||
String::from("-")
|
||||
};
|
||||
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
use std::cmp::max;
|
||||
#[cfg(unix)]
|
||||
use std::env;
|
||||
use std::ops::Deref;
|
||||
#[cfg(unix)]
|
||||
use std::sync::{Mutex, MutexGuard};
|
||||
|
||||
use datetime::TimeZone;
|
||||
#[cfg(unix)]
|
||||
use zoneinfo_compiled::CompiledData;
|
||||
use zoneinfo_compiled::Result as TZResult;
|
||||
use chrono::prelude::*;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use log::*;
|
||||
|
@ -336,13 +331,12 @@ impl Default for TimeTypes {
|
|||
/// Any environment field should be able to be mocked up for test runs.
|
||||
pub struct Environment {
|
||||
|
||||
/// The computer’s current time offset, determined from time zone.
|
||||
time_offset: FixedOffset,
|
||||
|
||||
/// Localisation rules for formatting numbers.
|
||||
numeric: locale::Numeric,
|
||||
|
||||
/// The computer’s current time zone. This gets used to determine how to
|
||||
/// offset files’ timestamps.
|
||||
tz: Option<TimeZone>,
|
||||
|
||||
/// Mapping cache of user IDs to usernames.
|
||||
#[cfg(unix)]
|
||||
users: Mutex<UsersCache>,
|
||||
|
@ -355,15 +349,7 @@ impl Environment {
|
|||
}
|
||||
|
||||
fn load_all() -> Self {
|
||||
let tz = match determine_time_zone() {
|
||||
Ok(t) => {
|
||||
Some(t)
|
||||
}
|
||||
Err(ref e) => {
|
||||
eprintln!("Unable to determine time zone: {e}");
|
||||
None
|
||||
}
|
||||
};
|
||||
let time_offset = *Local::now().offset();
|
||||
|
||||
let numeric = locale::Numeric::load_user_locale()
|
||||
.unwrap_or_else(|_| locale::Numeric::english());
|
||||
|
@ -371,57 +357,10 @@ impl Environment {
|
|||
#[cfg(unix)]
|
||||
let users = Mutex::new(UsersCache::new());
|
||||
|
||||
Self { numeric, tz, #[cfg(unix)] users }
|
||||
Self { time_offset, numeric, #[cfg(unix)] users }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn determine_time_zone() -> TZResult<TimeZone> {
|
||||
if let Ok(file) = env::var("TZ") {
|
||||
TimeZone::from_file({
|
||||
if file.starts_with('/') {
|
||||
file
|
||||
} else {
|
||||
format!("/usr/share/zoneinfo/{}", {
|
||||
if file.starts_with(':') {
|
||||
file.replacen(':', "", 1)
|
||||
} else {
|
||||
file
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
TimeZone::from_file("/etc/localtime")
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_wraps)] // Needs to match Unix function
|
||||
#[cfg(windows)]
|
||||
fn determine_time_zone() -> TZResult<TimeZone> {
|
||||
use datetime::zone::{FixedTimespan, FixedTimespanSet, StaticTimeZone, TimeZoneSource};
|
||||
use std::borrow::Cow;
|
||||
|
||||
Ok(TimeZone(TimeZoneSource::Static(&StaticTimeZone {
|
||||
name: "Unsupported",
|
||||
fixed_timespans: FixedTimespanSet {
|
||||
first: FixedTimespan {
|
||||
offset: 0,
|
||||
is_dst: false,
|
||||
name: Cow::Borrowed("ZONE_A"),
|
||||
},
|
||||
rest: &[(
|
||||
1_206_838_800, // Sun Mar 30 2008 01:00:00 GMT+0000
|
||||
FixedTimespan {
|
||||
offset: 3600,
|
||||
is_dst: false,
|
||||
name: Cow::Borrowed("ZONE_B"),
|
||||
},
|
||||
)],
|
||||
},
|
||||
})))
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref ENVIRONMENT: Environment = Environment::load_all();
|
||||
}
|
||||
|
@ -561,16 +500,16 @@ impl<'a> Table<'a> {
|
|||
}
|
||||
|
||||
Column::Timestamp(TimeType::Modified) => {
|
||||
file.modified_time().render(self.theme.ui.date, &self.env.tz, self.time_format)
|
||||
file.modified_time().render(self.theme.ui.date, self.env.time_offset, self.time_format)
|
||||
}
|
||||
Column::Timestamp(TimeType::Changed) => {
|
||||
file.changed_time().render(self.theme.ui.date, &self.env.tz, self.time_format)
|
||||
file.changed_time().render(self.theme.ui.date, self.env.time_offset, self.time_format)
|
||||
}
|
||||
Column::Timestamp(TimeType::Created) => {
|
||||
file.created_time().render(self.theme.ui.date, &self.env.tz, self.time_format)
|
||||
file.created_time().render(self.theme.ui.date, self.env.time_offset, self.time_format)
|
||||
}
|
||||
Column::Timestamp(TimeType::Accessed) => {
|
||||
file.accessed_time().render(self.theme.ui.date, &self.env.tz, self.time_format)
|
||||
file.accessed_time().render(self.theme.ui.date, self.env.time_offset, self.time_format)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
//! Timestamp formatting.
|
||||
|
||||
use std::convert::TryInto;
|
||||
use std::cmp::max;
|
||||
use std::time::{SystemTime, UNIX_EPOCH, Duration};
|
||||
|
||||
use datetime::{LocalDateTime, TimeZone, DatePiece, TimePiece, Instant};
|
||||
use datetime::fmt::DateFormat;
|
||||
|
||||
use core::cmp::max;
|
||||
use std::time::Duration;
|
||||
use chrono::prelude::*;
|
||||
use lazy_static::lazy_static;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
|
@ -53,80 +49,59 @@ pub enum TimeFormat {
|
|||
Relative,
|
||||
}
|
||||
|
||||
// There are two different formatting functions because local and zoned
|
||||
// timestamps are separate types.
|
||||
|
||||
impl TimeFormat {
|
||||
pub fn format_local(self, time: SystemTime) -> String {
|
||||
pub fn format(self, time: &DateTime<FixedOffset>) -> String {
|
||||
match self {
|
||||
Self::DefaultFormat => default_local(time),
|
||||
Self::ISOFormat => iso_local(time),
|
||||
Self::LongISO => long_local(time),
|
||||
Self::FullISO => full_local(time),
|
||||
Self::Relative => relative(time),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format_zoned(self, time: SystemTime, zone: &TimeZone) -> String {
|
||||
match self {
|
||||
Self::DefaultFormat => default_zoned(time, zone),
|
||||
Self::ISOFormat => iso_zoned(time, zone),
|
||||
Self::LongISO => long_zoned(time, zone),
|
||||
Self::FullISO => full_zoned(time, zone),
|
||||
Self::DefaultFormat => default(time),
|
||||
Self::ISOFormat => iso(time),
|
||||
Self::LongISO => long(time),
|
||||
Self::FullISO => full(time),
|
||||
Self::Relative => relative(time),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[allow(trivial_numeric_casts)]
|
||||
fn default_local(time: SystemTime) -> String {
|
||||
let date = LocalDateTime::at(systemtime_epoch(time));
|
||||
let date_format = get_dateformat(&date);
|
||||
date_format.format(&date, &LOCALE)
|
||||
fn default(time: &DateTime<FixedOffset>) -> String {
|
||||
let month = &*LOCALE.short_month_name(time.month0() as usize);
|
||||
let month_width = short_month_padding(*MAX_MONTH_WIDTH, month);
|
||||
let format = if time.year() == *CURRENT_YEAR {
|
||||
format!("%_d {month:<month_width$} %H:%M")
|
||||
} else {
|
||||
format!("%_d {month:<month_width$} %Y")
|
||||
};
|
||||
time.format(format.as_str()).to_string()
|
||||
}
|
||||
|
||||
#[allow(trivial_numeric_casts)]
|
||||
fn default_zoned(time: SystemTime, zone: &TimeZone) -> String {
|
||||
let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time)));
|
||||
let date_format = get_dateformat(&date);
|
||||
date_format.format(&date, &LOCALE)
|
||||
/// Convert between Unicode width and width in chars to use in format!.
|
||||
/// ex: in Japanese, 月 is one character, but it has the width of two.
|
||||
/// For alignement purposes, we take the real display width into account.
|
||||
/// So, `MAXIMUM_MONTH_WIDTH` (“12月”) = 4, but if we use `{:4}` in format!,
|
||||
/// it will add a space (“ 12月”) because format! counts characters.
|
||||
/// Conversely, a char can have a width of zero (like combining diacritics)
|
||||
fn short_month_padding(max_month_width: usize, month: &str) -> usize {
|
||||
let shift = month.chars().count() as isize - UnicodeWidthStr::width(month) as isize;
|
||||
(max_month_width as isize + shift) as usize
|
||||
}
|
||||
|
||||
fn get_dateformat(date: &LocalDateTime) -> &'static DateFormat<'static> {
|
||||
match (is_recent(date), *MAXIMUM_MONTH_WIDTH) {
|
||||
(true, 4) => &FOUR_WIDE_DATE_TIME,
|
||||
(true, 5) => &FIVE_WIDE_DATE_TIME,
|
||||
(true, _) => &OTHER_WIDE_DATE_TIME,
|
||||
(false, 4) => &FOUR_WIDE_DATE_YEAR,
|
||||
(false, 5) => &FIVE_WIDE_DATE_YEAR,
|
||||
(false, _) => &OTHER_WIDE_DATE_YEAR,
|
||||
fn iso(time: &DateTime<FixedOffset>) -> String {
|
||||
if time.year() == *CURRENT_YEAR {
|
||||
time.format("%m-%d %H:%M").to_string()
|
||||
} else {
|
||||
time.format("%Y-%m-%d").to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(trivial_numeric_casts)]
|
||||
fn long_local(time: SystemTime) -> String {
|
||||
let date = LocalDateTime::at(systemtime_epoch(time));
|
||||
format!("{:04}-{:02}-{:02} {:02}:{:02}",
|
||||
date.year(), date.month() as usize, date.day(),
|
||||
date.hour(), date.minute())
|
||||
fn long(time: &DateTime<FixedOffset>) -> String {
|
||||
time.format("%Y-%m-%d %H:%M").to_string()
|
||||
}
|
||||
|
||||
#[allow(trivial_numeric_casts)]
|
||||
fn long_zoned(time: SystemTime, zone: &TimeZone) -> String {
|
||||
let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time)));
|
||||
format!("{:04}-{:02}-{:02} {:02}:{:02}",
|
||||
date.year(), date.month() as usize, date.day(),
|
||||
date.hour(), date.minute())
|
||||
}
|
||||
|
||||
#[allow(trivial_numeric_casts)]
|
||||
fn relative(time: SystemTime) -> String {
|
||||
// #[allow(trivial_numeric_casts)]
|
||||
fn relative(time: &DateTime<FixedOffset>) -> String {
|
||||
timeago::Formatter::new()
|
||||
.ago("")
|
||||
.convert(
|
||||
Duration::from_secs(
|
||||
max(0, Instant::now().seconds() - systemtime_epoch(time))
|
||||
max(0, Local::now().timestamp() - time.timestamp())
|
||||
// this .unwrap is safe since the call above can never result in a
|
||||
// value < 0
|
||||
.try_into().unwrap()
|
||||
|
@ -134,131 +109,63 @@ fn relative(time: SystemTime) -> String {
|
|||
)
|
||||
}
|
||||
|
||||
#[allow(trivial_numeric_casts)]
|
||||
fn full_local(time: SystemTime) -> String {
|
||||
let date = LocalDateTime::at(systemtime_epoch(time));
|
||||
format!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:09}",
|
||||
date.year(), date.month() as usize, date.day(),
|
||||
date.hour(), date.minute(), date.second(), systemtime_nanos(time))
|
||||
}
|
||||
|
||||
#[allow(trivial_numeric_casts)]
|
||||
fn full_zoned(time: SystemTime, zone: &TimeZone) -> String {
|
||||
use datetime::Offset;
|
||||
|
||||
let local = LocalDateTime::at(systemtime_epoch(time));
|
||||
let date = zone.to_zoned(local);
|
||||
let offset = Offset::of_seconds(zone.offset(local) as i32).expect("Offset out of range");
|
||||
format!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:09} {:+03}{:02}",
|
||||
date.year(), date.month() as usize, date.day(),
|
||||
date.hour(), date.minute(), date.second(), systemtime_nanos(time),
|
||||
offset.hours(), offset.minutes().abs())
|
||||
}
|
||||
|
||||
#[allow(trivial_numeric_casts)]
|
||||
fn iso_local(time: SystemTime) -> String {
|
||||
let date = LocalDateTime::at(systemtime_epoch(time));
|
||||
|
||||
if is_recent(&date) {
|
||||
format!("{:02}-{:02} {:02}:{:02}",
|
||||
date.month() as usize, date.day(),
|
||||
date.hour(), date.minute())
|
||||
}
|
||||
else {
|
||||
format!("{:04}-{:02}-{:02}",
|
||||
date.year(), date.month() as usize, date.day())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(trivial_numeric_casts)]
|
||||
fn iso_zoned(time: SystemTime, zone: &TimeZone) -> String {
|
||||
let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time)));
|
||||
|
||||
if is_recent(&date) {
|
||||
format!("{:02}-{:02} {:02}:{:02}",
|
||||
date.month() as usize, date.day(),
|
||||
date.hour(), date.minute())
|
||||
}
|
||||
else {
|
||||
format!("{:04}-{:02}-{:02}",
|
||||
date.year(), date.month() as usize, date.day())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn systemtime_epoch(time: SystemTime) -> i64 {
|
||||
time.duration_since(UNIX_EPOCH)
|
||||
.map(|t| t.as_secs() as i64)
|
||||
.unwrap_or_else(|e| {
|
||||
let diff = e.duration();
|
||||
let mut secs = diff.as_secs();
|
||||
if diff.subsec_nanos() > 0 {
|
||||
secs += 1;
|
||||
}
|
||||
-(secs as i64)
|
||||
})
|
||||
}
|
||||
|
||||
fn systemtime_nanos(time: SystemTime) -> u32 {
|
||||
time.duration_since(UNIX_EPOCH)
|
||||
.map(|t| t.subsec_nanos())
|
||||
.unwrap_or_else(|e| {
|
||||
let nanos = e.duration().subsec_nanos();
|
||||
if nanos > 0 {
|
||||
1_000_000_000 - nanos
|
||||
} else {
|
||||
nanos
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn is_recent(date: &LocalDateTime) -> bool {
|
||||
date.year() == *CURRENT_YEAR
|
||||
fn full(time: &DateTime<FixedOffset>) -> String {
|
||||
time.format("%Y-%m-%d %H:%M:%S.%f %z").to_string()
|
||||
}
|
||||
|
||||
|
||||
lazy_static! {
|
||||
|
||||
static ref CURRENT_YEAR: i64 = LocalDateTime::now().year();
|
||||
static ref CURRENT_YEAR: i32 = Local::now().year();
|
||||
|
||||
static ref LOCALE: locale::Time = {
|
||||
locale::Time::load_user_locale()
|
||||
.unwrap_or_else(|_| locale::Time::english())
|
||||
};
|
||||
|
||||
static ref MAXIMUM_MONTH_WIDTH: usize = {
|
||||
static ref MAX_MONTH_WIDTH: usize = {
|
||||
// Some locales use a three-character wide month name (Jan to Dec);
|
||||
// others vary between three to four (1月 to 12月, juil.). We check each month width
|
||||
// to detect the longest and set the output format accordingly.
|
||||
let mut maximum_month_width = 0;
|
||||
for i in 0..11 {
|
||||
let current_month_width = UnicodeWidthStr::width(&*LOCALE.short_month_name(i));
|
||||
maximum_month_width = std::cmp::max(maximum_month_width, current_month_width);
|
||||
}
|
||||
maximum_month_width
|
||||
(0..11).map(|i| UnicodeWidthStr::width(&*LOCALE.short_month_name(i))).max().unwrap()
|
||||
};
|
||||
|
||||
static ref FOUR_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse(
|
||||
"{2>:D} {4<:M} {02>:h}:{02>:m}"
|
||||
).unwrap();
|
||||
|
||||
static ref FIVE_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse(
|
||||
"{2>:D} {5<:M} {02>:h}:{02>:m}"
|
||||
).unwrap();
|
||||
|
||||
static ref OTHER_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse(
|
||||
"{2>:D} {:M} {02>:h}:{02>:m}"
|
||||
).unwrap();
|
||||
|
||||
static ref FOUR_WIDE_DATE_YEAR: DateFormat<'static> = DateFormat::parse(
|
||||
"{2>:D} {4<:M} {5>:Y}"
|
||||
).unwrap();
|
||||
|
||||
static ref FIVE_WIDE_DATE_YEAR: DateFormat<'static> = DateFormat::parse(
|
||||
"{2>:D} {5<:M} {5>:Y}"
|
||||
).unwrap();
|
||||
|
||||
static ref OTHER_WIDE_DATE_YEAR: DateFormat<'static> = DateFormat::parse(
|
||||
"{2>:D} {:M} {5>:Y}"
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn short_month_width_japanese() {
|
||||
let max_month_width = 4;
|
||||
let month = "1\u{2F49}"; // 1月
|
||||
let padding = short_month_padding(max_month_width, month);
|
||||
let final_str = format!("{:<width$}", month, width = padding);
|
||||
assert_eq!(max_month_width, UnicodeWidthStr::width(final_str.as_str()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn short_month_width_hindi() {
|
||||
let max_month_width = 4;
|
||||
assert_eq!(true, [
|
||||
"\u{091C}\u{0928}\u{0970}", // जन॰
|
||||
"\u{092B}\u{093C}\u{0930}\u{0970}", // फ़र॰
|
||||
"\u{092E}\u{093E}\u{0930}\u{094D}\u{091A}", // मार्च
|
||||
"\u{0905}\u{092A}\u{094D}\u{0930}\u{0948}\u{0932}", // अप्रैल
|
||||
"\u{092E}\u{0908}", // मई
|
||||
"\u{091C}\u{0942}\u{0928}", // जून
|
||||
"\u{091C}\u{0941}\u{0932}\u{0970}", // जुल॰
|
||||
"\u{0905}\u{0917}\u{0970}", // अग॰
|
||||
"\u{0938}\u{093F}\u{0924}\u{0970}", // सित॰
|
||||
"\u{0905}\u{0915}\u{094D}\u{0924}\u{0942}\u{0970}", // अक्तू॰
|
||||
"\u{0928}\u{0935}\u{0970}", // नव॰
|
||||
"\u{0926}\u{093F}\u{0938}\u{0970}", // दिस॰
|
||||
].iter()
|
||||
.map(|month| format!(
|
||||
"{:<width$}",
|
||||
month,
|
||||
width = short_month_padding(max_month_width, month)
|
||||
)).all(|string| UnicodeWidthStr::width(string.as_str()) == max_month_width)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue