Convert nanoseconds (since midnight) to printable time? - c++

I have a uint64_t representing the number of nanoseconds since midnight. Would std::chrono allow me to convert this into a meaningful "time", relatively simply?
Also, how would I do it if I have the time since epoch?
For example in such a format:
14:03:27.812374923
And same situation, but when given nanoseconds since epoch? (in case the answer is significantly different)

You could use Howard Hinnant's, free, open-source, header-only library to do this:
#include "date.h"
#include <cstdint>
#include <iostream>
int
main()
{
using namespace std;
using namespace std::chrono;
using namespace date;
uint64_t since_midnight = 50607812374923;
cout << make_time(nanoseconds{since_midnight}) << '\n';
uint64_t since_epoch = 1499522607812374923;
cout << sys_time<nanoseconds>{nanoseconds{since_epoch}} << '\n';
}
This outputs:
14:03:27.812374923
2017-07-08 14:03:27.812374923
Or did you need to take leap seconds into account for since_epoch?
cout << utc_time<nanoseconds>{nanoseconds{since_epoch}} << '\n';
2017-07-08 14:03:00.812374923
For this latter computation, you'll need "tz.h" documented here, and this library is not header only.

Related

Converting time in milliseconds since epoch to time in yy-dd-hh-ss format

I have a bunch of tasks which are in the order of microseconds, the below code prints only until seconds (Thu Oct 21 12:48:20 2021) so comparing the values of start and finish always ends up giving 0. I want to be able to compare in the order of milliseconds and microseconds. Is there a function to help with this?
Also, is there a way to convert uint64_t current1 = std::chrono::system_clock::now().time_since_epoch().count(); to time_t to print out the current time based on the count()?
const auto p1 = std::chrono::system_clock::now();
std::time_t now = std::chrono::system_clock::to_time_t(p1);
std::cout << "now: " << std::ctime(&now);
I recommend skipping the C timing API entirely. It is error-prone and doesn't handle sub-second precision.
If UTC (as opposed to local time) is ok, then there is a header-only, open-source preview of C++20 that works with C++11/14/17:
#include "date/date.h"
#include <chrono>
#include <iostream>
int
main()
{
using date::operator<<;
const auto p1 = std::chrono::system_clock::now();
std::cout << "now: " << p1 << '\n';
}
Output:
now: 2021-10-21 20:28:15.754423
To port the above program to C++20 (which is already shipping in the latest Visual Studio), just drop the #include "date/date.h" and using date::operator<<;.
If you need local time, that can be also be had in C++20 (shipping in VS), but the open-source preview of C++20 is no longer header only. There exists one source file that needs to be compiled, and depending on your needs, might require a download of the IANA tz database.
#include "date/tz.h"
#include <chrono>
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
const auto p1 = system_clock::now();
std::cout << "now: " << zoned_time{current_zone(), p1} << '\n';
}
Output:
now: 2021-10-21 16:28:15.754423 EDT
The above syntax assumes C++17. For C++11/14 the template parameter for zoned_time needs to be specified: zoned_time<system_clock::duration>.
The above program ports to C++20 by dropping #include "date/tz.h" and using namespace date;.
In either program you can truncate to millisecond precision with:
const auto p1 = floor<milliseconds>(system_clock::now());
time_t is usually an integer specifying (whole) seconds.
You could get the millseconds by subtracting the whole-second time_t from now:
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
p1 - std::chrono::system_clock::from_time_t(now)).count();
or using operator%:
auto ms = std::chrono::time_point_cast<std::chrono::milliseconds>p1)
.time_since_epoch() % std::chrono::seconds(1);
std::cout << ms.count();
Example how you could do the formatting:
#include <chrono>
#include <iostream>
#include <iomanip>
int main() {
using Clock = std::chrono::system_clock;
using Precision = std::chrono::milliseconds;
auto time_point = Clock::now();
// extract std::time_t from time_point
std::time_t t = Clock::to_time_t(time_point);
// output the part supported by std::tm
std::cout << std::put_time(std::localtime(&t), "%FT%T."); // select format here
// get duration since epoch
auto dur = time_point.time_since_epoch();
// extract the sub second part from the duration since epoch
auto ss =
std::chrono::duration_cast<Precision>(dur) % std::chrono::seconds{1};
// output the millisecond part
std::cout << std::setfill('0') << std::setw(3) << ss.count();
}

C++ Parsing TimeZone From Date String

Hello I have the following date that I am consuming from an api
string sToParse = "2020-04-17T09:30:00-04:00";
which should be in human form "Friday, April 17, 2020 08:30:00" central time
or epoch of 1587130200
however this code
cout << "raw: " << sToParse << endl;
static const std::string dateTimeFormat { "%Y-%m-%dT%H:%M:%S%Z" };
istringstream ss{ sToParse };
tm dt;
ss >> get_time(&dt, dateTimeFormat.c_str());
cout << mktime(&dt) << endl;
Gives me an epoch of 1587137400 which is a human format of "Friday, April 17, 2020 10:30:00 AM" which is two hours difference. How do i get the %Z to process the timezone appropriately?
Thanks in advance for any help you can give
C++20 will do this:
#include <chrono>
#include <iostream>
#include <sstream>
#include <string>
int
main()
{
using namespace std;
using namespace std::chrono;
string sToParse = "2020-04-17T09:30:00-04:00";
cout << "raw: " << sToParse << endl;
static const std::string dateTimeFormat { "%Y-%m-%dT%H:%M:%S%z" };
istringstream ss{ sToParse };
sys_seconds dt;
ss >> parse(dateTimeFormat, dt);
cout << dt << '\n';
cout << dt.time_since_epoch() << '\n';
}
Output:
2020-04-17 13:30:00
1587130200s
This gets the "epoch time" you're looking for. The big difference is the use of %z instead of %Z. %z is the command for parsing the offset. %Z parses time zone abbreviation.
This doesn't get the "human time" you're expecting. The time printed out above is UTC. This is clearly correct on inspection: 13:30:00 is 4 hours after 09:30:00.
If you are wanting local time, it would be 2020-04-17 09:30:00, same as the input. To come up with 08:30:00 would require more information than you are providing above (e.g. output in some time zone other than that which has a UTC offset of -4h at this local time).
Also it is in general not possible to go from a UTC offset to a time zone name or abbreviation because more than one time zone will generally have the same UTC offset at any point in time.
If the C++20 <chrono> header isn't available for you (to the best of my knowledge it is not yet available anywhere), you can use a free, open-source preview of C+++20 <chrono>. For this problem, one only needs the header-only "date.h" from this preview. And everything is in namespace date instead of namespace std::chrono. It would look like this:
#include "date/date.h"
#include <chrono>
#include <iostream>
#include <sstream>
#include <string>
int
main()
{
using namespace date;
using namespace std;
using namespace std::chrono;
string sToParse = "2020-04-17T09:30:00-04:00";
cout << "raw: " << sToParse << endl;
static const std::string dateTimeFormat { "%Y-%m-%dT%H:%M:%S%z" };
istringstream ss{ sToParse };
sys_seconds dt;
ss >> parse(dateTimeFormat, dt);
cout << dt << '\n';
cout << dt.time_since_epoch() << '\n';
}
Update
With the new knowledge that the "expected human form" of the time should be US Central Time ("America/Chicago" in IANA terms), I'm updating the example code to show how that can be handled.
#include "date/tz.h"
#include <chrono>
#include <iostream>
#include <sstream>
#include <string>
int
main()
{
using namespace date;
using namespace std;
using namespace std::chrono;
string sToParse = "2020-04-17T09:30:00-04:00";
cout << "raw: " << sToParse << endl;
static const std::string dateTimeFormat { "%FT%T%z" };
istringstream ss{ sToParse };
sys_seconds utc;
ss >> parse(dateTimeFormat, utc);
zoned_seconds cst{"America/Chicago", utc};
cout << utc.time_since_epoch() << '\n';
cout << format("%F %T %Z\n", utc);
cout << format("%F %T %Z\n", cst);
}
A few changes above:
A new header is required to handle the time zone issues: "tz.h" (only in the C++20 preview library, not in C++20).
For parsing I've substituted "%Y-%m-%dT%H:%M:%S%z" for "%FT%T%z". These are equivalent. %F is just shorthand for %Y-%m-%d and %T is shorthand for %H:%M:%S. This change is not required.
I've renamed dt to utc to emphasize that this variable holds a UTC time point. This change is not required.
The new line constructs a zoned_time (with seconds precision) with the desired destination time zone ("America/Chicago"), and the UTC time point. This creates an object that knows all about the local time at this time point and in this time zone.
Then everything is printed out using the date::format function and the formatting string "%F %T %Z". %Z is used to output the time zone abbreviation to make the output more readable. In C++20, this will be std::format, and the formatting string will be "{:%F %T %Z}".
The output is now:
raw: 2020-04-17T09:30:00-04:00
1587130200s
2020-04-17 13:30:00 UTC
2020-04-17 08:30:00 CDT
If your computer's current time zone setting happens to be US Central, then the line that constructs zoned_seconds can also look like:
zoned_seconds cst{current_zone(), utc};
Or conversely, you can use this line to find the local time at utc in any time zone which your computer is set to.
Note that whether the time zone is specified with a name such as "America/Chicago", or with current_zone(), any changes of UTC offset within the specified time zone (such as daylight saving time) will be correctly taken into account.
With the preview C+++20 library, the use of the header "tz.h" is not header-only. It requires a single source file, tz.cpp. Here are instructions on how to compile it. But if you are using a fully conforming C++20 <chrono>, then the above will just work by removing #include "date/tz.h", using namespace date;, and adjusting the formatting string as noted in the 5th bullet above.

c++ chrono Clock in HH:MM:SS when it needs to be in seconds.milliseconds

So right now, the code im using is
using std::chrono::system_clock;
std::time_t tt = system_clock::to_time_t (system_clock::now());
struct std::tm * ptm = std::localtime(&tt);
std::cout << "Current time: " << std::put_time(ptm,"%X") << '\n';
std::this_thread::sleep_for (std::chrono::seconds(7));
It is simple in that this is in a loop, and chrono sleep_for delays the system for however many seconds.
The problem is that it is in the HH:MM:SS format when I really need seconds.milliseconds to show the system clock transaction time. How would I do this? I really just need someone to explain the code, why is it making a struct? And what should I do to change the format? Thanks!
I've got two answers for you:
How to do this next year (in C++20), which isn't implemented today, and
How you can do it today with some minor syntax changes and an open-source 3rd party library.
First 1:
#include <chrono>
#include <iostream>
#include <thread>
int
main()
{
using namespace std::chrono;
auto tp = system_clock::now();
while (true)
{
zoned_time zt{current_zone(), floor<milliseconds>(system_clock::now())};
cout << "Current time: " << std::format("{:%T}", zt) << '\n';
tp += 7s;
std::this_thread::sleep_until (tp);
}
}
This creates a local time using the computer's currently set time zone, with a precision of milliseconds. And then just prints it out with the desired format (%T). I'm using sleep_until instead of sleep_for so that each iteration of the loop doesn't drift off of the desired 7s interval due to loop overhead.
Second 2:
Nobody has C++20 chrono yet, but you can approximate it today with Howard Hinnant's free open source date/time library:
#include "date/tz.h"
#include <chrono>
#include <iostream>
#include <thread>
int
main()
{
using namespace date;
using namespace std::chrono;
auto tp = system_clock::now();
while (true)
{
zoned_time zt{current_zone(), floor<milliseconds>(system_clock::now())};
cout << "Current time: " << format("%T", zt) << '\n';
tp += 7s;
std::this_thread::sleep_until (tp);
}
}
The difference is that the format statement is slightly different, and the library lives in namespace date instead of namespace std::chrono. And there's an extra header to include. And some installation is required to handle the time zones.
If you're happy with a UTC time stamp, instead of a local time stamp, then you can use a header-only version of the same library like this (no installation required):
#include "date/date.h"
#include <iostream>
#include <thread>
int
main()
{
auto tp = std::chrono::system_clock::now();
while (true)
{
using namespace date;
using namespace std::chrono;
std::cout << "Current time: "
<< format("%T", floor<milliseconds>(system_clock::now())) << '\n';
tp += 7s;
std::this_thread::sleep_until (tp);
}
}

Can I avoid going through time_t to print a time_point?

Here's an example adapted from cppreference.com :
#include <iostream>
#include <iomanip>
#include <ctime>
#include <chrono>
int main() {
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t now_c = std::chrono::system_clock::to_time_t(now);
std::cout << "The time was just "
<< std::put_time(std::localtime(&now_c), "%F %T") << '\n';
}
I don't like this. I want to print my time point without having to go through time_t. Can I do so...:
at all?
with an arbitrary format like put_time supports?
Notes:
Standard library solutions are best; non-standard but robust solutions are also relevant.
Not a dupe of this - since I'm also interested in arbitrary format printing; but it should be noted that #HowardHinnant's answer to that one resolves the first part of this one.
Howard Hinnant's library - which has been voted to become part of C++20 - also supports put_time-like formatting.
#include "date/date.h"
#include <iostream>
int
main()
{
std::cout << date::format("%m/%d/%Y %I:%M:%S %p\n", std::chrono::system_clock::now());
}
Example output:
07/22/2018 03:30:35.001865 AM
A partial solution which doesn't allow you a choice of printing format or timezone, thanks to #inf's suggestion, is found in this answer: you can simply pipe a timepoint to the standard output to get a UTC timestamp string for it:
std::cout << std::chrono::system_clock::now() << " UTC\n";
but the question remains open for arbitrary formats.

elapsed time in seconds using Boost

I usually seed my RNG by the following time, obtained by a call to time.h
#include <iostream>
#include <time.h>
using namespace std;
int main()
{
cout << static_cast<unsigned int>(time(0)) << endl;
return 0;
}
Is there an equivalent to static_cast<unsigned int>(time(0)) in the Boost-library?
You can get the time using boost::posix_time. See this SO question. Ex:
boost::posix_time::time_duration diff = tick - now;
diff.total_milliseconds();
You can also use the C++11 chrono, if you can use C++11. Ex:
int elapsed_milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count();
With these two methods, you can get the number of milliseconds from the start of the day, and then assign it to your seed.