Consider a historic date string of format:
Thu Jan 9 12:35:34 2014
I want to parse such a string into some kind of C++ date representation, then calculate the amount of time that has passed since then.
From the resulting duration I need access to the numbers of seconds, minutes, hours and days.
Can this be done with the new C++11 std::chrono namespace? If not, how should I go about this today?
I'm using g++-4.8.1 though presumably an answer should just target the C++11 spec.
std::tm tm = {};
std::stringstream ss("Jan 9 2014 12:35:34");
ss >> std::get_time(&tm, "%b %d %Y %H:%M:%S");
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
GCC prior to version 5 doesn't implement std::get_time. You should also be able to write:
std::tm tm = {};
strptime("Thu Jan 9 2014 12:35:34", "%a %b %d %Y %H:%M:%S", &tm);
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
New answer for old question. Rationale for the new answer: The question was edited from its original form because tools at the time would not handle exactly what was being asked. And the resulting accepted answer gives a subtly different behavior than what the original question asked for.
I'm not trying to put down the accepted answer. It's a good answer. It's just that the C API is so confusing that it is inevitable that mistakes like this will happen.
The original question was to parse "Thu, 9 Jan 2014 12:35:34 +0000". So clearly the intent was to parse a timestamp representing a UTC time. But strptime (which isn't standard C or C++, but is POSIX) does not parse the trailing UTC offset indicating this is a UTC timestamp (it will format it with %z, but not parse it).
The question was then edited to ask about "Thu Jan 9 12:35:34 2014". But the question was not edited to clarify if this was a UTC timestamp, or a timestamp in the computer's current local timezone. The accepted answer implicitly assumes the timestamp represents the computer's current local timezone because of the use of std::mktime.
std::mktime not only transforms the field type tm to the serial type time_t, it also performs an offset adjustment from the computer's local time zone to UTC.
But what if we want to parse a UTC timestamp as the original (unedited) question asked?
That can be done today using this newer, free open-source library.
#include "date/date.h"
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
using namespace date;
istringstream in{"Thu, 9 Jan 2014 12:35:34 +0000"};
sys_seconds tp;
in >> parse("%a, %d %b %Y %T %z", tp);
}
This library can parse %z. And date::sys_seconds is just a typedef for:
std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>
The question also asks:
From the resulting duration I need access to the numbers of seconds, minutes, hours and days.
That part has remained unanswered. Here's how you do it with this library.
#include "date/date.h"
#include <chrono>
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
using namespace date;
istringstream in{"Thu, 9 Jan 2014 12:35:34 +0000"};
sys_seconds tp;
in >> parse("%a, %d %b %Y %T %z", tp);
auto tp_days = floor<days>(tp);
auto hms = hh_mm_ss<seconds>{tp - tp_days};
std::cout << "Number of days = " << tp_days.time_since_epoch() << '\n';
std::cout << "Number of hours = " << hms.hours() << '\n';
std::cout << "Number of minutes = " << hms.minutes() << '\n';
std::cout << "Number of seconds = " << hms.seconds() << '\n';
}
floor<days> truncates the seconds-precision time_point to a days-precision time_point. If you subtract the days-precision time_point from tp, you're left with a duration that represents the time since midnight (UTC).
The type hh_mm_ss<seconds> takes any duration convertible to seconds (in this case time since midnight) and creates a {hours, minutes, seconds} field type with getters for each field. If the duration has precision finer than seconds this field type will also have a getter for the subseconds. Prior to C++17, one has to specify that finer duration as the template parameter. In C++17 and later it can be deduced:
auto hms = hh_mm_ss{tp - tp_days};
Finally, one can just print out all of these durations. This example outputs:
Number of days = 16079d
Number of hours = 12h
Number of minutes = 35min
Number of seconds = 34s
So 2014-01-09 is 16079 days after 1970-01-01.
Here is the full example but at milliseconds precision:
#include "date/date.h"
#include <chrono>
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
using namespace std::chrono;
using namespace date;
istringstream in{"Thu, 9 Jan 2014 12:35:34.123 +0000"};
sys_time<milliseconds> tp;
in >> parse("%a, %d %b %Y %T %z", tp);
auto tp_days = floor<days>(tp);
hh_mm_ss hms{tp - tp_days};
std::cout << tp << '\n';
std::cout << "Number of days = " << tp_days.time_since_epoch() << '\n';
std::cout << "Number of hours = " << hms.hours() << '\n';
std::cout << "Number of minutes = " << hms.minutes() << '\n';
std::cout << "Number of seconds = " << hms.seconds() << '\n';
std::cout << "Number of milliseconds = " << hms.subseconds() << '\n';
}
Output:
2014-01-09 12:35:34.123
Number of days = 16079d
Number of hours = 12h
Number of minutes = 35min
Number of seconds = 34s
Number of milliseconds = 123ms
This library is now part of C++20, but is in namespace std::chrono and found in the header <chrono>.
This is rather C-ish and not as elegant of a solution as Simple's answer, but I think it might work. This answer is probably wrong but I'll leave it up so someone can post corrections.
#include <iostream>
#include <ctime>
int main ()
{
struct tm timeinfo;
std::string buffer = "Thu, 9 Jan 2014 12:35:00";
if (!strptime(buffer.c_str(), "%a, %d %b %Y %T", &timeinfo))
std::cout << "Error.";
time_t now;
struct tm timeinfo2;
time(&now);
timeinfo2 = *gmtime(&now);
time_t seconds = difftime(mktime(&timeinfo2), mktime(&timeinfo));
time(&seconds);
struct tm result;
result = *gmtime ( &seconds );
std::cout << result.tm_sec << " " << result.tm_min << " "
<< result.tm_hour << " " << result.tm_mday;
return 0;
}
Cases covered (code is below):
since a give date until now
long int min0 = getMinutesSince( "2005-02-19 12:35:00" );
since the epoch until now
long int min1 = getMinutesSince1970( );
between two date+hours (since the epoch until a given date)
long int min0 = getMinutesSince1970Until( "2019-01-18 14:23:00" );
long int min1 = getMinutesSince1970Until( "2019-01-18 14:27:00" );
cout << min1 - min0 << endl;
Complete code:
#include <iostream>
#include <chrono>
#include <sstream>
#include <string>
#include <iomanip>
using namespace std;
// ------------------------------------------------
// ------------------------------------------------
long int getMinutesSince1970Until( string dateAndHour ) {
tm tm = {};
stringstream ss( dateAndHour );
ss >> get_time(&tm, "%Y-%m-%d %H:%M:%S");
chrono::system_clock::time_point tp = chrono::system_clock::from_time_t(mktime(&tm));
return
chrono::duration_cast<chrono::minutes>(
tp.time_since_epoch()).count();
} // ()
// ------------------------------------------------
// ------------------------------------------------
long int getMinutesSince1970() {
chrono::system_clock::time_point now = chrono::system_clock::now();
return
chrono::duration_cast<chrono::minutes>( now.time_since_epoch() ).count();
} // ()
// ------------------------------------------------
// ------------------------------------------------
long int getMinutesSince( string dateAndHour ) {
tm tm = {};
stringstream ss( dateAndHour );
ss >> get_time(&tm, "%Y-%m-%d %H:%M:%S");
chrono::system_clock::time_point then =
chrono::system_clock::from_time_t(mktime(&tm));
chrono::system_clock::time_point now = chrono::system_clock::now();
return
chrono::duration_cast<chrono::minutes>(
now.time_since_epoch()-
then.time_since_epoch()
).count();
} // ()
// ------------------------------------------------
// ------------------------------------------------
int main () {
long int min = getMinutesSince1970Until( "1970-01-01 01:01:00" );
cout << min << endl;
long int min0 = getMinutesSince1970Until( "2019-01-18 14:23:00" );
long int min1 = getMinutesSince1970Until( "2019-01-18 14:27:00" );
if ( (min1 - min0) != 4 ) {
cout << " something is wrong " << endl;
} else {
cout << " it appears to work !" << endl;
}
min0 = getMinutesSince( "1970-01-01 01:00:00" );
min1 = getMinutesSince1970( );
if ( (min1 - min0) != 0 ) {
cout << " something is wrong " << endl;
} else {
cout << " it appears to work !" << endl;
}
} // ()
Related
I have a backend process running 24*7 mostly built using C++ and I need to validate if an input date (in format YYYYMMDD) belongs in a set of next 5 business days. The input date is not a clear indicator of the current date so I am using the following function to get the current date and then calculating the next 5 business days from it.
const std::string& CurrentDateStr() {
static const std::string sDate = []() {
time_t currTime = time(NULL);
struct tm timeinfo;
localtime_r(&currTime, &timeinfo);
char buffer[16]="";
strftime(buffer, sizeof(buffer), "%Y%m%d", &timeinfo);
return std::string(buffer);
} ();
return sDate;
}
This function returns me the correct current date if the process was started today but if the process continues running till tomorrow then it will return me yesterday's date as current date due to which calculation of next 5 business days from current date goes for a toss.
Is this expected ? Is there some workaround for it or is there a better way to implement the requirement using standard C++
Your issue is the static variable. You should read up on that, because you're going to encounter it a lot. This is what the comments were trying to get you to do. You can fix your issue by just removing it:
const std::string& CurrentDateStr() {
time_t currTime = time(NULL);
struct tm timeinfo;
localtime_r(&currTime, &timeinfo);
char buffer[16]="";
strftime(buffer, sizeof(buffer), "%Y%m%d", &timeinfo);
return std::string(buffer);
}
For a more modern solution, as suggested in the comments as well, read up on chrono. Especially system_clock::now().
one way to do it using chrono:
#include <iostream>
#include <ctime>
#include <chrono>
#include <thread>
int main()
{
while (true)
{
theTime currentTime = time(nullptr);
tm* date = gmtime(¤tTime);
// Print the date and time
std::cout << "Current date and time: " << date->theDay << "/" << date->theMon + 1 << "/" << date->theYear + 1900;
std::cout << " " << date->theHour << ":" << date->theMmin << ":" << date->theSec << std::endl;
// Wait for 1 minute
std::this_thread::sleep_for(std::chrono::minutes(1));
}
}
OR Use the sleep method.
#include <iostream>
#include <ctime>
#include <unistd.h>
int main()
{
while (true)
{
time_t currentTime = time(nullptr);
tm* date = gmtime(¤tTime);
std::cout << "Current date and time: " << date->tm_mday << "/" << date->tm_mon + 1 << "/" << date->tm_year + 1900;
std::cout << " " << date->tm_hour << ":" << date->tm_min << std::endl;
// Wait for 1 minute (60 seconds)
sleep(60);
}
}
Let's say I have :
time in msec = 1655205146419 , which is generated using :
auto msec = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
Tuesday, June 14, 2022 11:12:26.419 AM
And I want to round it up to the previous midnight :
Tuesday, June 14, 2022 00:00:00.00 AM
any ideas how ?
You can use https://en.cppreference.com/w/cpp/chrono/time_point/floor with a duration https://en.cppreference.com/w/cpp/chrono/duration of 1 day:
#include <iostream>
#include <chrono>
int main()
{
using Day = std::chrono::days;
using std::chrono::duration_cast;
auto start = std::chrono::system_clock::now();
std::cout << duration_cast<std::chrono::milliseconds>(std::chrono::floor<Day>(start).time_since_epoch()).count() << "\n";
}
https://godbolt.org/z/z89nr4Mo3
increased readability when storing the days in a variable:
auto start = std::chrono::system_clock::now();
auto days = std::chrono::floor<Day>(start).time_since_epoch();
std::cout << duration_cast<std::chrono::milliseconds>(days) << std::endl;
Let's say I have : time in msec = 1655205146419
I'd try to stay within the chrono domain as much as it is possible, but if you are forced to use milliseconds since the epoch as an input value:
auto midnight_tp = system_clock::time_point(milliseconds(msec)) -
milliseconds(msec) % days(1);
// or
auto midnight_tp = floor<days>(system_clock::time_point(milliseconds(msec)));
Getting to the unitless milliseconds since the epoch again is just a repetition what you've already done earlier:
auto midnight_msec =
duration_cast<milliseconds>(midnight_tp.time_since_epoch()).count();
Demo
You could do it this way, not as pretty, but you can play a bit with std::tm and get answers that you wish.
#include <ctime>
#include <iostream>
#include <string>
int main() {
std::time_t now = time(0);
std::tm tstruct;
char current_time[20];
char last_midnight[20];
tstruct = *std::localtime(&now);
std::strftime(current_time, sizeof(current_time), "%Y-%m-%d %X", &tstruct);
tstruct.tm_hour = 00;
tstruct.tm_min = 00;
tstruct.tm_sec = 00;
std::strftime(last_midnight, sizeof(last_midnight), "%Y-%m-%d %X", &tstruct);
std::cout << "current_time: " << current_time << std::endl;
std::cout << "last_midnight: " << last_midnight << std::endl;
return 0;
}
Output results
I want to get the date, month and year information from the string.
Example Date String: Thu, 30 Jul 2020 00:51:08 -0700 (PDT)
PDT here is for Pacific Daylight time. This string offset (-0700) can change based on system timezone when the file was created.
I need to write a c++ program to extract date, month and year from this string.
Any thoughts on how to go about this?
This is a story of evolution. The correct answer greatly depends on your current toolset (how modern it is). And even if it is completely modern, there are still better tools coming.
Homo habilis
In C++98 we could stand upright. And we had tools to scan ints out of arrays of chars. scanf was the tool to do this. This result was not type safe, but we could scan ints and strings and then reinterpret those values as the components of a date: year, month and day. This might look something like this:
#include <cstdio>
#include <cstring>
#include <iostream>
int
main()
{
using namespace std;
string s = "Thu, 30 Jul 2020 00:51:08 -0700 (PDT)";
char const* months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
char wd[4] = {};
int d;
char mon[4] = {};
int y;
sscanf(s.c_str(), "%s %d %s %d", wd, &d, mon, &y);
int m;
for (m = 0; m < 12; ++m)
if (strcmp(months[m], mon) == 0)
break;
++m;
cout << y << '\n';
cout << m << '\n';
cout << d << '\n';
}
This outputs:
2020
7
30
Notes:
The " 00:51:08 -0700 (PDT)" is never even parsed. It could be parsed. But it is a lot more work.
There's no error checking. This might be a valid date or might not.
There's no type safety. The results are just ints and if you mix them up, it's a run-time error, not a compile-time error.
Neanderthal
Using C++98, there's also a popular but non-standard solution: strptime.
#include <time.h>
#include <iostream>
int
main()
{
using namespace std;
string s = "Thu, 30 Jul 2020 00:51:08 -0700 (PDT)";
tm tm;
strptime(s.c_str(), "%a, %d %b %Y %T", &tm);
cout << tm.tm_year + 1900 << '\n';
cout << tm.tm_mon + 1 << '\n';
cout << tm.tm_mday << '\n';
cout << tm.tm_hour << '\n';
cout << tm.tm_min << '\n';
cout << tm.tm_sec << '\n';
}
strptime is in the POSIX standard, but not in the C or C++ standards. It is also supported by MS Visual Studio. So it is a popular extension. And with good reason. It is much higher level, and puts the results into a struct tm: A type representing a date/time; the beginnings of type safety.
Output:
2020
7
30
0
51
8
There are still some problems:
" -0700 (PDT)" is never parsed. There's no way to ask strptime to do this.
There are weird and inconsistent offsets on the different fields of tm. For example the month is zero-based and the day is one-based. But at least it knows how to parse the time too, and relatively easily.
Error checking is there but easy to ignore. strptime returns NULL if something bad happens.
Cro-Magnon
With C++11 arrived an actual C++ wrapper around strptime that was officially recognized by the C++ standard with std::get_time:
#include <iomanip>
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
string s = "Thu, 30 Jul 2020 00:51:08 -0700 (PDT)";
istringstream in{s};
in.exceptions(ios::failbit);
tm tm;
in >> get_time(&tm, "%a, %d %b %Y %T");
cout << tm.tm_year + 1900 << '\n';
cout << tm.tm_mon + 1 << '\n';
cout << tm.tm_mday << '\n';
cout << tm.tm_hour << '\n';
cout << tm.tm_min << '\n';
cout << tm.tm_sec << '\n';
}
With a C++ wrapper you can parse from streams, which gives you access to throwing an exception on parse failure. But it is still a simple wrapper and so the result is just a tm. This has the same weirdness as the previous solution.
The output is the same as in the previous solution:
2020
7
30
0
51
8
Homo sapiens
Though the strongly typed std::chrono time_point / duration system was introduced in C++11, it is not until C++20 that it is integrated with the civil calendar, gaining get_time-like functionality, and going far beyond that.
#include <chrono>
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
using namespace std::chrono;
string s = "Thu, 30 Jul 2020 00:51:08 -0700 (PDT)";
istringstream in{s};
in.exceptions(ios::failbit);
local_seconds t;
in >> parse("%a, %d %b %Y %T %z (%Z)", t);
auto td = floor<days>(t);
year_month_day ymd{td};
hh_mm_ss hms{t-td};
cout << ymd << ' ' << hms << '\n';
cout << ymd.year() << '\n';
cout << ymd.month() << '\n';
cout << ymd.day() << '\n';
cout << hms.hours() << '\n';
cout << hms.minutes() << '\n';
cout << hms.seconds() << '\n';
}
Output:
2020-07-30 00:51:08
2020
Jul
30
0h
51min
8s
The first thing to notice is the much stronger type-safety. No longer is there a need to convert everything to ints to print it out. And no longer is it necessary to convert to ints to do other operations such as arithmetic and comparison.
For example ymd.year() has type std::chrono::year, not int. If necessary, one can explicitly convert between these two representations. But it is generally unnecessary, and akin to a risky reinterpret_cast.
There are no longer unintuitive biases such as 1900, or zero-based counts in unexpected places.
Output generally includes the units for easier debugging.
The " -0700 (PDT)" is parsed here! These values are not used in the results, but they must be there, else there is a parse error. And if you want to get these values, they are available with very simple changes:
string abbrev;
minutes offset;
in >> parse("%a, %d %b %Y %T %z (%Z)", t, abbrev, offset);
...
cout << offset << '\n';
cout << abbrev << '\n';
Now the output includes:
-420min
PDT
If you need the fields in UTC, instead of in local time, that is one simple change:
sys_seconds t;
instead of:
local_seconds t;
Now the offset is subtracted from the parsed time point to result in a UTC time_point (a std::chrono::time_point based on system_clock) instead and the output changes to:
2020-07-30 07:51:08
2020
Jul
30
7h
51min
8s
This allows you to easily parse local times plus offset directly into system_clock::time_point.
Though not shipping yet (as I write this), vendors are working on implementing this. And in the meantime you can get this functionality with a free, open-source, header-only C++20 <chrono> preview library that works with C++11/14/17. Just add #include "date/date.h" and using namespace date; and everything just works. Though with C++11/14 you will need to substitute hh_mm_ss<seconds> hms{t-td}; for hh_mm_ss hms{t-td}; (lack of CTAD).
#include <time.h>
char *strptime(const char *buf, const char *format, struct tm *tm);
I have converted a timestamp (UTC) since Epoch to a boost::posix_time::ptime and applied a timezone, resulting in a boost::local_time::local_date_time object. However, I cannot retrieve the year, month, day, hh/mm/ss/ns or nanoseconds since midnight for the adjusted date time.
It appears the local_date_time object doesn't provide getters for these.
I can't get these from the boost::posix_time::ptime because it hasn't been shifted for timezone.
What's the best approach?
using namespace boost::gregorian;
using namespace boost::local_time;
using namespace boost::posix_time;
// Create timezone
tz_database tz_db;
tz_db.load_from_file("libs/date_time/data/date_time_zonespec.csv");
time_zone_ptr chicago_tz = tz_db.time_zone_from_region("America/Chicago");
// Create Epoch offset (seconds)
std::time_t btime_ = nanosSinceEpochUTC / 1E9;
ptime dateTime = boost::posix_time::from_time_t(btime_);
// Create local Chicago time at Epoch offset
const local_date_time chicago(dateTime, chicago_tz);
// I need to retrieve the year/month/day/hh/mm/ss etc from the adjusted time, not the ptime.
The time properties are in the time_of_day() sub object. The representation type of that subobject is time_duration and it has all the accessors you want:
Live On Coliru
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/tz_db_base.hpp>
int main() {
// Create timezone
boost::local_time::tz_database tz_db;
{
std::istringstream iss(R"("America/Chicago","CST","Central Standard Time","CDT","Central Daylight Time","-06:00:00","+01:00:00","2;0;3","+02:00:00","1;0;11","+02:00:00")");
tz_db.load_from_stream(iss);
}
auto chicago_tz = tz_db.time_zone_from_region("America/Chicago");
// Create Epoch offset (seconds)
std::time_t btime_ = 1596241091; // nanosSinceEpochUTC / 1E9;
auto dateTime = boost::posix_time::from_time_t(btime_);
std::cout << "ptime: " << dateTime << "\n";
// Create local Chicago time at Epoch offset
const boost::local_time::local_date_time chicago(dateTime, chicago_tz);
std::cout << "local_date_time: " << chicago << "\n";
// I need to retrieve the year/month/day/hh/mm/ss etc from the adjusted
// time, not the ptime.
std::cout << "year/m/d: " << chicago.local_time().date() << "\n";
auto tod = chicago.local_time().time_of_day();
std::cout << "time_of_day: " << tod << "\n";
std::cout << "hh, mm, ss: " <<
tod.hours() << ", " <<
tod.minutes() << ", " <<
tod.seconds() << "\n";
}
As you can see, it's important to access through the local_time() accessor. Note how all the items (day, month, hours) wrapped back correctly according to the time zone.
Prints:
ptime: 2020-Aug-01 00:18:11
local_date_time: 2020-Jul-31 19:18:11 CDT
year/m/d: 2020-Jul-31
time_of_day: 19:18:11
hh, mm, ss: 19, 18, 11
What I do is as follows: I am naming one class after the name of a time zone. In my case gmt and fetch everything via instances of my very own time as well as date class.
class gmt {
string get(string& s) {
this->dt= this->d.getDay();
this->tm= this->d.getTime();
s= "expires="+this->d.getName(this->d.getDayName())
+", " +this->dt.substr( 0, 2) +"-" +this->d.getMonthName() +"-" +this->dt.substr( 8, 2)
+" " +this->tm +" GMT";
return s;
}
friend class cookie;
string dt, tm;
MyDate d;
};
Okay, it isn't "boost" but you can solve it via its own std and isn't that contrary.
So say I set a time in tm to be 23:00:00
ptm->tm_hour = 23; ptm->tm_min = 0; ptm->tm_sec = 0;
And I want to allow a user to subtract time from this
ptm->tm_hour -= hourinput; ptm->tm_min -= minuteinput; ptm->tm_sec -= secondinput;
If the user subtracts 0 hours, 5 minutes, and 5 seconds, instead of showing up as 22:54:55, it will show up as 23:-5:-5.
I suppose I could do a bunch of if statements to check if ptm is below 0 and account for this, but is there a more efficient way of getting the proper time?
Yes, you can use std::mktime for this. It doesn't just convert a std::tm to a std::time_t, it also fixes the tm if some field went out of range. Consider this example where we take the current time and add 1000 seconds.
#include <iostream>
#include <iomanip> // put_time
#include <ctime>
int main(int argc, char **argv) {
std::time_t t = std::time(nullptr);
std::tm tm = *std::localtime(&t);
std::cout << "Time: " << std::put_time(&tm, "%c %Z") << std::endl;
tm.tm_sec += 1000; // the seconds are now out of range
//std::cout << "Time in 1000 sec" << std::put_time(&tm, "%c %Z") << std::endl; this would crash!
std::mktime(&tm); // also returns a time_t, but we don't need that here
std::cout << "Time in 1000 sec: " << std::put_time(&tm, "%c %Z") << std::endl;
return 0;
}
My Output:
Time: 01/24/19 09:26:46 W. Europe Standard Time
Time in 1000 sec: 01/24/19 09:43:26 W. Europe Standard Time
As you can see, the time went from 09:26:46 to 09:43:26.
Here's another approach using Howard Hinnant's date library, which is on its way into C++2a.
#include <iostream>
#include "date/date.h"
using namespace std::chrono_literals;
// Time point representing the start of today:
auto today = date::floor<date::days>(std::chrono::system_clock::now());
auto someTp = today + 23h; // Today, at 23h00
auto anotherTp = someTp - 5min - 5s; // ... should be self-explanatory now :)
std::cout << date::format("%b-%d-%Y %T\n", anotherTp);
If you want to expose the manipulation of time points via a user interface, the compile-time constructs 23h, 5min and so on are of course not available. Those literals construct std::chrono::duration objects, so you need a mechanism to turn user input into equivalent instances.