1use time::OffsetDateTime;
4use time::format_description::well_known::Rfc3339;
5
6pub fn now_rfc3339() -> String {
8 OffsetDateTime::now_utc()
9 .format(&Rfc3339)
10 .expect("format RFC3339 timestamp")
11}
12
13pub fn now_ts_ms() -> i64 {
15 OffsetDateTime::now_utc().unix_timestamp_nanos() as i64 / 1_000_000
16}
17
18pub fn after_millis_rfc3339(millis: u64) -> String {
24 let delta = time::Duration::milliseconds(i64::try_from(millis).unwrap_or(i64::MAX));
25 OffsetDateTime::now_utc()
26 .saturating_add(delta)
27 .format(&Rfc3339)
28 .expect("format RFC3339 timestamp")
29}
30
31#[cfg(test)]
32mod tests {
33 use super::*;
34
35 fn parse(value: &str) -> OffsetDateTime {
36 OffsetDateTime::parse(value, &Rfc3339).expect("parse rfc3339")
37 }
38
39 fn to_ms(value: OffsetDateTime) -> i128 {
40 value.unix_timestamp_nanos() / 1_000_000
41 }
42
43 #[test]
44 fn now_rfc3339_is_parseable_and_close_to_now() {
45 let before = OffsetDateTime::now_utc();
46 let parsed = parse(&now_rfc3339());
47 let after = OffsetDateTime::now_utc();
48 assert!(parsed >= before - time::Duration::seconds(1));
49 assert!(parsed <= after + time::Duration::seconds(1));
50 }
51
52 #[test]
53 fn now_ts_ms_is_a_plausible_epoch_millisecond() {
54 let ms = now_ts_ms();
56 assert!(ms > 1_577_836_800_000, "看起来不是毫秒时间戳: {ms}");
57 assert!(ms < 4_102_444_800_000, "看起来不是毫秒时间戳: {ms}");
58 }
59
60 #[test]
61 fn after_millis_zero_is_now_and_positive_moves_forward() {
62 let start = to_ms(OffsetDateTime::now_utc());
63
64 let at_zero = to_ms(parse(&after_millis_rfc3339(0)));
65 assert!(
66 (at_zero - start).abs() < 2_000,
67 "偏离过大: {at_zero} vs {start}"
68 );
69
70 let plus = to_ms(parse(&after_millis_rfc3339(60_000)));
71 assert!(
72 (plus - start - 60_000).abs() < 2_000,
73 "应大约晚 60s: {plus} vs {start}"
74 );
75 }
76
77 #[test]
78 fn after_millis_saturates_instead_of_panicking_on_huge_inputs() {
79 for millis in [u64::MAX, i64::MAX as u64, (i64::MAX as u64) + 1, 1u64 << 62] {
82 let text = after_millis_rfc3339(millis);
83 let parsed = parse(&text);
84 assert!(
85 parsed >= OffsetDateTime::now_utc(),
86 "{millis} 应装出未来时刻,实际 {text}"
87 );
88 }
89 }
90}