diff --git a/Cargo.toml b/Cargo.toml index 3b7b327..4d2e14f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "simpledateformat" -version = "0.1.3" +version = "0.1.4" authors = ["Hatter Jiang "] edition = "2018" description = "SimpleDateFormat.java style like date format" diff --git a/src/lib.rs b/src/lib.rs index 03e4ddd..ad8f385 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,15 +1,16 @@ #[macro_use] extern crate quick_error; -use chrono::prelude::*; use std::{ convert::TryFrom, - time::Duration, - str::Chars, iter::Peekable, + str::Chars, + time::Duration, }; use std::time::SystemTime; +use chrono::prelude::*; + quick_error! { /// Format parse error #[derive(Debug)] @@ -82,6 +83,50 @@ pub fn format_human(d: Duration) -> String { return_ret(ret) } +/// Format duration for human read 2 +/// ```ignore +/// assert_eq!("2days 0hour 0min 1s", format_human(Duration::from_secs(2 * 24 * 60 * 60 + 1))); +/// ``` +pub fn format_human2(d: Duration) -> String { + let mut ret = vec![]; + let millis = d.as_millis(); + let original_millis = millis; + if millis == 0 { + return "0ms".into(); + } + let return_ret = |mut v: Vec| { + v.reverse(); + v.join(" ") + }; + let left_millis = millis % 1000; + if left_millis > 0 && original_millis < 60_000 { + ret.push(format!("{}ms", left_millis)) + } + let secs = millis / 1000; + if secs == 0 { return return_ret(ret); } + let left_secs = secs % 60; + if (left_secs != 0 || !ret.is_empty()) && original_millis < 3600_000 { + ret.push(format!("{}s", left_secs)); + } + let mins = secs / 60; + if mins == 0 { return return_ret(ret); } + let left_mins = mins % 60; + if (left_mins != 0 || !ret.is_empty()) && original_millis < 24 * 3600_000 { + ret.push(format!("{}min", left_mins)); + } + let hours = mins / 60; + if hours == 0 { return return_ret(ret); } + let left_hours = hours % 24; + if (left_hours != 0 || !ret.is_empty()) && original_millis < 30 * 24 * 3600_000 { + ret.push(format!("{}hour", left_hours)); + } + let days = hours / 24; + if days != 0 { + ret.push(format!("{}day{}", days, if days == 1 { "" } else { "s" })); + } + return_ret(ret) +} + pub fn get_local_now() -> DateTime { Local::now() } @@ -134,7 +179,7 @@ impl SimpleDateFormat { let mut ret = String::with_capacity(512); for part in &self.parts { - date_time.timezone(); + let _ = date_time.timezone(); match part { SimpleDateFormatPart::Ear => ret.push_str("AD"), // ? SimpleDateFormatPart::LiteralChar(c) => ret.push(*c), diff --git a/tests/lib_test.rs b/tests/lib_test.rs index 9735f59..d84b693 100644 --- a/tests/lib_test.rs +++ b/tests/lib_test.rs @@ -1,25 +1,25 @@ -use simpledateformat::{ SimpleDateFormat, fmt, format_human, }; +use simpledateformat::{SimpleDateFormat, fmt, format_human, format_human2}; use chrono::prelude::*; use std::time::Duration; #[test] fn test_simpledateformat_format() { - let t = Utc.timestamp_millis(0); + let t = Utc.timestamp_millis_opt(0).unwrap(); assert_eq!("1970/01/01 00:00:00.000 Z", &fmt("yyyy/MM/dd HH:mm:ss.SSS z").unwrap().format(&t)); - let t = Utc.timestamp_millis(1111111111); + let t = Utc.timestamp_millis_opt(1111111111).unwrap(); assert_eq!("1970/01/13 20:38:31.111 Z", &fmt("yyyy/MM/dd HH:mm:ss.SSS z").unwrap().format(&t)); - let t = Utc.timestamp_millis(1111111111); + let t = Utc.timestamp_millis_opt(1111111111).unwrap(); assert_eq!("1970/01/13 08:38:31.111 Z PM", &fmt("yyyy/MM/dd hh:mm:ss.SSS z a").unwrap().format(&t)); - let t = Utc.timestamp_millis(1590816448678); + let t = Utc.timestamp_millis_opt(1590816448678).unwrap(); assert_eq!("2020/05/30 05:27:28.678 Z AM", &fmt("yyyy/MM/dd hh:mm:ss.SSS z a").unwrap().format(&t)); - let t = Utc.timestamp_millis(1590816448678); + let t = Utc.timestamp_millis_opt(1590816448678).unwrap(); assert_eq!("Sat May 30, 2020 05:27:28.678 Z AM", &fmt("EEE MMM dd, yyyy hh:mm:ss.SSS z a").unwrap().format(&t)); - let t = Local.timestamp_millis(1590816448678); + let t = Local.timestamp_millis_opt(1590816448678).unwrap(); assert_eq!("Sat May 30, 2020 01:27:28.678 +08:00 PM", &fmt("EEE MMM dd, yyyy hh:mm:ss.SSS z a").unwrap().format(&t)); } @@ -36,10 +36,28 @@ fn test_format_human() { assert_eq!("2days 0hour 0min 1s", format_human(Duration::from_secs(2 * 24 * 60 * 60 + 1))); } +#[test] +fn test_format_human2() { + assert_eq!("0ms", format_human2(Duration::from_millis(0))); + assert_eq!("11ms", format_human2(Duration::from_millis(11))); + assert_eq!("11s 111ms", format_human2(Duration::from_millis(11111))); + assert_eq!("1s", format_human2(Duration::from_secs(1))); + assert_eq!("1min", format_human2(Duration::from_secs(60))); + assert_eq!("1min 1s", format_human2(Duration::from_secs(61))); + assert_eq!("1hour", format_human2(Duration::from_secs(60 * 60))); + assert_eq!("1hour 1min", format_human2(Duration::from_secs(61 * 60))); + assert_eq!("1day", format_human2(Duration::from_secs(24 * 60 * 60))); + assert_eq!("2days", format_human2(Duration::from_secs(2 * 24 * 60 * 60))); + assert_eq!("2days", format_human2(Duration::from_secs(2 * 24 * 60 * 60 + 1))); + assert_eq!("2days 1hour", format_human2(Duration::from_secs(2 * 24 * 61 * 60 + 3600 + 1))); + assert_eq!("29days 12hour", format_human2(Duration::from_secs(29 * 24 * 61 * 60 + 3600 + 1))); + assert_eq!("40days", format_human2(Duration::from_secs(40 * 24 * 61 * 60 + 3600 + 1))); +} + #[test] fn test_try_from() { use std::convert::TryInto; - let t = Utc.timestamp_millis(0); + let t = Utc.timestamp_millis_opt(0).unwrap(); let fmt = "yyyy/MM/dd HH:mm:ss.SSS z"; let sdf: Result = fmt.try_into(); assert_eq!("1970/01/01 00:00:00.000 Z", sdf.unwrap().format(&t));