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.