parent
fc7b4109c7
commit
d346c9f2f3
@ -0,0 +1,95 @@ |
||||
use chrono::{ |
||||
DateTime, FixedOffset as Offset, Local, NaiveDateTime, NaiveTime, TimeZone, Timelike, Utc, |
||||
}; |
||||
|
||||
/// A convenience wrapper around [DateTime][t] with fixed timezone
|
||||
///
|
||||
/// [t]: chrono::DateTime
|
||||
pub struct Time { |
||||
inner: DateTime<Offset>, |
||||
} |
||||
|
||||
impl Time { |
||||
/// Get the current local time and pin it to a fixed Tz offset
|
||||
pub fn now() -> Self { |
||||
let now = Local::now(); |
||||
Self { |
||||
inner: build_datetime(now.time()), |
||||
} |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
pub(crate) fn fixed(hour: u32, min: u32, sec: u32) -> Self { |
||||
Self { |
||||
inner: build_datetime(NaiveTime::from_hms(hour, min, sec)), |
||||
} |
||||
} |
||||
|
||||
/// Return a new instance that is rounded to nearest 15 minutes
|
||||
///
|
||||
/// It uses the internally provided offset to do rounding, meaning
|
||||
/// that the timezone information will not change, even when
|
||||
/// rounding values that were created in a different timezone.
|
||||
pub fn round(&self) -> Self { |
||||
let naive = self.inner.time(); |
||||
|
||||
let (new_min, incr_hour) = match naive.minute() { |
||||
// 0-7 => (0, false)
|
||||
m if m > 0 && m < 7 => (0, false), |
||||
// 7-22 => (15, false)
|
||||
m if m >= 7 && m < 22 => (15, false), |
||||
// 22-37 => (30, false)
|
||||
m if m >= 22 && m < 37 => (30, false), |
||||
// 37-52 => (45, false)
|
||||
m if m >= 37 && m < 52 => (45, false), |
||||
// 52-59 => (0, true)
|
||||
m if m >= 52 && m <= 59 => (0, true), |
||||
_ => unreachable!(), |
||||
}; |
||||
|
||||
let hour = naive.hour(); |
||||
let new = NaiveTime::from_hms(if incr_hour { hour + 1 } else { hour }, new_min, 0); |
||||
let offset = self.inner.offset(); |
||||
let date = self.inner.date(); |
||||
|
||||
Self { |
||||
inner: DateTime::from_utc(NaiveDateTime::new(date.naive_local(), new), *offset), |
||||
} |
||||
} |
||||
|
||||
pub fn hour(&self) -> u32 { |
||||
self.inner.hour() |
||||
} |
||||
|
||||
pub fn minute(&self) -> u32 { |
||||
self.inner.minute() |
||||
} |
||||
|
||||
pub fn second(&self) -> u32 { |
||||
self.inner.second() |
||||
} |
||||
} |
||||
|
||||
/// Build a DateTime with the current local fixed offset
|
||||
fn build_datetime(nt: NaiveTime) -> DateTime<Offset> { |
||||
let date = Utc::now().date().naive_local(); |
||||
let offset = Local.offset_from_utc_date(&date); |
||||
|
||||
DateTime::from_utc(NaiveDateTime::new(date, nt), offset) |
||||
} |
||||
|
||||
#[test] |
||||
fn simple() { |
||||
let t = Time::fixed(10, 44, 0); |
||||
let round = t.round(); |
||||
assert_eq!(round.minute(), 45); |
||||
|
||||
let t = Time::fixed(6, 8, 0); |
||||
let round = t.round(); |
||||
assert_eq!(round.minute(), 15); |
||||
|
||||
let t = Time::fixed(6, 55, 0); |
||||
let round = t.round(); |
||||
assert_eq!(round.minute(), 0); |
||||
assert_eq!(round.hour(), 7); |
||||
} |
Loading…
Reference in new issue