Allow out-of-bounds values for Time
This commit is contained in:
parent
44bcd5712d
commit
6e6a696ca4
3 changed files with 46 additions and 21 deletions
|
|
@ -358,7 +358,7 @@ mod tests {
|
||||||
fn apply_dt(step: Step, from: (i32, u32, u32, u32, u32)) -> Result<(NaiveDate, Time)> {
|
fn apply_dt(step: Step, from: (i32, u32, u32, u32, u32)) -> Result<(NaiveDate, Time)> {
|
||||||
delta(step).apply_date_time(
|
delta(step).apply_date_time(
|
||||||
NaiveDate::from_ymd(from.0, from.1, from.2),
|
NaiveDate::from_ymd(from.0, from.1, from.2),
|
||||||
Time::new(from.3, from.4).unwrap(),
|
Time::new(from.3, from.4),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -368,7 +368,7 @@ mod tests {
|
||||||
apply_dt(step, from).unwrap(),
|
apply_dt(step, from).unwrap(),
|
||||||
(
|
(
|
||||||
NaiveDate::from_ymd(expected.0, expected.1, expected.2),
|
NaiveDate::from_ymd(expected.0, expected.1, expected.2),
|
||||||
Time::new(expected.3, expected.4).unwrap()
|
Time::new(expected.3, expected.4)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -552,34 +552,34 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn delta_time() {
|
fn delta_time() {
|
||||||
test_dt(
|
test_dt(
|
||||||
Step::Time(Time::new(12, 33).unwrap()),
|
Step::Time(Time::new(12, 33)),
|
||||||
(2021, 7, 3, 12, 34),
|
(2021, 7, 3, 12, 34),
|
||||||
(2021, 7, 4, 12, 33),
|
(2021, 7, 4, 12, 33),
|
||||||
);
|
);
|
||||||
test_dt(
|
test_dt(
|
||||||
Step::Time(Time::new(12, 34).unwrap()),
|
Step::Time(Time::new(12, 34)),
|
||||||
(2021, 7, 3, 12, 34),
|
(2021, 7, 3, 12, 34),
|
||||||
(2021, 7, 3, 12, 34),
|
(2021, 7, 3, 12, 34),
|
||||||
);
|
);
|
||||||
test_dt(
|
test_dt(
|
||||||
Step::Time(Time::new(12, 35).unwrap()),
|
Step::Time(Time::new(12, 35)),
|
||||||
(2021, 7, 3, 12, 34),
|
(2021, 7, 3, 12, 34),
|
||||||
(2021, 7, 3, 12, 35),
|
(2021, 7, 3, 12, 35),
|
||||||
);
|
);
|
||||||
|
|
||||||
// 24:00 != 00:00
|
// 24:00 != 00:00
|
||||||
test_dt(
|
test_dt(
|
||||||
Step::Time(Time::new(24, 0).unwrap()),
|
Step::Time(Time::new(24, 0)),
|
||||||
(2021, 7, 3, 12, 0),
|
(2021, 7, 3, 12, 0),
|
||||||
(2021, 7, 3, 24, 0),
|
(2021, 7, 3, 24, 0),
|
||||||
);
|
);
|
||||||
test_dt(
|
test_dt(
|
||||||
Step::Time(Time::new(0, 0).unwrap()),
|
Step::Time(Time::new(0, 0)),
|
||||||
(2021, 7, 3, 12, 0),
|
(2021, 7, 3, 12, 0),
|
||||||
(2021, 7, 4, 0, 0),
|
(2021, 7, 4, 0, 0),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Requires time
|
// Requires time
|
||||||
assert!(apply_d(Step::Time(Time::new(12, 34).unwrap()), (2021, 7, 3)).is_err());
|
assert!(apply_d(Step::Time(Time::new(12, 34)), (2021, 7, 3)).is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,9 +84,11 @@ fn parse_time(p: Pair<'_, Rule>) -> Result<Spanned<Time>> {
|
||||||
|
|
||||||
assert_eq!(p.next(), None);
|
assert_eq!(p.next(), None);
|
||||||
|
|
||||||
match Time::new(hour, min) {
|
let time = Time::new(hour, min);
|
||||||
Some(time) => Ok(Spanned::new(span, time)),
|
if time.in_normal_range() {
|
||||||
None => fail(pspan, "invalid time"),
|
Ok(Spanned::new(span, time))
|
||||||
|
} else {
|
||||||
|
fail(pspan, "invalid time")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
use std::cmp::{self, Ordering};
|
use std::cmp::{self, Ordering};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use chrono::{NaiveTime, Timelike};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Span {
|
pub struct Span {
|
||||||
pub start: usize,
|
pub start: usize,
|
||||||
|
|
@ -63,18 +65,39 @@ impl fmt::Debug for Time {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<NaiveTime> for Time {
|
||||||
|
fn from(t: NaiveTime) -> Self {
|
||||||
|
Self::new(t.hour(), t.minute())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Time {
|
impl Time {
|
||||||
pub fn new(hour: u32, min: u32) -> Option<Self> {
|
pub fn new(hour: u32, min: u32) -> Self {
|
||||||
if hour < 24 && min < 60 || hour == 24 && min == 0 {
|
Self {
|
||||||
Some(Self {
|
hour: hour as u8,
|
||||||
hour: hour as u8,
|
min: min as u8,
|
||||||
min: min as u8,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether this time is within the normal range for times. This means that
|
||||||
|
/// the minutes are always smaller than 60 and the whole time is between
|
||||||
|
/// `00:00` and `24:00` (inclusive).
|
||||||
|
///
|
||||||
|
/// In cases like leap seconds or daylight savings time, it is possible that
|
||||||
|
/// times outside of this range occur.
|
||||||
|
pub fn in_normal_range(&self) -> bool {
|
||||||
|
if self.min >= 60 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if self.hour > 24 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if self.hour == 24 && self.min != 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_minutes(&self, amount: i32) -> (i32, Self) {
|
pub fn add_minutes(&self, amount: i32) -> (i32, Self) {
|
||||||
match amount.cmp(&0) {
|
match amount.cmp(&0) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
|
|
@ -85,7 +108,7 @@ impl Time {
|
||||||
|
|
||||||
let hour = mins.div_euclid(60) as u32;
|
let hour = mins.div_euclid(60) as u32;
|
||||||
let min = mins.rem_euclid(60) as u32;
|
let min = mins.rem_euclid(60) as u32;
|
||||||
(days, Self::new(hour, min).unwrap())
|
(days, Self::new(hour, min))
|
||||||
}
|
}
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
let mut mins = (self.hour as i32) * 60 + (self.min as i32) + amount;
|
let mut mins = (self.hour as i32) * 60 + (self.min as i32) + amount;
|
||||||
|
|
@ -101,7 +124,7 @@ impl Time {
|
||||||
|
|
||||||
let hour = mins.div_euclid(60) as u32;
|
let hour = mins.div_euclid(60) as u32;
|
||||||
let min = mins.rem_euclid(60) as u32;
|
let min = mins.rem_euclid(60) as u32;
|
||||||
(days, Self::new(hour, min).unwrap())
|
(days, Self::new(hour, min))
|
||||||
}
|
}
|
||||||
Ordering::Equal => (0, *self),
|
Ordering::Equal => (0, *self),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue