From 69a6fea3716363d62b88a34d987b686edfe3e46b Mon Sep 17 00:00:00 2001 From: Thaumy Date: Wed, 20 Sep 2023 18:04:55 +0800 Subject: [PATCH] feat: friendly time display --- src/display/colorful.rs | 35 ++++++++++++++++++----------------- src/display/normal.rs | 29 +++++++++++++++++------------ src/infra/time.rs | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 29 deletions(-) diff --git a/src/display/colorful.rs b/src/display/colorful.rs index 14ddae3..bbdcd75 100644 --- a/src/display/colorful.rs +++ b/src/display/colorful.rs @@ -9,9 +9,9 @@ use crate::api::post::get_one::PostEntry; use crate::api::user::info::UserInfo; use crate::infra::iter::IteratorExt; use crate::infra::str::StrExt; -use crate::infra::time::patch_rfc3339; +use crate::infra::time::{fmt_time_to_string_friendly, patch_rfc3339}; use anyhow::Result; -use chrono::DateTime; +use chrono::{DateTime, Local, Utc}; use colored::Colorize; use std::fmt::Display; use std::ops::Not; @@ -70,8 +70,9 @@ pub fn list_ing( let create_time = { let rfc3339 = patch_rfc3339(&ing.create_time); let dt = DateTime::parse_from_rfc3339(&rfc3339) - .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)); - dt.format("%m-%d %H:%M").to_string() + .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)) + .with_timezone(&Utc); + fmt_time_to_string_friendly(dt.into(), Local::now()) }; print!("{}", create_time.dimmed()); @@ -188,15 +189,17 @@ pub fn show_post_meta(entry: &Result) { let create_time = { let rfc3339 = patch_rfc3339(&entry.create_time); let dt = DateTime::parse_from_rfc3339(&rfc3339) - .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)); - dt.format("%Y-%m-%d %H:%M") + .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)) + .with_timezone(&Utc); + fmt_time_to_string_friendly(dt.into(), Local::now()) }; println!("Create {}", create_time); let modify_time = { let rfc3339 = patch_rfc3339(&entry.modify_time); let dt = DateTime::parse_from_rfc3339(&rfc3339) - .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)); - dt.format("%Y-%m-%d %H:%M") + .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)) + .with_timezone(&Utc); + fmt_time_to_string_friendly(dt.into(), Local::now()) }; println!("Modify {}", modify_time); println!("Link https:{}", entry.url); @@ -212,15 +215,12 @@ pub fn show_post_comment(comment_list: &Result>, rev: bool let create_time = { let rfc3339 = patch_rfc3339(&comment.create_time); let dt = DateTime::parse_from_rfc3339(&rfc3339) - .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)); - dt.format("%Y-%m-%d %H:%M") + .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)) + .with_timezone(&Utc); + fmt_time_to_string_friendly(dt.into(), Local::now()) }; let floor_text = format!("{}F", comment.floor); - println!( - "{} {}", - create_time.to_string().dimmed(), - floor_text.dimmed() - ); + println!("{} {}", create_time.dimmed(), floor_text.dimmed()); println!(" {} {}", comment.user_name.cyan(), comment.content); }) } @@ -281,8 +281,9 @@ pub fn list_news(news_list: &Result>, rev: bool) { let create_time = { let rfc3339 = patch_rfc3339(&news.create_time); let dt = DateTime::parse_from_rfc3339(&rfc3339) - .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)); - dt.format("%Y-%m-%d %H:%M").to_string() + .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)) + .with_timezone(&Utc); + fmt_time_to_string_friendly(dt.into(), Local::now()) }; let url = format!("https://news.cnblogs.com/n/{}", news.id); diff --git a/src/display/normal.rs b/src/display/normal.rs index 3b6c60a..efca02e 100644 --- a/src/display/normal.rs +++ b/src/display/normal.rs @@ -9,9 +9,9 @@ use crate::api::post::get_one::PostEntry; use crate::api::user::info::UserInfo; use crate::infra::iter::IteratorExt; use crate::infra::str::StrExt; -use crate::infra::time::patch_rfc3339; +use crate::infra::time::{fmt_time_to_string_friendly, patch_rfc3339}; use anyhow::Result; -use chrono::DateTime; +use chrono::{DateTime, Local, Utc}; use colored::Colorize; use std::fmt::Display; use std::ops::Not; @@ -70,8 +70,9 @@ pub fn list_ing( let create_time = { let rfc3339 = patch_rfc3339(&ing.create_time); let dt = DateTime::parse_from_rfc3339(&rfc3339) - .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)); - dt.format("%m-%d %H:%M") + .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)) + .with_timezone(&Utc); + fmt_time_to_string_friendly(dt.into(), Local::now()) }; print!("{}", create_time); @@ -188,15 +189,17 @@ pub fn show_post_meta(entry: &Result) { let create_time = { let rfc3339 = patch_rfc3339(&entry.create_time); let dt = DateTime::parse_from_rfc3339(&rfc3339) - .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)); - dt.format("%Y-%m-%d %H:%M") + .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)) + .with_timezone(&Utc); + fmt_time_to_string_friendly(dt.into(), Local::now()) }; println!("Create {}", create_time); let modify_time = { let rfc3339 = patch_rfc3339(&entry.modify_time); let dt = DateTime::parse_from_rfc3339(&rfc3339) - .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)); - dt.format("%Y-%m-%d %H:%M") + .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)) + .with_timezone(&Utc); + fmt_time_to_string_friendly(dt.into(), Local::now()) }; println!("Modify {}", modify_time); println!("Link https:{}", entry.url); @@ -212,8 +215,9 @@ pub fn show_post_comment(comment_list: &Result>, rev: bool let create_time = { let rfc3339 = patch_rfc3339(&comment.create_time); let dt = DateTime::parse_from_rfc3339(&rfc3339) - .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)); - dt.format("%Y-%m-%d %H:%M") + .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)) + .with_timezone(&Utc); + fmt_time_to_string_friendly(dt.into(), Local::now()) }; println!("{} {}F", create_time, comment.floor); println!(" {} {}", comment.user_name, comment.content); @@ -276,8 +280,9 @@ pub fn list_news(news_list: &Result>, rev: bool) { let create_time = { let rfc3339 = patch_rfc3339(&news.create_time); let dt = DateTime::parse_from_rfc3339(&rfc3339) - .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)); - dt.format("%Y-%m-%d %H:%M") + .unwrap_or_else(|_| panic!("Invalid RFC3339: {}", rfc3339)) + .with_timezone(&Utc); + fmt_time_to_string_friendly(dt.into(), Local::now()) }; let url = format!("https://news.cnblogs.com/n/{}", news.id); diff --git a/src/infra/time.rs b/src/infra/time.rs index 0de4956..8331612 100644 --- a/src/infra/time.rs +++ b/src/infra/time.rs @@ -1,3 +1,6 @@ +use chrono::{DateTime, Datelike, TimeZone, Timelike}; +use std::fmt::Display; + // HACK: // Sometimes cnblogs' web API returns time string like: "2023-09-12T14:07:00" or "2019-02-06T08:45:53.94" // This will patch it to standard RFC3339 format @@ -13,3 +16,39 @@ pub fn patch_rfc3339(time_str: &str) -> String { time_str.to_owned() } } + +pub fn fmt_time_to_string_friendly(time_to_fmt: DateTime, current_time: DateTime) -> String +where + T: TimeZone, + ::Offset: Display, +{ + let diff = current_time.clone() - time_to_fmt.clone(); + match diff { + // In the future + _ if diff.num_milliseconds() < 0 => time_to_fmt.format("%Y-%m-%d %H:%M").to_string(), + // Same year... + _ if time_to_fmt.year() != current_time.year() => { + time_to_fmt.format("%Y-%m-%d").to_string() + } + _ if time_to_fmt.month() != current_time.month() => { + time_to_fmt.format("%m-%d %H:%M").to_string() + } + _ if time_to_fmt.day() != current_time.day() => { + let postfix = match time_to_fmt.day() { + 1 => "st", + 2 => "nd", + 3 => "rd", + _ => "th", + }; + time_to_fmt + .format(&format!("%d{} %H:%M", postfix)) + .to_string() + } + _ if time_to_fmt.hour() != current_time.hour() => time_to_fmt.format("%H:%M").to_string(), + // Within an hour + _ if diff.num_seconds() < 30 => "Now".to_owned(), + _ if diff.num_minutes() < 3 => "Recently".to_owned(), + _ if diff.num_minutes() < 30 => format!("{}m", diff.num_minutes()), + _ => time_to_fmt.format("%H:%M").to_string(), + } +}