Skip to content

Commit a330f4a

Browse files
drspxalkk-ds
andauthored
Add a relative format similar to git graph (#103)
git log --graph has a format which tells me how long time ago a change was made. it makes it a little bit easy to look for changes. e.g. `git log --graph --abbrev-commit --decorate --format=format:'(%ar)' --all` Co-authored-by: Alexander Kjeldsen <alkk@danskespil.dk>
1 parent fd162df commit a330f4a

2 files changed

Lines changed: 60 additions & 8 deletions

File tree

docs/manual.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,10 +192,12 @@ Formatting strings use a subset of the placeholders available in `git log --form
192192
| %ae | author email |
193193
| %ad | author date |
194194
| %as | author date in short format `YYYY-MM-DD` |
195+
| %ar | author date, relative format (e.g., "21 hours ago") |
195196
| %cn | committer name |
196197
| %ce | committer email |
197198
| %cd | committer date |
198199
| %cs | committer date in short format `YYYY-MM-DD` |
200+
| %cr | committer date, relative format (e.g., "4 days ago") |
199201

200202
If you add a '+' (plus sign) after % of a placeholder, a line-feed is inserted immediately before the expansion if and only if the placeholder expands to a non-empty string.
201203

src/print/format.rs

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,14 @@ const AUTHOR: usize = 7;
4343
const AUTHOR_EMAIL: usize = 8;
4444
const AUTHOR_DATE: usize = 9;
4545
const AUTHOR_DATE_SHORT: usize = 10;
46-
const COMMITTER: usize = 11;
47-
const COMMITTER_EMAIL: usize = 12;
48-
const COMMITTER_DATE: usize = 13;
49-
const COMMITTER_DATE_SHORT: usize = 14;
50-
const BODY: usize = 15;
51-
const BODY_RAW: usize = 16;
46+
const AUTHOR_DATE_RELATIVE: usize = 11;
47+
const COMMITTER: usize = 12;
48+
const COMMITTER_EMAIL: usize = 13;
49+
const COMMITTER_DATE: usize = 14;
50+
const COMMITTER_DATE_SHORT: usize = 15;
51+
const COMMITTER_DATE_RELATIVE: usize = 16;
52+
const BODY: usize = 17;
53+
const BODY_RAW: usize = 18;
5254

5355
const MODE_SPACE: usize = 1;
5456
const MODE_PLUS: usize = 2;
@@ -57,8 +59,8 @@ const MODE_MINUS: usize = 3;
5759
lazy_static! {
5860
pub static ref PLACEHOLDERS: Vec<[String; 4]> = {
5961
let base = vec![
60-
"n", "H", "h", "P", "p", "d", "s", "an", "ae", "ad", "as", "cn", "ce", "cd", "cs", "b",
61-
"B",
62+
"n", "H", "h", "P", "p", "d", "s", "an", "ae", "ad", "as", "ar", "cn", "ce", "cd",
63+
"cs", "cr", "b", "B",
6264
];
6365
base.iter()
6466
.map(|b| {
@@ -260,6 +262,14 @@ pub fn format_commit(
260262
}
261263
write!(out, "{}", format_date(commit.author().when(), "%F"))
262264
}
265+
AUTHOR_DATE_RELATIVE => {
266+
match mode {
267+
MODE_SPACE => write!(out, " ").unwrap(),
268+
MODE_PLUS => add_line(&mut lines, &mut out, wrapping),
269+
_ => {}
270+
}
271+
write!(out, "{}", format_relative_time(commit.author().when()))
272+
}
263273
COMMITTER => {
264274
match mode {
265275
MODE_SPACE => write!(out, " ").unwrap(),
@@ -296,6 +306,14 @@ pub fn format_commit(
296306
}
297307
write!(out, "{}", format_date(commit.committer().when(), "%F"))
298308
}
309+
COMMITTER_DATE_RELATIVE => {
310+
match mode {
311+
MODE_SPACE => write!(out, " ").unwrap(),
312+
MODE_PLUS => add_line(&mut lines, &mut out, wrapping),
313+
_ => {}
314+
}
315+
write!(out, "{}", format_relative_time(commit.committer().when()))
316+
}
299317
BODY => {
300318
let message = commit
301319
.message()
@@ -517,6 +535,38 @@ pub fn format_date(time: Time, format: &str) -> String {
517535
format!("{}", date.format(format))
518536
}
519537

538+
/// Format a time as a relative time string (e.g., "21 hours ago", "4 days ago")
539+
pub fn format_relative_time(time: Time) -> String {
540+
let commit_time =
541+
Local::from_offset(&FixedOffset::east(time.offset_minutes())).timestamp(time.seconds(), 0);
542+
let now = Local::now();
543+
let duration = now.signed_duration_since(commit_time);
544+
545+
let seconds = duration.num_seconds();
546+
let minutes = duration.num_minutes();
547+
let hours = duration.num_hours();
548+
let days = duration.num_hours() / 24;
549+
let weeks = days / 7;
550+
let months = days / 30;
551+
let years = days / 365;
552+
553+
if seconds < 60 {
554+
format!("{} seconds ago", seconds)
555+
} else if minutes < 60 {
556+
format!("{} minutes ago", minutes)
557+
} else if hours < 24 {
558+
format!("{} hours ago", hours)
559+
} else if days < 7 {
560+
format!("{} days ago", days)
561+
} else if weeks < 4 {
562+
format!("{} weeks ago", weeks)
563+
} else if months < 12 {
564+
format!("{} months ago", months)
565+
} else {
566+
format!("{} years ago", years)
567+
}
568+
}
569+
520570
fn append_wrapped(vec: &mut Vec<String>, str: String, wrapping: &Option<Options>) {
521571
if str.is_empty() {
522572
vec.push(str);

0 commit comments

Comments
 (0)