1use std::str::FromStr;
16
17use chrono::{LocalResult, NaiveDateTime, TimeZone};
18use chrono_tz::Tz;
19
20use crate::Timezone;
21use crate::timezone::get_timezone;
22
23pub fn format_utc_datetime(utc: &NaiveDateTime, pattern: &str) -> String {
24 match get_timezone(None) {
25 crate::Timezone::Offset(offset) => {
26 offset.from_utc_datetime(utc).format(pattern).to_string()
27 }
28 crate::Timezone::Named(tz) => tz.from_utc_datetime(utc).format(pattern).to_string(),
29 }
30}
31
32pub fn datetime_to_utc(
34 datetime: &NaiveDateTime,
35 timezone: &Timezone,
36) -> LocalResult<NaiveDateTime> {
37 match timezone {
38 crate::Timezone::Offset(offset) => {
39 offset.from_local_datetime(datetime).map(|x| x.naive_utc())
40 }
41 crate::Timezone::Named(tz) => tz.from_local_datetime(datetime).map(|x| x.naive_utc()),
42 }
43}
44
45pub fn find_tz_from_env() -> Option<Tz> {
46 std::env::var("TZ")
51 .ok()
52 .and_then(|tz| Tz::from_str(&tz).ok())
53}
54
55pub trait SystemTimer {
57 fn current_time_millis(&self) -> i64;
59
60 fn current_time_rfc3339(&self) -> String;
62}
63
64#[derive(Debug, Default, Clone, Copy)]
66pub struct DefaultSystemTimer;
67
68impl SystemTimer for DefaultSystemTimer {
69 fn current_time_millis(&self) -> i64 {
70 current_time_millis()
71 }
72
73 fn current_time_rfc3339(&self) -> String {
74 current_time_rfc3339()
75 }
76}
77
78pub fn current_time_millis() -> i64 {
80 chrono::Utc::now().timestamp_millis()
81}
82
83pub fn current_time_rfc3339() -> String {
85 chrono::Utc::now().to_rfc3339()
86}
87
88pub fn yesterday_rfc3339() -> String {
90 let now = chrono::Utc::now();
91 let day_before = now
92 - chrono::Duration::try_days(1).unwrap_or_else(|| {
93 panic!("now time ('{now}') is too early to calculate the day before")
94 });
95 day_before.to_rfc3339()
96}
97
98pub(crate) fn div_ceil(this: i64, rhs: i64) -> i64 {
100 let d = this / rhs;
101 let r = this % rhs;
102 if r > 0 && rhs > 0 { d + 1 } else { d }
103}
104
105pub fn format_nanoseconds_human_readable(nanos: usize) -> String {
121 if nanos == 0 {
122 return "0ns".to_string();
123 }
124
125 let nanos_i64 = nanos as i64;
126
127 if nanos_i64 >= 1_000_000_000 {
129 let secs = nanos_i64 as f64 / 1_000_000_000.0;
130 if secs >= 10.0 {
131 return format!("{:.1}s", secs);
132 } else {
133 return format!("{:.2}s", secs);
134 }
135 }
136
137 if nanos_i64 >= 1_000_000 {
139 let millis = nanos_i64 as f64 / 1_000_000.0;
140 if millis >= 10.0 {
141 return format!("{:.0}ms", millis);
142 } else {
143 return format!("{:.1}ms", millis);
144 }
145 }
146
147 if nanos_i64 >= 1_000 {
149 let micros = nanos_i64 as f64 / 1_000.0;
150 if micros >= 10.0 {
151 return format!("{:.0}us", micros);
152 } else {
153 return format!("{:.1}us", micros);
154 }
155 }
156
157 format!("{}ns", nanos_i64)
159}
160
161#[cfg(test)]
162mod tests {
163 use std::time::{self, SystemTime};
164
165 use chrono::{Datelike, TimeZone, Timelike};
166
167 use super::*;
168
169 #[test]
170 fn test_current_time_millis() {
171 let now = current_time_millis();
172
173 let millis_from_std = SystemTime::now()
174 .duration_since(time::UNIX_EPOCH)
175 .unwrap()
176 .as_millis() as i64;
177 let datetime_now = chrono::Utc.timestamp_millis_opt(now).unwrap();
178 let datetime_std = chrono::Utc.timestamp_millis_opt(millis_from_std).unwrap();
179
180 assert_eq!(datetime_std.year(), datetime_now.year());
181 assert_eq!(datetime_std.month(), datetime_now.month());
182 assert_eq!(datetime_std.day(), datetime_now.day());
183 assert_eq!(datetime_std.hour(), datetime_now.hour());
184 assert_eq!(datetime_std.minute(), datetime_now.minute());
185 }
186
187 #[test]
188 fn test_div_ceil() {
189 let v0 = 9223372036854676001;
190 assert_eq!(9223372036854677, div_ceil(v0, 1000));
191 }
192
193 #[test]
194 fn test_format_nanoseconds_human_readable() {
195 assert_eq!("0ns", format_nanoseconds_human_readable(0));
197
198 assert_eq!("1ns", format_nanoseconds_human_readable(1));
200 assert_eq!("123ns", format_nanoseconds_human_readable(123));
201 assert_eq!("999ns", format_nanoseconds_human_readable(999));
202
203 assert_eq!("1.0us", format_nanoseconds_human_readable(1_000));
205 assert_eq!("1.5us", format_nanoseconds_human_readable(1_500));
206 assert_eq!("10us", format_nanoseconds_human_readable(10_000));
207 assert_eq!("123us", format_nanoseconds_human_readable(123_000));
208 assert_eq!("999us", format_nanoseconds_human_readable(999_000));
209
210 assert_eq!("1.0ms", format_nanoseconds_human_readable(1_000_000));
212 assert_eq!("1.5ms", format_nanoseconds_human_readable(1_500_000));
213 assert_eq!("10ms", format_nanoseconds_human_readable(10_000_000));
214 assert_eq!("123ms", format_nanoseconds_human_readable(123_000_000));
215 assert_eq!("999ms", format_nanoseconds_human_readable(999_000_000));
216
217 assert_eq!("1.00s", format_nanoseconds_human_readable(1_000_000_000));
219 assert_eq!("1.23s", format_nanoseconds_human_readable(1_234_567_890));
220 assert_eq!("10.0s", format_nanoseconds_human_readable(10_000_000_000));
221 assert_eq!("123.5s", format_nanoseconds_human_readable(123_456_789_012));
222
223 assert_eq!(
225 "1234.6s",
226 format_nanoseconds_human_readable(1_234_567_890_123)
227 );
228 }
229}