Home > database >  recommended way to floor time_point to a given duration
recommended way to floor time_point to a given duration

Time:04-19

I have a user-provided duration

const int period_seconds = cfg.period_seconds;

I would like to floor a time_point to the granularity of that duration.

I see that there is a std::chrono::floor function for time_point and duration, but it's not immediately obvious how to use them to do what I'm looking for.

I have the following toy example which works:

const auto seconds = std::chrono::seconds{period_seconds};
const auto period = std::chrono::duration_cast<std::chrono::nanoseconds>(seconds);
const auto now = std::chrono::system_clock::now();
const auto floored = now - (now.time_since_epoch() % period);

The net effect of the above code, for a duration of 10 seconds would be the following:

now:     2022-04-19 15:06:26.781772408
floored: 2022-04-19 15:06:20.000000000    # so "floors" the 25.78 seconds to 20 seconds

I can't help but feel that working in terms of the time_since_epoch and a modulus operator isn't the "right" way of getting the result I'm looking for...

Is there a "better" / recommended way to floor a time_point to some user-provided duration?

CodePudding user response:

Your solution looks pretty good to me. However it can be slightly simplified. There's no need to form the nanoseconds-precision period. You can operate directly with seconds:

const auto floored = now - (now.time_since_epoch() % seconds);

CodePudding user response:

You could use std::chrono::floor with a custom duration, e.g. TenSecondsDuration, like shown below (if you need to be able to create that custom duration at runtime, this won't be of much help though).

[Demo]

#include <chrono>
#include <fmt/core.h>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    using TenSecondsDuration = std::chrono::duration<int, std::ratio<10>>;

    for (const auto& d : { 985s, 992s, 999s, 1006s, 1013s, 1020s }) {
        fmt::print("{}s rounded to 10s = {}\n",
            d.count(), std::chrono::floor<TenSecondsDuration>(d).count() * 10);
    }
}

// Outputs:
//
//   985s rounded to 10s = 980
//   992s rounded to 10s = 990
//   999s rounded to 10s = 990
//   1006s rounded to 10s = 1000
//   1013s rounded to 10s = 1010
//   1020s rounded to 10s = 1020
  • Related