Skip to content

Commit

Permalink
refactor(proto): add error handling to FromMillis and ToMillis
Browse files Browse the repository at this point in the history
  • Loading branch information
lklimek committed Oct 10, 2024
1 parent 46bc39a commit e5c94a6
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 21 deletions.
5 changes: 5 additions & 0 deletions proto/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ use crate::prelude::*;

define_error! {
Error {
TimeConversion
{ reason: String }
| e | {
format!("error converting time: {}", e.reason)
},
TryFromProtobuf
{ reason: String }
| e | {
Expand Down
47 changes: 26 additions & 21 deletions proto/src/time.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Time conversion traits and functions
use crate::google::protobuf::Timestamp;
use crate::{google::protobuf::Timestamp, Error};
pub trait ToMillis {
/// Convert protobuf timestamp into milliseconds since epoch
Expand All @@ -13,42 +13,44 @@ pub trait ToMillis {
/// # Panics
///
/// Panics when timestamp doesn't fit `u64` type
fn to_millis(&self) -> u64;
fn to_millis(&self) -> Result<u64, Error>;

#[deprecated = "use `to_millis` instead"]
fn to_milis(&self) -> u64 {
self.to_millis()
.expect("cannot convert time to milliseconds")
}
}

impl ToMillis for Timestamp {
/// Convert protobuf timestamp into milliseconds since epoch
fn to_millis(&self) -> u64 {
fn to_millis(&self) -> Result<u64, Error> {
chrono::DateTime::from_timestamp(self.seconds, self.nanos as u32)
.unwrap()
.to_utc()
.timestamp_millis()
.try_into()
.expect("timestamp value out of u64 range")
.map(|t| t.to_utc().timestamp_millis())
.and_then(|t| t.try_into().ok())
.ok_or(Error::time_conversion(format!(
"time value {:?} out of range",
self
)))
}
}

pub trait FromMillis {
pub trait FromMillis: Sized {
/// Create protobuf timestamp from milliseconds since epoch
///
/// Note there is a resolution difference, as timestamp uses nanoseconds
///
/// # Arguments
///
/// * millis - time since epoch, in milliseconds; must fit `i64` type
fn from_millis(millis: u64) -> Self;
fn from_millis(millis: u64) -> Result<Self, Error>;

#[deprecated = "use `from_millis` instead"]
fn from_milis(millis: u64) -> Self
where
Self: Sized,
{
Self::from_millis(millis)
Self::from_millis(millis).expect("conversion from milliseconds should not fail")
}
}

Expand All @@ -60,18 +62,21 @@ impl FromMillis for Timestamp {
/// # Panics
///
/// Panics when `millis` don't fit `i64` type
fn from_millis(millis: u64) -> Self {
let dt = chrono::DateTime::from_timestamp_millis(
millis
.try_into()
.expect("milliseconds timestamp out of i64 range"),
)
.expect("cannot parse timestamp")
.to_utc();
fn from_millis(millis: u64) -> Result<Self, Error> {
let ts_millis = millis
.try_into()
.map_err(|e| Error::time_conversion(format!("milliseconds out of range: {:?}", e)))?;

let dt = chrono::DateTime::from_timestamp_millis(ts_millis)
.ok_or(Error::time_conversion(format!(
"cannot create date/time from milliseconds {}",
ts_millis,
)))?
.to_utc();

Self {
Ok(Self {
nanos: dt.timestamp_subsec_nanos() as i32,
seconds: dt.timestamp(),
}
})
}
}

0 comments on commit e5c94a6

Please sign in to comment.