1use std::time::{SystemTime, UNIX_EPOCH};
9
10pub const NANOS_PER_SEC: i64 = 1_000_000_000;
12pub const NANOS_PER_DAY: i64 = 86_400 * NANOS_PER_SEC;
14
15pub type DtNs = i64;
17
18pub type Day = i32;
20
21pub fn days_from_civil(y: i32, m: u32, d: u32) -> Day {
25 let y = if m <= 2 { y - 1 } else { y } as i64;
26 let era = if y >= 0 { y } else { y - 399 } / 400;
27 let yoe = y - era * 400; let mp: i64 = ((m as i64) + 9) % 12; let doy = (153 * mp + 2) / 5 + (d as i64) - 1; let doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; (era * 146097 + doe - 719468) as Day
32}
33
34pub fn civil_from_days(z: Day) -> (i32, u32, u32) {
36 let z = z as i64 + 719468;
37 let era = if z >= 0 { z } else { z - 146096 } / 146097;
38 let doe = z - era * 146097; let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; let y = yoe + era * 400;
41 let doy = doe - (365 * yoe + yoe / 4 - yoe / 100); let mp = (5 * doy + 2) / 153; let d = (doy - (153 * mp + 2) / 5 + 1) as u32; let m = (if mp < 10 { mp + 3 } else { mp - 9 }) as u32; ((y + if m <= 2 { 1 } else { 0 }) as i32, m, d)
46}
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50pub struct Civil {
51 pub year: i32,
53 pub month: u32,
55 pub day: u32,
57 pub hour: u32,
59 pub minute: u32,
61 pub second: u32,
63 pub nanos: u32,
65}
66
67pub fn civil_to_nanos(c: Civil) -> DtNs {
69 let days = days_from_civil(c.year, c.month, c.day) as i64;
70 days * NANOS_PER_DAY
71 + (c.hour as i64) * 3600 * NANOS_PER_SEC
72 + (c.minute as i64) * 60 * NANOS_PER_SEC
73 + (c.second as i64) * NANOS_PER_SEC
74 + c.nanos as i64
75}
76
77pub fn civil_from_nanos(t: DtNs) -> Civil {
79 let days = t.div_euclid(NANOS_PER_DAY);
80 let secs_of_day = t.rem_euclid(NANOS_PER_DAY);
81 let (year, month, day) = civil_from_days(days as Day);
82 let total_sec = secs_of_day / NANOS_PER_SEC;
83 let nanos = (secs_of_day % NANOS_PER_SEC) as u32;
84 Civil {
85 year,
86 month,
87 day,
88 hour: (total_sec / 3600) as u32,
89 minute: (total_sec % 3600 / 60) as u32,
90 second: (total_sec % 60) as u32,
91 nanos,
92 }
93}
94
95pub fn now_nanos() -> DtNs {
97 from_system_time(SystemTime::now())
98}
99
100pub fn trading_day(t: DtNs) -> Day {
102 t.div_euclid(NANOS_PER_DAY) as Day
103}
104
105pub fn from_system_time(t: SystemTime) -> DtNs {
108 match t.duration_since(UNIX_EPOCH) {
109 Ok(d) => d.as_nanos() as DtNs,
110 Err(e) => -(e.duration().as_nanos() as DtNs),
111 }
112}
113
114pub fn format_civil(t: DtNs) -> String {
118 let c = civil_from_nanos(t);
119 let base = format!(
120 "{:04}-{:02}-{:02} {:02}:{:02}:{:02}",
121 c.year, c.month, c.day, c.hour, c.minute, c.second
122 );
123 if c.nanos == 0 {
124 base
125 } else {
126 format!("{base}.{:09}", c.nanos)
127 }
128}