Reputation: 413
Is there an alternative for std::chrono:ceil
in a c++ version prior to c++ 17?
I want to round a time_point to it's minute ceiling (i.e. nearest minute).
https://en.cppreference.com/w/cpp/chrono/duration/ceil
std::chrono::time_point<std::chrono::system_clock> time_point_now = std::chrono::system_clock::now();
auto start_time = std::chrono::ceil<std::chrono::minutes>(time_point_now);
...
Upvotes: 6
Views: 539
Reputation: 16747
One a bit verbose way of doing minutes-ceil (but using just <chrono>
) is:
time_point_now += std::chrono::duration_cast<std::chrono::minutes>(
(time_point_now + std::chrono::minutes(1)).time_since_epoch()) -
time_point_now.time_since_epoch();
Full example with output to console:
#include <chrono>
#include <iostream>
#include <iomanip>
int main() {
auto time_point_now = std::chrono::system_clock::now();
auto Out = [&]{
auto in_time_t = std::chrono::system_clock::to_time_t(time_point_now);
std::cout << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X")
<< std::endl;
};
Out();
time_point_now += std::chrono::duration_cast<std::chrono::minutes>(
(time_point_now + std::chrono::minutes(1)).time_since_epoch()) -
time_point_now.time_since_epoch();
Out();
}
Output:
2022-01-04 12:07:23
2022-01-04 12:08:00
One may convert solution above into handy TimeCeil()
templated function, that is exactly what you're looking for:
#include <chrono>
#include <iostream>
#include <iomanip>
template <typename Unit, typename TimePoint>
inline TimePoint TimeCeil(TimePoint const & tp) {
return tp + std::chrono::duration_cast<Unit>(
(tp + Unit(1)).time_since_epoch()) - tp.time_since_epoch();
}
int main() {
auto time_point_now = std::chrono::system_clock::now();
auto Out = [&]{
auto in_time_t = std::chrono::system_clock::to_time_t(time_point_now);
std::cout << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X")
<< std::endl;
};
Out();
time_point_now = TimeCeil<std::chrono::minutes>(time_point_now);
Out();
}
Output:
2022-01-15 10:31:10
2022-01-15 10:32:00
In both code snippets above ignore complex Out()
lambda function, it is not needed for you, it is a way to output formatted time to console, just for example.
As noted by @HowardHinnant, if you care about strictly handling very rare case when time point is exactly equal to multiple of minute, then I did small fixup such that ceil of minute-multiple time is equal to initial time (and not plus 1 minute):
#include <chrono>
#include <iostream>
#include <iomanip>
template <typename Unit, typename TimePoint>
inline TimePoint TimeCeil(TimePoint const & tp) {
auto const res = tp + std::chrono::duration_cast<Unit>(
(tp + Unit(1)).time_since_epoch()) - tp.time_since_epoch();
if (res == tp + Unit(1))
return tp;
return res;
}
int main() {
auto time_point_now = std::chrono::system_clock::now();
auto Out = [&]{
auto in_time_t = std::chrono::system_clock::to_time_t(time_point_now);
std::cout << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X")
<< std::endl;
};
Out();
time_point_now = TimeCeil<std::chrono::minutes>(time_point_now);
Out();
}
Output:
2022-01-16 11:43:00
2022-01-16 11:43:00
Upvotes: 1
Reputation: 219255
Yes, std::chrono::ceil
was extensively field tested prior to standardization in order to prove its usefulness. That field test implementation is still available here as a free, open-source, header-only library which works with C++11/14:
#include "date/date.h"
#include <chrono>
int
main()
{
auto time_point_now = std::chrono::system_clock::now();
auto start_time = date::ceil<std::chrono::minutes>(time_point_now);
}
Upvotes: 4