bench: add benchmarks for constructing a timestamp type

Both `chrono` and `time` use more elaborate representations for their
canonical "timestamp" data types. In contrast, Jiff just uses an integer
number of nanoseconds (like `std::time::Duration`). This makes, among
other things, construction from an integer virtually free:

    $ cargo bench -- timestamp/from_seconds
    timestamp/from_seconds/span/jiff
                            time:   [385.45 ps 385.53 ps 385.62 ps]
    Found 7 outliers among 100 measurements (7.00%)
      1 (1.00%) high mild
      6 (6.00%) high severe

    timestamp/from_seconds/duration/chrono
                            time:   [4.6363 ns 4.6375 ns 4.6387 ns]
    Found 9 outliers among 100 measurements (9.00%)
      5 (5.00%) high mild
      4 (4.00%) high severe

    timestamp/from_seconds/duration/time
                            time:   [9.6360 ns 9.6387 ns 9.6418 ns]
    Found 8 outliers among 100 measurements (8.00%)
      5 (5.00%) high mild
      3 (3.00%) high severe

Chrono doesn't really have a "timestamp" type, but `DateTime<Utc>` is
the de facto choice. `time` just recently added a `UtcDateTime` type,
which also feels a lot like a timestamp type, but its representation is
more elaborate than Jiff's.
This commit is contained in:
Andrew Gallant 2025-03-31 18:28:52 -04:00
parent ef5ee45a1b
commit a22abc7617
No known key found for this signature in database
GPG key ID: B2E3A4923F8B0D44
2 changed files with 47 additions and 0 deletions

View file

@ -112,6 +112,13 @@ impl ConvertFrom<jiff::Timestamp> for time::OffsetDateTime {
}
}
impl ConvertFrom<jiff::Timestamp> for time::UtcDateTime {
fn convert_from(x: jiff::Timestamp) -> time::UtcDateTime {
time::UtcDateTime::from_unix_timestamp_nanos(x.as_nanosecond())
.unwrap()
}
}
impl ConvertFrom<jiff::tz::Offset> for time::UtcOffset {
fn convert_from(x: jiff::tz::Offset) -> time::UtcOffset {
time::UtcOffset::from_whole_seconds(x.seconds()).unwrap()

View file

@ -13,6 +13,7 @@ use crate::{benchmark, convert::ConvertFrom};
pub(super) fn define(c: &mut Criterion) {
add_time_secs(c);
add_time_subsec(c);
from_seconds(c);
every_hour_in_week(c);
to_civil_datetime_offset_conversion(c);
to_civil_datetime_offset_holistic(c);
@ -118,6 +119,45 @@ fn add_time_subsec(c: &mut Criterion) {
}
}
/// Measures how long it takes to build the library's canonical "timestamp"
/// type from an actual integer number of seconds.
fn from_seconds(c: &mut Criterion) {
const NAME: &str = "timestamp/from_seconds";
const SECONDS: i64 = 1719755160;
const EXPECTED: Timestamp = Timestamp::constant(SECONDS, 0);
{
benchmark(c, format!("{NAME}/span/jiff"), |b| {
b.iter(|| {
let got = Timestamp::from_second(bb(SECONDS)).unwrap();
assert_eq!(got, EXPECTED);
})
});
}
{
let expected = chrono::DateTime::convert_from(EXPECTED);
benchmark(c, format!("{NAME}/duration/chrono"), |b| {
b.iter(|| {
let got =
chrono::DateTime::from_timestamp(bb(SECONDS), 0).unwrap();
assert_eq!(got, expected);
})
});
}
{
let expected = time::UtcDateTime::convert_from(EXPECTED);
benchmark(c, format!("{NAME}/duration/time"), |b| {
b.iter(|| {
let got = time::UtcDateTime::from_unix_timestamp(bb(SECONDS))
.unwrap();
assert_eq!(got, expected);
})
});
}
}
/// Measures the time it takes to iterate over a series of hours for 1 week.
///
/// This is a regression benchmark for when the `Timestamp::series` API was