Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add a time style with better human readability #1202

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Expand Up @@ -32,6 +32,8 @@ term_grid = "0.2.0"
terminal_size = "0.1.16"
unicode-width = "0.1"
zoneinfo_compiled = "0.5.1"
chrono = "0.4.26"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the dependencies list should be sorted alphabetically.

chrono-humanize = "0.2.2"

[target.'cfg(unix)'.dependencies]
users = "0.11"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -89,7 +89,7 @@ Some of the options accept parameters:
- Valid **--color** options are **always**, **automatic**, and **never**.
- Valid sort fields are **accessed**, **changed**, **created**, **extension**, **Extension**, **inode**, **modified**, **name**, **Name**, **size**, **type**, and **none**. Fields starting with a capital letter sort uppercase before lowercase. The modified field has the aliases **date**, **time**, and **newest**, while its reverse has the aliases **age** and **oldest**.
- Valid time fields are **modified**, **changed**, **accessed**, and **created**.
- Valid time styles are **default**, **iso**, **long-iso**, and **full-iso**.
- Valid time styles are **default**, **iso**, **long-iso**, **full-iso** and **hu**.


---
Expand Down
2 changes: 1 addition & 1 deletion completions/bash/exa
Expand Up @@ -29,7 +29,7 @@ _exa()
;;

--time-style)
COMPREPLY=( $( compgen -W 'default iso long-iso full-iso --' -- "$cur" ) )
COMPREPLY=( $( compgen -W 'default iso long-iso full-iso hu --' -- "$cur" ) )
return
;;
esac
Expand Down
1 change: 1 addition & 0 deletions completions/fish/exa.fish
Expand Up @@ -79,6 +79,7 @@ complete -c exa -l 'time-style' -d "How to format timestamps" -x -a "
iso\t'Display brief ISO timestamps'
long-iso\t'Display longer ISO timestaps, up to the minute'
full-iso\t'Display full ISO timestamps, up to the nanosecond'
hu\t'Display more readable date forms for humans'
"
complete -c exa -l 'no-permissions' -d "Suppress the permissions field"
complete -c exa -l 'octal-permissions' -d "List each file's permission in octal format"
Expand Down
2 changes: 1 addition & 1 deletion completions/zsh/_exa
Expand Up @@ -43,7 +43,7 @@ __exa() {
{-n,--numeric}"[List numeric user and group IDs.]" \
{-S,--blocks}"[List each file's number of filesystem blocks]" \
{-t,--time}="[Which time field to show]:(time field):(accessed changed created modified)" \
--time-style="[How to format timestamps]:(time style):(default iso long-iso full-iso)" \
--time-style="[How to format timestamps]:(time style):(default iso long-iso full-iso hu)" \
--no-permissions"[Suppress the permissions field]" \
--octal-permissions"[List each file's permission in octal format]" \
--no-filesize"[Suppress the filesize field]" \
Expand Down
3 changes: 3 additions & 0 deletions src/options/view.rs
Expand Up @@ -266,6 +266,9 @@ impl TimeFormat {
else if &word == "full-iso" {
Ok(Self::FullISO)
}
else if &word == "hu" {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why hu instead of human or relative?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! I also thought that after seeing nushell, exa should have come up with the idea of this PR, which was a temporary idea, so I didn't think much about it. However, now It's better to use "human" or "relative" instead.

Ok(Self::Human)
}
else {
Err(OptionsError::BadArgument(&flags::TIME_STYLE, word))
}
Expand Down
22 changes: 21 additions & 1 deletion src/output/time.rs
Expand Up @@ -2,6 +2,7 @@

use std::time::{SystemTime, UNIX_EPOCH};

use chrono_humanize::HumanTime;
use datetime::{LocalDateTime, TimeZone, DatePiece, TimePiece};
use datetime::fmt::DateFormat;

Expand All @@ -24,7 +25,7 @@ use unicode_width::UnicodeWidthStr;
/// prints month names as numbers.
///
/// Currently exa does not support *custom* styles, where the user enters a
/// format string in an environment variable or something. Just these four.
/// format string in an environment variable or something. Just these five.
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum TimeFormat {

Expand All @@ -46,6 +47,10 @@ pub enum TimeFormat {
/// millisecond and includes its offset down to the minute. This too uses
/// only numbers so doesn’t require any special consideration.
FullISO,

/// The **Human format** converts the time form into a more human readable form,
/// such as one month ago, three weeks ago
Human,
}

// There are two different formatting functions because local and zoned
Expand All @@ -58,6 +63,7 @@ impl TimeFormat {
Self::ISOFormat => iso_local(time),
Self::LongISO => long_local(time),
Self::FullISO => full_local(time),
Self::Human => hu_local(time),
}
}

Expand All @@ -67,6 +73,7 @@ impl TimeFormat {
Self::ISOFormat => iso_zoned(time, zone),
Self::LongISO => long_zoned(time, zone),
Self::FullISO => full_zoned(time, zone),
Self::Human => hu_zoned(time, zone),
}
}
}
Expand Down Expand Up @@ -97,6 +104,19 @@ fn get_dateformat(date: &LocalDateTime) -> &'static DateFormat<'static> {
}
}

#[allow(trivial_numeric_casts)]
fn hu_local(time: SystemTime) -> String {
format!("{}", HumanTime::from(time))
}

#[allow(trivial_numeric_casts)]
fn hu_zoned(time: SystemTime, _: &TimeZone) -> String {

let dt: chrono::DateTime<chrono::Utc> = time.clone().into();
let tt: chrono::DateTime<chrono::Local> = dt.with_timezone(&chrono::Local);
format!("{}", HumanTime::from(tt))
}

#[allow(trivial_numeric_casts)]
fn long_local(time: SystemTime) -> String {
let date = LocalDateTime::at(systemtime_epoch(time));
Expand Down