time duration calculation since from Application start deploy/run to reach midnight 12 AM in C++

Viewed 49

I have requirement like time period in seconds needs to be return from the function, since from Application is deployed to reach midnight 12:00 AM in GMT. since at 12:00AM some action needs to be taken in Application. I got to know what will be the time after 12 hours, but this will not give number of hours left to reach midnight 12 AM. can you help me what will be the correct solution.

#include <iostream>
#include <iomanip>
#include <ctime>
#include <chrono>

int main()
{
    using namespace std::literals; // enables the usage of 24h, 1ms, 1s instead of
                                   // e.g. std::chrono::hours(24), accordingly

    const std::chrono::time_point<std::chrono::system_clock> now =
        std::chrono::system_clock::now();

    const std::time_t t_c = std::chrono::system_clock::to_time_t(now - 24h);
    std::cout << "24 hours ago, the time was "
              << std::put_time(std::localtime(&t_c), "%F %T.\n") << std::flush;

    const std::time_t t_c_12 = std::chrono::system_clock::to_time_t(now + 12h);
    std::cout << "12 hours after, the time was "
              << std::put_time(std::localtime(&t_c_12), "%F %T.\n") << std::flush;
}
1 Answers

The answer is slightly different for C++17 and C++14 as the chrono tools continue to evolve to be easier to use.

First the C++17 solution:

#include <chrono>
#include <iostream>

using days = std::chrono::duration
    <int, std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>>;

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

    auto now = time_point_cast<seconds>(system_clock::now());
    auto tomorrow = ceil<days>(now);
    cout << (tomorrow - now)/1s << '\n';
}

This prints out the number of seconds until the next 12:00am (00:00:00) UTC.

The first thing you should to do is create a custom duration days which is equal to 24 hours (or 86400 seconds if you prefer).

Next get the current time. Since you want the final answer to have a precision of seconds it makes sense to just truncate the precision of the current time to seconds up front.

The next step is to truncate the precision of now again, but to a precision of days, rounding partial days up as opposed to down. This is exactly what std::chrono::ceil does. The resulting time_point tomorrow points to the next upcoming 00:00:00 UTC, or to now if now is 00:00:00 UTC.

The difference between tomorrow and now is simply the number of seconds until the next 00:00:00 UTC.

Note that at no time is there any translation into local time since the the input (system_clock::now()1) and the output (00:00:00 UTC) are both in UTC (approximately GMT as stated in the question).

The expression (tomorrow - now)/1s simply converts the number of seconds between tomorrow and now into an integral type so that it can be printed as the number of seconds.

The C++14 solution:

In C++14, std::chrono::ceil does not yet exist. Here is how to supply it yourself:

template <class To, class Rep, class Period>
constexpr
inline
To
ceil(const std::chrono::duration<Rep, Period>& d)
{
    auto t = std::chrono::duration_cast<To>(d);
    if (t < d)
        return t + To{1};
    return t;
}

template <class To, class Clock, class FromDuration>
constexpr
inline
std::chrono::time_point<Clock, To>
ceil(const std::chrono::time_point<Clock, FromDuration>& tp)
{
    using std::chrono::time_point;
    return time_point<Clock, To>{ceil<To>(tp.time_since_epoch())};
}

The C++20 solution:

I know you didn't ask for this, but in C++20 you no longer need to convert to an integral type to stream durations out. You can just:

cout << tomorrow - now << '\n';

And the output will look something like:

77094s

Also in C++20 if you would prefer the output to be in another format, such as hh:mm:ss, you can:

cout << format("{:%T}", tomorrow - now) << '\n';

to instead get:

21:24:54

Also, you no longer need to define your own days duration type. std::chrono::days exists in C++20 and you can just use that.


1 In C++14 and C++17 the epoch of system_clock::now() isn't specified to be aligned with 00:00:00 UTC, but in practice, every implementation does so. In C++20 this existing practice is specified in the standard.

Related