1#![doc = include_str!("../README.md")]
2
3use anyhow::{anyhow, Result};
6use lazy_static::lazy_static;
7use time::OffsetDateTime;
8
9pub const FMT_COMPACT: &str = "[year][month][day]-[hour][minute][second]Z";
12pub const FMT_ISO8601: &str = "[year]-[month]-[day]T[hour]:[minute]:[second]Z";
13pub const FMT_ISO8601NS: &str = "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:9]Z";
14
15lazy_static! {
18 pub static ref COMPACT: KronFormat<'static> = KronFormat::new(FMT_COMPACT).unwrap();
19 pub static ref ISO8601: KronFormat<'static> = KronFormat::new(FMT_ISO8601).unwrap();
20 pub static ref ISO8601NS: KronFormat<'static> = KronFormat::new(FMT_ISO8601NS).unwrap();
21}
22
23#[cfg(test)]
26mod tests;
27
28#[derive(Clone)]
31pub struct KronFormat<'a> {
32 fmt: Vec<time::format_description::FormatItem<'a>>,
33}
34
35impl KronFormat<'_> {
36 pub fn new(s: &str) -> Result<KronFormat> {
37 Ok(KronFormat {
38 fmt: time::format_description::parse(s)?,
39 })
40 }
41
42 pub fn from(s: &str) -> Result<KronFormat> {
43 match s {
44 "COMPACT" => Ok(COMPACT.clone()),
45 "ISO8601" => Ok(ISO8601.clone()),
46 "ISO8601NS" => Ok(ISO8601NS.clone()),
47 _ => KronFormat::new(s),
48 }
50 }
51}
52
53pub struct Kron {
56 pub dt: OffsetDateTime,
57}
58
59impl Kron {
60 pub fn now() -> Kron {
61 Kron {
62 dt: OffsetDateTime::now_utc(),
63 }
64 }
65
66 pub fn from(s: &str) -> Result<Kron> {
67 if s.contains('.') && s.parse::<f64>().is_ok() {
68 let mut p = s.split('.');
69 let mut ts = Kron::timestamp(p.next().unwrap().parse::<i64>()?)?;
70 let mut nanos = p.next().unwrap().to_string();
71 while nanos.len() < 9 {
72 nanos.push('0');
73 }
74 ts.dt = ts.dt.replace_nanosecond(nanos.parse::<u32>()?)?;
75 Ok(ts)
76 } else if let Ok(n) = s.parse::<i64>() {
77 Kron::timestamp(n)
78 } else {
79 Err(anyhow!("Invalid timestamp: {s:?}"))
80 }
81 }
82
83 pub fn timestamp(n: i64) -> Result<Kron> {
84 Ok(Kron {
85 dt: OffsetDateTime::from_unix_timestamp(n)?,
86 })
87 }
88
89 pub fn epoch() -> Kron {
90 Kron::timestamp(0).unwrap()
91 }
92
93 pub fn format(&self, f: &KronFormat) -> Result<String> {
94 Ok(self.dt.format(&f.fmt)?)
95 }
96
97 pub fn format_str(&self, s: &'static str) -> Result<String> {
98 self.format(&KronFormat::new(s)?)
99 }
100}
101
102impl std::fmt::Display for Kron {
103 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
104 write!(f, "{}", self.dt.format(&ISO8601.fmt).unwrap())
105 }
106}