Skip to content

Commit

Permalink
Time Debug impl (#47)
Browse files Browse the repository at this point in the history
* Implement Debug for Time
  • Loading branch information
fabian-braun authored Oct 26, 2023
1 parent 04c5dc5 commit 42d409c
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ derive_more = "0.99.17"
lazy_static = "1.4.0"
regex = "1.7.1"
serde = { version = "1.0.152", features = ["derive"], default-features = false }
thiserror = "1.0.49"
thiserror = "1.0.50"

[dev-dependencies]
serde_test = "1.0.152"
Expand Down
94 changes: 93 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ use std::cmp::Ordering;
use std::error::Error;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use std::ops::Add;
use std::ops::AddAssign;
use std::ops::Div;
Expand Down Expand Up @@ -74,7 +75,7 @@ use thiserror::Error;
///
/// Low overhead time representation. Internally represented as milliseconds.
#[derive(
Eq, PartialEq, Hash, Ord, PartialOrd, Copy, Clone, Debug, Default, Serialize, Deref, From, Into,
Eq, PartialEq, Hash, Ord, PartialOrd, Copy, Clone, Default, Serialize, Deref, From, Into,
)]
pub struct Time(i64);

Expand Down Expand Up @@ -326,6 +327,33 @@ pub enum TimeWindowError {
StartAfterEnd,
}

impl Debug for Time {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
// This implementation is tailor-made, because NaiveDateTime does not support
// the full range of Time. For some Time instances it wouldn't be
// possible to reconstruct them based on the Debug-representation ('∞').
let positive = self.0 >= 0;
let mut total = self.0.unsigned_abs();
let millis_part = total % 1000;
total -= millis_part;
let seconds_part = (total % (1000 * 60)) / 1000;
total -= seconds_part;
let minutes_part = (total % (1000 * 60 * 60)) / (1000 * 60);
total -= minutes_part;
let hours_part = total / (1000 * 60 * 60);
if !positive {
f.write_str("-")?;
}
write!(f, "{:02}:", hours_part)?;
write!(f, "{:02}:", minutes_part)?;
write!(f, "{:02}", seconds_part)?;
if millis_part > 0 {
write!(f, ".{:03}", millis_part)?;
}
Ok(())
}
}

/// An interval or range of time: `[start,end)`.
/// Debug-asserts ensure that start <= end.
/// If compiled in release mode, the invariant of start <= end is maintained, by
Expand Down Expand Up @@ -1393,6 +1421,70 @@ mod time_test {
}
}

#[test]
fn test_debug() {
struct TestCase {
name: &'static str,
input: Time,
expected: String,
}
let tests = vec![
TestCase {
name: "EPOCH",
input: Time::EPOCH,
expected: "00:00:00".to_string(),
},
TestCase {
name: "i16::MAX + 1",
input: Time::seconds(i64::from(i16::MAX) + 1),
expected: "09:06:08".to_string(),
},
TestCase {
name: "i32::MAX + 1",
input: Time::seconds(i64::from(i32::MAX) + 1),
expected: "596523:14:08".to_string(),
},
TestCase {
name: "u32::MAX + 1",
input: Time::seconds(i64::from(u32::MAX) + 1),
expected: "1193046:28:16".to_string(),
},
TestCase {
name: "very large",
input: Time::seconds(i64::from(i32::MAX) * 3500),
expected: "2087831323:28:20".to_string(),
},
TestCase {
name: "MAX",
input: Time::MAX,
expected: "2562047788015:12:55.807".to_string(),
},
TestCase {
name: "i16::MIN",
input: Time::seconds(i64::from(i16::MIN)),
expected: "-09:06:08".to_string(),
},
TestCase {
name: "i64::MIN",
input: Time::millis(i64::MIN),
expected: "-2562047788015:12:55.808".to_string(),
},
TestCase {
name: "millis",
input: Time::hours(3) + Duration::millis(42),
expected: "03:00:00.042".to_string(),
},
];
for test in tests {
assert_eq!(
test.expected,
format!("{:?}", test.input),
"test '{}' failed",
test.name
);
}
}

#[test]
fn deserialize_time() {
// strings
Expand Down

0 comments on commit 42d409c

Please sign in to comment.