Rust时间格式化库fancy-duration的使用,提供优雅且灵活的持续时间(duration)显示与解析功能
Rust时间格式化库fancy-duration的使用,提供优雅且灵活的持续时间(duration)显示与解析功能
"fancy duration"是一种持续时间的文本描述。例如,“1h 20m 30s"可以读作"一小时二十分钟三十秒”。通过多种方式可以透明地表达持续时间类型;支持chrono和time crate,以及通过serde将字符串类型序列化和反序列化。时间支持从年到纳秒的范围。
以下是使用示例。您可以将类似duration的类型包装在FancyDuration结构体中,或者使用允许monkeypatch方法的类型,这些方法允许您直接在目标类型上工作。例如,使用AsFancyDuration注入fancy_duration调用来执行构造(可以格式化或转换为字符串),并使用ParseFancyDuration注入parse_fancy_duration构造函数来将字符串解析为您喜欢的类型。支持std::time::Duration、time::Duration和chrono::Duration(某些功能可能需要启用),您可以通过实现AsTimes特性使更多类型符合条件。
示例代码
use std::time::Duration;
use fancy_duration::FancyDuration;
pub fn main() {
assert_eq!(FancyDuration(Duration::new(20, 0)).to_string(), "20s");
assert_eq!(FancyDuration(Duration::new(600, 0)).to_string(), "10m");
assert_eq!(FancyDuration(Duration::new(120, 0)).to_string(), "2m");
assert_eq!(FancyDuration(Duration::new(185, 0)).to_string(), "3m 5s");
assert_eq!(FancyDuration::<Duration>::parse("3m 5s").unwrap().duration(), Duration::new(185, 0));
assert_eq!(FancyDuration(Duration::new(185, 0)).to_string(), "3m 5s");
// these traits are also implemented for chrono and time
use fancy_duration::{ParseFancyDuration, AsFancyDuration};
assert_eq!(Duration::new(20, 0).fancy_duration().to_string(), "20s");
assert_eq!(Duration::new(600, 0).fancy_duration().to_string(), "10m");
assert_eq!(Duration::new(120, 0).fancy_duration().to_string(), "2m");
assert_eq!(Duration::new(185, 0).fancy_duration().to_string(), "3m 5s");
assert_eq!(Duration::parse_fancy_duration("3m 5s".to_string()).unwrap(), Duration::new(185, 0));
assert_eq!(Duration::new(185, 0).fancy_duration().to_string(), "3m 5s");
#[cfg(feature = "time")]
{
// also works with time::Duration from the `time` crate
assert_eq!(FancyDuration(time::Duration::new(20, 0)).to_string(), "20s");
assert_eq!(FancyDuration(time::Duration::new(600, 0)).to_string(), "10m");
assert_eq!(FancyDuration(time::Duration::new(120, 0)).to_string(), "2m");
assert_eq!(FancyDuration(time::Duration::new(185, 0)).to_string(), "3m 5s");
assert_eq!(FancyDuration::<time::Duration>::parse("3m 5s").unwrap().duration(), time::Duration::new(185, 0));
assert_eq!(FancyDuration(time::Duration::new(185, 0)).to_string(), "3m 5s");
}
#[cfg(feature = "chrono")]
{
// also works with chrono!
assert_eq!(FancyDuration(chrono::Duration::seconds(20)).to_string(), "20s");
assert_eq!(FancyDuration(chrono::Duration::seconds(600)).to_string(), "10m");
assert_eq!(FancyDuration(chrono::Duration::seconds(120)).to_string(), "2m");
assert_eq!(FancyDuration(chrono::Duration::seconds(185)).to_string(), "3m 5s");
assert_eq!(FancyDuration::<chrono::Duration>::parse("3m 5s").unwrap().duration(), chrono::Duration::seconds(185));
assert_eq!(FancyDuration(chrono::Duration::seconds(185)).to_string(), "3m 5s");
}
}
完整示例代码
// 添加依赖到Cargo.toml
// fancy-duration = "0.9.2"
use std::time::Duration;
use fancy_duration::{FancyDuration, AsFancyDuration, ParseFancyDuration};
fn main() {
// 基本用法
let duration = Duration::new(125, 0); // 2分钟5秒
let fancy = FancyDuration(duration);
println!("Formatted duration: {}", fancy.to_string()); // 输出: 2m 5s
// 使用AsFancyDuration trait
let fancy2 = duration.fancy_duration();
println!("Alternative formatting: {}", fancy2.to_string()); // 输出: 2m 5s
// 解析字符串为Duration
let parsed = Duration::parse_fancy_duration("1h 30m").unwrap();
println!("Parsed duration: {:?}", parsed); // 输出: 5400s (1.5小时)
// 使用chrono (需要启用chrono特性)
#[cfg(feature = "chrono")]
{
use chrono::Duration as ChronoDuration;
let chrono_duration = ChronoDuration::seconds(3665); // 1小时1分钟5秒
let chrono_fancy = FancyDuration(chrono_duration);
println!("Chrono duration: {}", chrono_fancy.to_string()); // 输出: 1h 1m 5s
}
// 使用time crate (需要启用time特性)
#[cfg(feature = "time")]
{
use time::Duration as TimeDuration;
let time_duration = TimeDuration::new(185, 0); // 3分钟5秒
let time_fancy = FancyDuration(time_duration);
println!("Time duration: {}", time_fancy.to_string()); // 输出: 3m 5s
}
}
性能基准
每个间隔测试增加了将被格式化的内容数量。第一组解析测试解析一个包含多个项的字符串,其他测试在单次迭代中解析5个静态项。
基准测试系统是Ryzen 5900X,64GB内存,运行Linux 6.6.8桌面配置。
截至0.9.1版本:
fancy duration format seconds: std
time: [644.13 ps 645.34 ps 646.96 ps]
fancy duration format seconds: time
time: [6.6756 ns 6.6945 ns 6.7181 ns]
fancy duration format seconds: chrono
time: [658.36 ps 658.73 ps 659.15 ps]
fancy duration format minutes: std
time: [666.00 ps 666.50 ps 667.03 ps]
fancy duration format minutes: time
time: [6.6301 ns 6.6324 ns 6.6349 ns]
fancy duration format minutes: chrono
time: [646.99 ps 647.24 ps 647.50 ps]
fancy duration format hours: std
time: [658.35 ps 660.83 ps 662.88 ps]
fancy duration format hours: time
time: [6.5761 ns 6.5792 ns 6.5826 ns]
fancy duration format hours: chrono
time: [648.05 ps 648.38 ps 648.74 ps]
fancy duration format days: std
time: [641.06 ps 641.33 ps 641.62 ps]
fancy duration format days: time
time: [6.5374 ns 6.5410 ns 6.5452 ns]
fancy duration format days: chrono
time: [662.60 ps 665.24 ps 667.41 ps]
fancy duration format weeks: std
time: [641.06 ps 641.32 ps 641.61 ps]
fancy duration format weeks: time
time: [6.7987 ns 6.8158 ns 6.8288 ns]
fancy duration format weeks: chrono
time: [660.01 ps 662.64 ps 665.05 ps]
fancy duration format months: std
time: [641.66 ps 642.02 ps 642.41 ps]
fancy duration format months: time
time: [6.5435 ns 6.5498 ns 6.5573 ns]
fancy duration format months: chrono
time: [672.00 ps 672.39 ps 672.83 ps]
fancy duration parse one: std
time: [332.00 ns 332.48 ns 332.98 ns]
fancy duration parse one: time
time: [346.25 ns 346.58 ns 346.92 ns]
fancy duration parse one: chrono
time: [369.81 ns 371.26 ns 372.65 ns]
fancy duration parse 5 distinct items: std
time: [1.9150 µs 1.9183 µs 1.9214 µs]
fancy duration parse 5 distinct items: time
time: [1.8446 µs 1.8474 µs 1.8503 µs]
fancy duration parse 5 distinct items: chrono
time: [1.8281 µs 1.8311 µs 1.8345 µs]
安装
在项目目录中运行以下Cargo命令:
cargo add fancy-duration
或者在Cargo.toml中添加以下行:
fancy-duration = "0.9.2"
作者
Erik Hollensbe git@hollensbe.org
许可证
MIT
Rust时间格式化库fancy-duration使用指南
fancy-duration
是一个Rust库,用于优雅且灵活地格式化和解析持续时间(Duration)。它提供了比标准库更人性化的持续时间显示方式,并支持自定义格式。
安装
在Cargo.toml中添加依赖:
[dependencies]
fancy-duration = "0.7"
基本使用
格式化持续时间
use std::time::Duration;
use fancy_duration::FancyDuration;
fn main() {
let duration = Duration::new(3665, 0); // 1小时1分钟5秒
// 默认格式化
println!("{}", FancyDuration(duration));
// 输出: "1h 1m 5s"
// 紧凑模式
println!("{}", FancyDuration(duration).compact());
// 输出: "1h1m5s"
}
解析持续时间
use fancy_duration::parse_fancy_duration;
fn main() {
let duration = parse_fancy_duration("1h 30m").unwrap();
println!("总秒数: {}", duration.as_secs());
// 输出: "总秒数: 5400"
}
高级功能
自定义格式
use std::time::Duration;
use fancy_duration::{FancyDuration, FancyDurationFormat};
fn main() {
let duration = Duration::new(93784, 0); // 1天2小时3分钟4秒
let custom_format = FancyDurationFormat::new()
.with_use_days(true)
.with_use_hours(true)
.with_use_minutes(true)
.with_use_seconds(false)
.with_separator(", ");
println!("{}", FancyDuration(duration).format(custom_format));
// 输出: "1d, 2h, 3m"
}
本地化支持
use std::time::Duration;
use fancy_duration::{FancyDuration, FancyDurationFormat};
fn main() {
let duration = Duration::new(3723, 0); // 1小时2分钟3秒
let french_format = FancyDurationFormat::new()
.with_days_label(" jours")
.with_hours_label(" heures")
.with_minutes_label(" minutes")
.with_seconds_label(" secondes");
println!("{}", FancyDuration(duration).format(french_format));
// 输出: "1 heures 2 minutes 3 secondes"
}
精确控制显示单位
use std::time::Duration;
use fancy_duration::{FancyDuration, FancyDurationFormat};
fn main() {
let duration = Duration::new(93784, 0); // 1天2小时3分钟4秒
let format = FancyDurationFormat::new()
.with_max_units(2); // 只显示最大的两个单位
println!("{}", FancyDuration(duration).format(format));
// 输出: "1d 2h" (跳过了分钟和秒)
}
错误处理
解析时可能会出错,需要适当处理:
use fancy_duration::parse_fancy_duration;
fn main() {
match parse_fancy_duration("1hour 30mins") {
Ok(duration) => println!("解析成功: {}秒", duration.as_secs()),
Err(e) => println!("解析错误: {}", e),
}
}
性能考虑
fancy-duration
在格式化时几乎没有性能开销,因为它只是对std::time::Duration
的轻量级包装。解析操作会有一些开销,但通常可以忽略不计。
这个库特别适合需要向用户显示友好时间间隔的应用,如日志系统、监控工具或任何需要展示时间数据的CLI/GUI应用。
完整示例代码
use std::time::Duration;
use fancy_duration::{FancyDuration, FancyDurationFormat, parse_fancy_duration};
fn main() {
// 基本格式化示例
let duration1 = Duration::new(3665, 0); // 1小时1分钟5秒
println!("基本格式化:");
println!("默认: {}", FancyDuration(duration1));
println!("紧凑模式: {}", FancyDuration(duration1).compact());
// 解析示例
println!("\n解析示例:");
let parsed = parse_fancy_duration("1h 30m").unwrap();
println!("解析结果: {}秒", parsed.as_secs());
// 自定义格式示例
println!("\n自定义格式:");
let duration2 = Duration::new(93784, 0); // 1天2小时3分钟4秒
let custom_format = FancyDurationFormat::new()
.with_use_days(true)
.with_use_hours(true)
.with_use_minutes(true)
.with_use_seconds(false)
.with_separator(", ");
println!("自定义格式: {}", FancyDuration(duration2).format(custom_format));
// 本地化示例
println!("\n本地化示例:");
let french_format = FancyDurationFormat::new()
.with_days_label(" jours")
.with_hours_label(" heures")
.with_minutes_label(" minutes")
.with_seconds_label(" secondes");
println!("法语格式: {}", FancyDuration(duration1).format(french_format));
// 控制显示单位示例
println!("\n控制显示单位:");
let max_units_format = FancyDurationFormat::new().with_max_units(2);
println!("只显示2个单位: {}", FancyDuration(duration2).format(max_units_format));
// 错误处理示例
println!("\n错误处理:");
match parse_fancy_duration("1hour 30mins") {
Ok(d) => println!("解析成功: {}秒", d.as_secs()),
Err(e) => println!("解析错误: {}", e),
}
}
输出结果示例:
基本格式化:
默认: 1h 1m 5s
紧凑模式: 1h1m5s
解析示例:
解析结果: 5400秒
自定义格式:
自定义格式: 1d, 2h, 3m
本地化示例:
法语格式: 1 heures 1 minutes 5 secondes
控制显示单位:
只显示2个单位: 1d 2h
错误处理:
解析错误: invalid duration string