mirror of
https://github.com/eza-community/eza.git
synced 2025-08-04 09:00:20 +00:00
feat: use chrono crate to handle datetime-related features
- Improve compatibility with other OSes, timezone are handled for us - Reduce significantly the code to render date and time
This commit is contained in:
parent
0d118d3bfa
commit
d1c9e9ddec
7 changed files with 315 additions and 308 deletions
204
Cargo.lock
generated
204
Cargo.lock
generated
|
@ -2,6 +2,21 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
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]]
|
[[package]]
|
||||||
name = "ansiterm"
|
name = "ansiterm"
|
||||||
version = "0.12.2"
|
version = "0.12.2"
|
||||||
|
@ -29,6 +44,12 @@ version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bumpalo"
|
||||||
|
version = "3.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.4.3"
|
version = "1.4.3"
|
||||||
|
@ -44,6 +65,33 @@ dependencies = [
|
||||||
"jobserver",
|
"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]]
|
[[package]]
|
||||||
name = "datetime"
|
name = "datetime"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
|
@ -51,8 +99,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44c3f7a77f3e57fedf80e09136f2d8777ebf621207306f6d96d610af048354bc"
|
checksum = "44c3f7a77f3e57fedf80e09136f2d8777ebf621207306f6d96d610af048354bc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"locale",
|
|
||||||
"pad",
|
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
@ -83,7 +129,7 @@ name = "eza"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansiterm",
|
"ansiterm",
|
||||||
"datetime",
|
"chrono",
|
||||||
"gethostname",
|
"gethostname",
|
||||||
"git2",
|
"git2",
|
||||||
"glob",
|
"glob",
|
||||||
|
@ -142,9 +188,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glob"
|
name = "glob"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
|
@ -152,6 +198,29 @@ version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
|
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]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
|
@ -183,6 +252,15 @@ dependencies = [
|
||||||
"libc",
|
"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]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -253,6 +331,15 @@ version = "1.0.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "308d96db8debc727c3fd9744aac51751243420e46edf401010908da7f8d5e57c"
|
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]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
|
@ -269,6 +356,12 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-src"
|
name = "openssl-src"
|
||||||
version = "111.26.0+1.1.1u"
|
version = "111.26.0+1.1.1u"
|
||||||
|
@ -292,15 +385,6 @@ dependencies = [
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pad"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d2ad9b889f1b12e0b9ee24db044b5129150d5eada288edc800f789928dc8c0e3"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-width",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "partition-identity"
|
name = "partition-identity"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -440,9 +524,9 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.31"
|
version = "2.0.29"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
|
checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -470,24 +554,35 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.47"
|
version = "1.0.48"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
|
checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.47"
|
version = "1.0.48"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
|
checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"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]]
|
[[package]]
|
||||||
name = "timeago"
|
name = "timeago"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
@ -573,6 +668,66 @@ version = "0.2.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cbdbff6266a24120518560b5dc983096efb98462e51d0d68169895b237be3e5d"
|
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]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
@ -595,6 +750,15 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
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]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -38,6 +38,7 @@ name = "eza"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ansiterm = "0.12.2"
|
ansiterm = "0.12.2"
|
||||||
gethostname = "0.4.3"
|
gethostname = "0.4.3"
|
||||||
|
chrono = "0.4"
|
||||||
glob = "0.3"
|
glob = "0.3"
|
||||||
lazy_static = "1.3"
|
lazy_static = "1.3"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
|
@ -55,11 +56,6 @@ unicode-width = "0.1"
|
||||||
urlencoding = "2.1.3"
|
urlencoding = "2.1.3"
|
||||||
zoneinfo_compiled = "0.5.1"
|
zoneinfo_compiled = "0.5.1"
|
||||||
|
|
||||||
[dependencies.datetime]
|
|
||||||
version = "0.5.2"
|
|
||||||
default-features = false
|
|
||||||
features = ["format"]
|
|
||||||
|
|
||||||
[dependencies.git2]
|
[dependencies.git2]
|
||||||
version = "0.18"
|
version = "0.18"
|
||||||
optional = true
|
optional = true
|
||||||
|
@ -71,9 +67,8 @@ proc-mounts = "0.3"
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
uzers = "0.11.2"
|
uzers = "0.11.2"
|
||||||
|
|
||||||
[build-dependencies.datetime]
|
[build-dependencies]
|
||||||
version = "0.5.2"
|
chrono = "0.4"
|
||||||
default-features = false
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ "git" ]
|
default = [ "git" ]
|
||||||
|
|
6
build.rs
6
build.rs
|
@ -15,7 +15,7 @@ use std::fs::File;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use datetime::{LocalDateTime, ISO};
|
use chrono::prelude::*;
|
||||||
|
|
||||||
|
|
||||||
/// The build script entry point.
|
/// The build script entry point.
|
||||||
|
@ -118,6 +118,6 @@ fn nonstandard_features_string() -> String {
|
||||||
|
|
||||||
/// Formats the current date as an ISO 8601 string.
|
/// Formats the current date as an ISO 8601 string.
|
||||||
fn build_date() -> String {
|
fn build_date() -> String {
|
||||||
let now = LocalDateTime::now();
|
let now = Local::now();
|
||||||
format!("{}", now.date().iso())
|
now.date_naive().format("%Y-%m-%d").to_string()
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,8 @@ use std::os::unix::fs::{FileTypeExt, MetadataExt, PermissionsExt};
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use std::os::windows::fs::MetadataExt;
|
use std::os::windows::fs::MetadataExt;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::time::SystemTime;
|
|
||||||
#[cfg(unix)]
|
use chrono::prelude::*;
|
||||||
use std::time::{Duration, UNIX_EPOCH};
|
|
||||||
|
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|
||||||
|
@ -536,42 +535,29 @@ impl<'dir> File<'dir> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This file’s last modified timestamp, if available on this platform.
|
/// 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 {
|
if self.is_link() && self.deref_links {
|
||||||
match self.link_target_recurse() {
|
return match self.link_target_recurse() {
|
||||||
FileTarget::Ok(f) => f.metadata.modified().ok(),
|
FileTarget::Ok(f) => f.modified_time(),
|
||||||
_ => None,
|
_ => 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.
|
/// This file’s last changed timestamp, if available on this platform.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub fn changed_time(&self) -> Option<SystemTime> {
|
pub fn changed_time(&self) -> Option<NaiveDateTime> {
|
||||||
if self.is_link() && self.deref_links {
|
if self.is_link() && self.deref_links {
|
||||||
match self.link_target_recurse() {
|
return match self.link_target_recurse() {
|
||||||
FileTarget::Ok(f) => return f.changed_time(),
|
FileTarget::Ok(f) => f.changed_time(),
|
||||||
_ => return None,
|
_ => 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)
|
|
||||||
}
|
}
|
||||||
|
NaiveDateTime::from_timestamp_opt(
|
||||||
|
self.metadata.ctime(),
|
||||||
|
self.metadata.ctime_nsec() as u32,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
@ -580,27 +566,25 @@ impl<'dir> File<'dir> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This file’s last accessed timestamp, if available on this platform.
|
/// 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 {
|
if self.is_link() && self.deref_links {
|
||||||
match self.link_target_recurse() {
|
return match self.link_target_recurse() {
|
||||||
FileTarget::Ok(f) => f.metadata.accessed().ok(),
|
FileTarget::Ok(f) => f.accessed_time(),
|
||||||
_ => None,
|
_ => 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.
|
/// 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 {
|
if self.is_link() && self.deref_links {
|
||||||
match self.link_target_recurse() {
|
return match self.link_target_recurse() {
|
||||||
FileTarget::Ok(f) => f.metadata.created().ok(),
|
FileTarget::Ok(f) => f.created_time(),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
};
|
||||||
} else {
|
|
||||||
self.metadata.created().ok()
|
|
||||||
}
|
}
|
||||||
|
self.metadata.created().map(|st| DateTime::<Utc>::from(st).naive_utc()).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This file’s ‘type’.
|
/// 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::cell::TextCell;
|
||||||
use crate::output::time::TimeFormat;
|
use crate::output::time::TimeFormat;
|
||||||
|
|
||||||
|
use ansiterm::Style;
|
||||||
|
use chrono::prelude::*;
|
||||||
|
|
||||||
|
|
||||||
pub trait Render {
|
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> {
|
impl Render for Option<NaiveDateTime> {
|
||||||
fn render(self, style: Style, tz: &Option<TimeZone>, format: TimeFormat) -> TextCell {
|
fn render(self, style: Style, time_offset: FixedOffset, time_format: TimeFormat) -> TextCell {
|
||||||
let datestamp = if let Some(time) = self {
|
let datestamp = if let Some(time) = self {
|
||||||
if let Some(ref tz) = tz {
|
time_format.format(&DateTime::<FixedOffset>::from_naive_utc_and_offset(time, time_offset))
|
||||||
format.format_zoned(time, tz)
|
} else {
|
||||||
}
|
|
||||||
else {
|
|
||||||
format.format_local(time)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
String::from("-")
|
String::from("-")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,9 @@
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
#[cfg(unix)]
|
|
||||||
use std::env;
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use std::sync::{Mutex, MutexGuard};
|
use std::sync::{Mutex, MutexGuard};
|
||||||
|
|
||||||
use datetime::TimeZone;
|
use chrono::prelude::*;
|
||||||
#[cfg(unix)]
|
|
||||||
use zoneinfo_compiled::CompiledData;
|
|
||||||
use zoneinfo_compiled::Result as TZResult;
|
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use log::*;
|
use log::*;
|
||||||
|
@ -336,13 +331,12 @@ impl Default for TimeTypes {
|
||||||
/// Any environment field should be able to be mocked up for test runs.
|
/// Any environment field should be able to be mocked up for test runs.
|
||||||
pub struct Environment {
|
pub struct Environment {
|
||||||
|
|
||||||
|
/// The computer’s current time offset, determined from time zone.
|
||||||
|
time_offset: FixedOffset,
|
||||||
|
|
||||||
/// Localisation rules for formatting numbers.
|
/// Localisation rules for formatting numbers.
|
||||||
numeric: locale::Numeric,
|
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.
|
/// Mapping cache of user IDs to usernames.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
users: Mutex<UsersCache>,
|
users: Mutex<UsersCache>,
|
||||||
|
@ -355,15 +349,7 @@ impl Environment {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_all() -> Self {
|
fn load_all() -> Self {
|
||||||
let tz = match determine_time_zone() {
|
let time_offset = *Local::now().offset();
|
||||||
Ok(t) => {
|
|
||||||
Some(t)
|
|
||||||
}
|
|
||||||
Err(ref e) => {
|
|
||||||
eprintln!("Unable to determine time zone: {e}");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let numeric = locale::Numeric::load_user_locale()
|
let numeric = locale::Numeric::load_user_locale()
|
||||||
.unwrap_or_else(|_| locale::Numeric::english());
|
.unwrap_or_else(|_| locale::Numeric::english());
|
||||||
|
@ -371,28 +357,7 @@ impl Environment {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
let users = Mutex::new(UsersCache::new());
|
let users = Mutex::new(UsersCache::new());
|
||||||
|
|
||||||
Self { numeric, tz, #[cfg(unix)] users }
|
Self { time_offset, numeric, 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")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,16 +526,16 @@ impl<'a> Table<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Column::Timestamp(TimeType::Modified) => {
|
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) => {
|
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) => {
|
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) => {
|
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.
|
//! Timestamp formatting.
|
||||||
|
|
||||||
use std::convert::TryInto;
|
use core::cmp::max;
|
||||||
use std::cmp::max;
|
use std::time::Duration;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH, Duration};
|
use chrono::prelude::*;
|
||||||
|
|
||||||
use datetime::{LocalDateTime, TimeZone, DatePiece, TimePiece, Instant};
|
|
||||||
use datetime::fmt::DateFormat;
|
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
|
@ -53,80 +49,59 @@ pub enum TimeFormat {
|
||||||
Relative,
|
Relative,
|
||||||
}
|
}
|
||||||
|
|
||||||
// There are two different formatting functions because local and zoned
|
|
||||||
// timestamps are separate types.
|
|
||||||
|
|
||||||
impl TimeFormat {
|
impl TimeFormat {
|
||||||
pub fn format_local(self, time: SystemTime) -> String {
|
pub fn format(self, time: &DateTime<FixedOffset>) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::DefaultFormat => default_local(time),
|
Self::DefaultFormat => default(time),
|
||||||
Self::ISOFormat => iso_local(time),
|
Self::ISOFormat => iso(time),
|
||||||
Self::LongISO => long_local(time),
|
Self::LongISO => long(time),
|
||||||
Self::FullISO => full_local(time),
|
Self::FullISO => full(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::Relative => relative(time),
|
Self::Relative => relative(time),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default(time: &DateTime<FixedOffset>) -> String {
|
||||||
#[allow(trivial_numeric_casts)]
|
let month = &*LOCALE.short_month_name(time.month0() as usize);
|
||||||
fn default_local(time: SystemTime) -> String {
|
let month_width = short_month_padding(*MAX_MONTH_WIDTH, month);
|
||||||
let date = LocalDateTime::at(systemtime_epoch(time));
|
let format = if time.year() == *CURRENT_YEAR {
|
||||||
let date_format = get_dateformat(&date);
|
format!("%_d {month:<month_width$} %H:%M")
|
||||||
date_format.format(&date, &LOCALE)
|
} else {
|
||||||
|
format!("%_d {month:<month_width$} %Y")
|
||||||
|
};
|
||||||
|
time.format(format.as_str()).to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(trivial_numeric_casts)]
|
/// Convert between Unicode width and width in chars to use in format!.
|
||||||
fn default_zoned(time: SystemTime, zone: &TimeZone) -> String {
|
/// ex: in Japanese, 月 is one character, but it has the width of two.
|
||||||
let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time)));
|
/// For alignement purposes, we take the real display width into account.
|
||||||
let date_format = get_dateformat(&date);
|
/// So, `MAXIMUM_MONTH_WIDTH` (“12月”) = 4, but if we use `{:4}` in format!,
|
||||||
date_format.format(&date, &LOCALE)
|
/// 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> {
|
fn iso(time: &DateTime<FixedOffset>) -> String {
|
||||||
match (is_recent(date), *MAXIMUM_MONTH_WIDTH) {
|
if time.year() == *CURRENT_YEAR {
|
||||||
(true, 4) => &FOUR_WIDE_DATE_TIME,
|
time.format("%m-%d %H:%M").to_string()
|
||||||
(true, 5) => &FIVE_WIDE_DATE_TIME,
|
} else {
|
||||||
(true, _) => &OTHER_WIDE_DATE_TIME,
|
time.format("%Y-%m-%d").to_string()
|
||||||
(false, 4) => &FOUR_WIDE_DATE_YEAR,
|
|
||||||
(false, 5) => &FIVE_WIDE_DATE_YEAR,
|
|
||||||
(false, _) => &OTHER_WIDE_DATE_YEAR,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(trivial_numeric_casts)]
|
fn long(time: &DateTime<FixedOffset>) -> String {
|
||||||
fn long_local(time: SystemTime) -> String {
|
time.format("%Y-%m-%d %H:%M").to_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())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(trivial_numeric_casts)]
|
// #[allow(trivial_numeric_casts)]
|
||||||
fn long_zoned(time: SystemTime, zone: &TimeZone) -> String {
|
fn relative(time: &DateTime<FixedOffset>) -> 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 {
|
|
||||||
timeago::Formatter::new()
|
timeago::Formatter::new()
|
||||||
.ago("")
|
.ago("")
|
||||||
.convert(
|
.convert(
|
||||||
Duration::from_secs(
|
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
|
// this .unwrap is safe since the call above can never result in a
|
||||||
// value < 0
|
// value < 0
|
||||||
.try_into().unwrap()
|
.try_into().unwrap()
|
||||||
|
@ -134,131 +109,63 @@ fn relative(time: SystemTime) -> String {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(trivial_numeric_casts)]
|
fn full(time: &DateTime<FixedOffset>) -> String {
|
||||||
fn full_local(time: SystemTime) -> String {
|
time.format("%Y-%m-%d %H:%M:%S.%f %z").to_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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
|
||||||
static ref CURRENT_YEAR: i64 = LocalDateTime::now().year();
|
static ref CURRENT_YEAR: i32 = Local::now().year();
|
||||||
|
|
||||||
static ref LOCALE: locale::Time = {
|
static ref LOCALE: locale::Time = {
|
||||||
locale::Time::load_user_locale()
|
locale::Time::load_user_locale()
|
||||||
.unwrap_or_else(|_| locale::Time::english())
|
.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);
|
// 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
|
// 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.
|
// to detect the longest and set the output format accordingly.
|
||||||
let mut maximum_month_width = 0;
|
(0..11).map(|i| UnicodeWidthStr::width(&*LOCALE.short_month_name(i))).max().unwrap()
|
||||||
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
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
static ref FOUR_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse(
|
|
||||||
"{2>:D} {4<:M} {02>:h}:{02>:m}"
|
#[cfg(test)]
|
||||||
).unwrap();
|
mod test {
|
||||||
|
use super::*;
|
||||||
static ref FIVE_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse(
|
|
||||||
"{2>:D} {5<:M} {02>:h}:{02>:m}"
|
#[test]
|
||||||
).unwrap();
|
fn short_month_width_japanese() {
|
||||||
|
let max_month_width = 4;
|
||||||
static ref OTHER_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse(
|
let month = "1\u{2F49}"; // 1月
|
||||||
"{2>:D} {:M} {02>:h}:{02>:m}"
|
let padding = short_month_padding(max_month_width, month);
|
||||||
).unwrap();
|
let final_str = format!("{:<width$}", month, width = padding);
|
||||||
|
assert_eq!(max_month_width, UnicodeWidthStr::width(final_str.as_str()));
|
||||||
static ref FOUR_WIDE_DATE_YEAR: DateFormat<'static> = DateFormat::parse(
|
}
|
||||||
"{2>:D} {4<:M} {5>:Y}"
|
|
||||||
).unwrap();
|
#[test]
|
||||||
|
fn short_month_width_hindi() {
|
||||||
static ref FIVE_WIDE_DATE_YEAR: DateFormat<'static> = DateFormat::parse(
|
let max_month_width = 4;
|
||||||
"{2>:D} {5<:M} {5>:Y}"
|
assert_eq!(true, [
|
||||||
).unwrap();
|
"\u{091C}\u{0928}\u{0970}", // जन॰
|
||||||
|
"\u{092B}\u{093C}\u{0930}\u{0970}", // फ़र॰
|
||||||
static ref OTHER_WIDE_DATE_YEAR: DateFormat<'static> = DateFormat::parse(
|
"\u{092E}\u{093E}\u{0930}\u{094D}\u{091A}", // मार्च
|
||||||
"{2>:D} {:M} {5>:Y}"
|
"\u{0905}\u{092A}\u{094D}\u{0930}\u{0948}\u{0932}", // अप्रैल
|
||||||
).unwrap();
|
"\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…
Add table
Add a link
Reference in a new issue