Skip to content

Commit

Permalink
Add a TimeConfigBuilder to avoid further breaking changes (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
adriangb authored Jul 13, 2023
1 parent 7058870 commit e133861
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 73 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "speedate"
authors = ["Samuel Colvin <s@muelcolvin.com>"]
version = "0.11.0"
version = "0.12.0"
edition = "2021"
description = "Fast and simple datetime, date, time and duration parsing"
readme = "README.md"
Expand Down
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,37 @@ fn main() {
}
```

To control the specifics of time parsing you can use provide a `TimeConfig`:

```rust
use speedate::{DateTime, Date, Time, TimeConfig};

fn main() {
let dt = DateTime::parse_bytes_with_config(
"1689102037.5586429".as_bytes(),
&TimeConfig::builder().unix_timestamp_offset(Some(0)).build(),
).unwrap();
assert_eq!(
dt,
DateTime {
date: Date {
year: 2023,
month: 7,
day: 11,
},
time: Time {
hour: 19,
minute: 0,
second: 37,
microsecond: 558643,
tz_offset: Some(0),
},
}
);
assert_eq!(dt.to_string(), "2023-07-11T19:00:37.558643Z");
}
```

## Performance

**speedate** is significantly faster than
Expand Down
23 changes: 12 additions & 11 deletions src/datetime.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::numbers::{float_parse_bytes, IntFloat};
use crate::{Date, ParseError, Time, TimeConfig};
use crate::TimeConfigBuilder;
use crate::{time::TimeConfig, Date, ParseError, Time};
use std::cmp::Ordering;
use std::fmt;
use std::time::SystemTime;
Expand Down Expand Up @@ -236,7 +237,7 @@ impl DateTime {
/// assert_eq!(dt.to_string(), "2022-01-01T12:13:14Z");
/// ```
pub fn parse_bytes_rfc3339(bytes: &[u8]) -> Result<Self, ParseError> {
DateTime::parse_bytes_rfc3339_with_config(bytes, &TimeConfig::default())
DateTime::parse_bytes_rfc3339_with_config(bytes, &TimeConfigBuilder::new().build())
}

/// Same as `parse_bytes_rfc3339` with with a `TimeConfig` parameter.
Expand All @@ -249,9 +250,9 @@ impl DateTime {
/// # Examples
///
/// ```
/// use speedate::{DateTime, Date, Time, TimeConfig};
/// use speedate::{DateTime, Date, Time, TimeConfigBuilder};
///
/// let dt = DateTime::parse_bytes_rfc3339_with_config(b"2022-01-01T12:13:14Z", &TimeConfig::default()).unwrap();
/// let dt = DateTime::parse_bytes_rfc3339_with_config(b"2022-01-01T12:13:14Z", &TimeConfigBuilder::new().build()).unwrap();
/// assert_eq!(
/// dt,
/// DateTime {
Expand Down Expand Up @@ -305,7 +306,7 @@ impl DateTime {
/// assert_eq!(dt.to_string(), "2022-01-01T12:13:14");
/// ```
pub fn parse_bytes(bytes: &[u8]) -> Result<Self, ParseError> {
DateTime::parse_bytes_with_config(bytes, &TimeConfig::default())
DateTime::parse_bytes_with_config(bytes, &TimeConfigBuilder::new().build())
}

/// Same as `DateTime::parse_bytes` but supporting TimeConfig
Expand All @@ -318,9 +319,9 @@ impl DateTime {
/// # Examples
///
/// ```
/// use speedate::{DateTime, Date, Time, TimeConfig};
/// use speedate::{DateTime, Date, Time, TimeConfigBuilder};
///
/// let dt = DateTime::parse_bytes_with_config(b"2022-01-01T12:13:14Z", &TimeConfig::default()).unwrap();
/// let dt = DateTime::parse_bytes_with_config(b"2022-01-01T12:13:14Z", &TimeConfigBuilder::new().build()).unwrap();
/// assert_eq!(dt.to_string(), "2022-01-01T12:13:14Z");
/// ```
pub fn parse_bytes_with_config(bytes: &[u8], config: &TimeConfig) -> Result<Self, ParseError> {
Expand Down Expand Up @@ -364,12 +365,12 @@ impl DateTime {
/// # Examples
///
/// ```
/// use speedate::{DateTime, TimeConfig};
/// use speedate::{DateTime, TimeConfigBuilder};
///
/// let d = DateTime::from_timestamp_with_config(1_654_619_320, 123, &TimeConfig::default()).unwrap();
/// let d = DateTime::from_timestamp_with_config(1_654_619_320, 123, &TimeConfigBuilder::new().build()).unwrap();
/// assert_eq!(d.to_string(), "2022-06-07T16:28:40.000123");
///
/// let d = DateTime::from_timestamp_with_config(1_654_619_320_123, 123_000, &TimeConfig::default()).unwrap();
/// let d = DateTime::from_timestamp_with_config(1_654_619_320_123, 123_000, &TimeConfigBuilder::new().build()).unwrap();
/// assert_eq!(d.to_string(), "2022-06-07T16:28:40.246");
/// ```
pub fn from_timestamp_with_config(
Expand Down Expand Up @@ -431,7 +432,7 @@ impl DateTime {
/// assert_eq!(d.to_string(), "2022-06-07T16:28:40.246");
/// ```
pub fn from_timestamp(timestamp: i64, timestamp_microsecond: u32) -> Result<Self, ParseError> {
Self::from_timestamp_with_config(timestamp, timestamp_microsecond, &TimeConfig::default())
Self::from_timestamp_with_config(timestamp, timestamp_microsecond, &TimeConfigBuilder::new().build())
}

/// Create a datetime from the system time. This method uses [std::time::SystemTime] to get
Expand Down
10 changes: 5 additions & 5 deletions src/duration.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::cmp::Ordering;
use std::fmt;

use crate::{ParseError, Time, TimeConfig};
use crate::{time::TimeConfig, ParseError, Time, TimeConfigBuilder};

/// A Duration
///
Expand Down Expand Up @@ -231,7 +231,7 @@ impl Duration {
/// ```
#[inline]
pub fn parse_bytes(bytes: &[u8]) -> Result<Self, ParseError> {
Duration::parse_bytes_with_config(bytes, &TimeConfig::default())
Duration::parse_bytes_with_config(bytes, &TimeConfigBuilder::new().build())
}

/// Same as `Duration::parse_bytes` but with a TimeConfig component.
Expand All @@ -244,9 +244,9 @@ impl Duration {
/// # Examples
///
/// ```
/// use speedate::{Duration, TimeConfig};
/// use speedate::{Duration, TimeConfigBuilder};
///
/// let d = Duration::parse_bytes_with_config(b"P1Y", &TimeConfig::default()).unwrap();
/// let d = Duration::parse_bytes_with_config(b"P1Y", &TimeConfigBuilder::new().build()).unwrap();
/// assert_eq!(
/// d,
/// Duration {
Expand Down Expand Up @@ -454,7 +454,7 @@ impl Duration {

match bytes.get(position).copied() {
Some(_) => {
let t = Time::parse_bytes_offset(bytes, position, &TimeConfig::default())?;
let t = Time::parse_bytes_offset(bytes, position, &TimeConfigBuilder::new().build())?;

Ok(Self {
positive: false, // is set above
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mod time;
pub use date::Date;
pub use datetime::DateTime;
pub use duration::Duration;
pub use time::{MicrosecondsPrecisionOverflowBehavior, Time, TimeConfig};
pub use time::{MicrosecondsPrecisionOverflowBehavior, Time, TimeConfig, TimeConfigBuilder};

pub use numbers::{float_parse_bytes, float_parse_str, int_parse_bytes, int_parse_str, IntFloat};

Expand Down
55 changes: 47 additions & 8 deletions src/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ impl Time {
/// ```
#[inline]
pub fn parse_bytes(bytes: &[u8]) -> Result<Self, ParseError> {
Self::parse_bytes_offset(bytes, 0, &TimeConfig::default())
Self::parse_bytes_offset(bytes, 0, &TimeConfigBuilder::new().build())
}

/// Same as `Time::parse_bytes` but with a `TimeConfig`.
Expand All @@ -199,9 +199,9 @@ impl Time {
/// # Examples
///
/// ```
/// use speedate::{Time, TimeConfig};
/// use speedate::{Time, TimeConfigBuilder};
///
/// let d = Time::parse_bytes_with_config(b"12:13:14.123456", &TimeConfig::default()).unwrap();
/// let d = Time::parse_bytes_with_config(b"12:13:14.123456", &TimeConfigBuilder::new().build()).unwrap();
/// assert_eq!(
/// d,
/// Time {
Expand Down Expand Up @@ -237,7 +237,11 @@ impl Time {
/// assert_eq!(d.to_string(), "01:02:20.000123");
/// ```
pub fn from_timestamp(timestamp_second: u32, timestamp_microsecond: u32) -> Result<Self, ParseError> {
Time::from_timestamp_with_config(timestamp_second, timestamp_microsecond, &TimeConfig::default())
Time::from_timestamp_with_config(
timestamp_second,
timestamp_microsecond,
&TimeConfigBuilder::new().build(),
)
}

/// Like `from_timestamp` but with a `TimeConfig`
Expand All @@ -253,9 +257,9 @@ impl Time {
/// # Examples
///
/// ```
/// use speedate::{Time, TimeConfig};
/// use speedate::{Time, TimeConfigBuilder};
///
/// let d = Time::from_timestamp_with_config(3740, 123, &TimeConfig::default()).unwrap();
/// let d = Time::from_timestamp_with_config(3740, 123, &TimeConfigBuilder::new().build()).unwrap();
/// assert_eq!(d.to_string(), "01:02:20.000123");
/// ```
pub fn from_timestamp_with_config(
Expand Down Expand Up @@ -555,7 +559,7 @@ impl PureTime {
}
}

#[derive(Debug, Clone, Default, Copy)]
#[derive(Debug, Clone, Default, Copy, PartialEq)]
pub enum MicrosecondsPrecisionOverflowBehavior {
Truncate,
#[default]
Expand All @@ -573,8 +577,43 @@ impl TryFrom<&str> for MicrosecondsPrecisionOverflowBehavior {
}
}

#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone, Default, PartialEq)]
pub struct TimeConfig {
pub microseconds_precision_overflow_behavior: MicrosecondsPrecisionOverflowBehavior,
pub unix_timestamp_offset: Option<i32>,
}

impl TimeConfig {
pub fn builder() -> TimeConfigBuilder {
TimeConfigBuilder::new()
}
}

#[derive(Debug, Clone, Default)]
pub struct TimeConfigBuilder {
microseconds_precision_overflow_behavior: Option<MicrosecondsPrecisionOverflowBehavior>,
unix_timestamp_offset: Option<i32>,
}

impl TimeConfigBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn microseconds_precision_overflow_behavior(
mut self,
microseconds_precision_overflow_behavior: MicrosecondsPrecisionOverflowBehavior,
) -> Self {
self.microseconds_precision_overflow_behavior = Some(microseconds_precision_overflow_behavior);
self
}
pub fn unix_timestamp_offset(mut self, unix_timestamp_offset: Option<i32>) -> Self {
self.unix_timestamp_offset = unix_timestamp_offset;
self
}
pub fn build(self) -> TimeConfig {
TimeConfig {
microseconds_precision_overflow_behavior: self.microseconds_precision_overflow_behavior.unwrap_or_default(),
unix_timestamp_offset: self.unix_timestamp_offset,
}
}
}
Loading

0 comments on commit e133861

Please sign in to comment.