20个版本

0.2.0-alpha.82023年1月9日
0.2.0-alpha.72023年1月4日
0.2.0-alpha.62022年9月15日
0.1.12 2022年9月8日
0.0.1 2022年8月6日

#564 in 编码

Download history 34/week @ 2024-03-30 7/week @ 2024-04-06

每月 84 次下载

MIT 许可证

94KB
2K SLoC

calends

calends 是一个用于持续时间、时间间隔和其他日历相关操作的库。它旨在与chrono一起使用。

理由

Calends 是为了扩展生态系统中现有的日期时间工具(如chrono)而构建的。其主要重点是查找和处理更复杂的事物,例如时间间隔、持续时间(专注于月份或更长时间,chrono 不支持月份),以及复杂的重复规则,例如“每月第3天重复3次”。

除了支持日期时间逻辑,还应考虑 ISO8601-2:2019。该标准是为了扩展当前的 ISO8601 标准并添加对间隔、持续时间、重复时间的支持而创建的。这并不是一个广泛采用的标准(可能由于其封闭和非常昂贵的性质)。

此库中的许多概念都受到了 ISO8601-2:2019 标准和 CalConnect 的影响。

时间持续时间

相对持续时间 是一个可以将日期应用于其中以产生另一个日期的时间单位。

use calends::RelativeDuration;
use chrono::NaiveDate;

// This will allow you to add one month and then go back two days from the added month
let rd = RelativeDuration::months(1).with_days(-2);

// It also compatible with NaiveDate
assert_eq!(
    NaiveDate::from_ymd(2022, 1, 1) + rd,
    NaiveDate::from_ymd(2022, 1, 30)
);

将持续时间应用于日期时,如果最大单位首先应用,则按顺序应用,例如,月份将在周之前。因此,当构建类似于 1 个月、-1 天的持续时间时,它将先向前移动 1 个月,然后向后移动 1 天。

序列化

有两种方法可以序列化相对持续时间

  • 第一种方法将其序列化为一个对象。
  • 第二种方法是一个与 ISO8601-2:2019 兼容的序列化器。因为格式尚未广泛使用,所以我们没有将其设置为默认(反)序列化器。
use calends::RelativeDuration;
use calends::rd_iso8601;

#[derive(Debug, serde::Deserialize, serde::Serialize)]
struct S {
   #[serde(
     deserialize_with = "rd_iso8601::deserialize",
     serialize_with = "rd_iso8601::serialize"
   )]
   rd: RelativeDuration,
}

let rd = RelativeDuration::default().with_days(1).with_months(23).with_weeks(-1);
let s = S { rd };

let rd_string = serde_json::to_string(&s).unwrap();
assert_eq!(rd_string, r#"{"rd":"P23M-1W1D"}"#);

let parsed: S = serde_json::from_str(&rd_string).unwrap();
assert_eq!(rd, parsed.rd)

重复和规则

[重复] 允许您指定事件(日期)在时间上重复的规则集。

use calends::{Recurrence, Rule};
use chrono::NaiveDate;

let date = NaiveDate::from_ymd(2022, 1, 1);
let end = NaiveDate::from_ymd(2022, 3, 1);

let mut recur = Recurrence::with_start(Rule::monthly(), date).until(end);
assert_eq!(recur.next(), Some(NaiveDate::from_ymd(2022, 1, 1)));
assert_eq!(recur.next(), Some(NaiveDate::from_ymd(2022, 2, 1)));
assert_eq!(recur.next(), None);

时间间隔

时间间隔是一段可以绑定或不绑定的持续时间。有三个重要的情况需要考虑:封闭的、无界起始和无限终止。

  • 封闭的时间间隔具有起始和终止,并且可以重复。
  • 无界起始的时间间隔没有起始,只有终止。
  • 无界终止的时间间隔没有终止,但有起始。

封闭时间间隔

结合相对持续时间,您可以执行诸如迭代月份倒数第二天之类的事情。

use calends::{Interval, RelativeDuration};
use chrono::NaiveDate;

let duration = RelativeDuration::months(1).with_days(-2);
let start = NaiveDate::from_ymd(2022, 1, 1);

let mut interval = Interval::closed_from_start(start, duration);

序列化

有三种方法可以序列化时间间隔

  • 第一种方法将其序列化为一个对象。
  • 第二种方法是一个与 ISO8601-2:2019 兼容的序列化器。因为格式尚未广泛使用,所以我们没有将其设置为默认(反)序列化器。
use chrono::NaiveDate;
use calends::{Interval, RelativeDuration, IntervalLike};
use calends::interval::marker::Start;

#[derive(Debug, serde::Deserialize, serde::Serialize)]
struct S {
   i: Interval,
}

let rd = RelativeDuration::default().with_days(1).with_months(23).with_weeks(-1);
let int = Interval::closed_from_start(NaiveDate::from_ymd(2022, 1, 1), rd);
let s = S { i: int.clone() };

let int_string = serde_json::to_string(&s).unwrap();
assert_eq!(int_string, r#"{"i":"2022-01-01/2023-11-25"}"#);

let parsed: S = serde_json::from_str(&int_string).unwrap();
assert_eq!(parsed.i.start_opt().unwrap(), int.start_opt().unwrap())

许可证: MIT

依赖项

~2.3–3.5MB
~62K SLoC