I have to instantiate an object of a custom library class that takes nanoseconds since 'epoch' in UTC time to construct:
class utc_time
{
public:
utc_time(TYPE nanoseconds_since_epoch):
_nanoseconds_since_epoch(nanoseconds_since_epoch){}
private:
TYPE _nanoseconds_since_epoch;
};
what I have as my input is nanoseconds since 'midnight' in UTC time. Naturally, I need to get the epoch till last midnight nanoseconds(in UTC) to add it to my input and supply it to my class constructor.
I know we have gtime that may be helpful, but I dont know how to extract the required information.
I appreciate your clues
In C++11 and later, <chrono> can be used to do this very easily:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
using namespace std;
using days = duration<int, ratio<86400>>;
nanoseconds last_midnight =
time_point_cast<days>(system_clock::now()).time_since_epoch();
cout << last_midnight.count() << '\n';
}
In deed, nanoseconds since Epoch = nanoseconds since midnight + 1e9 * calendar time of last midnight. You lack the latter value. You can built it with a conjunction of ::gmtime() and ::mktime().
#include <ctime>
std::time_t last_midnight()
{
// compute "now"
std::tm& tm = *::gmtime(NULL);
// move it to "last midnight"
tm.tm_hour = 0;
tm.tm_min = 0;
tm.tm_sec = 0;
// get time_t back
return ::mktime(&tm);
}
You may find interest in using ::gmtime_r() (re-entrant version) instead of ::gmtime().
Related
I wrote the below code to get the number of seconds since midnight.
However, I'm not great with the C time date structs. Is there a simpler way of doing this using a standard C++ library?
// Get today's date
time_t aTime = time(NULL);
// Set the time to midnight
struct tm* tm = localtime(&aTime);
tm->tm_sec = 0;
tm->tm_min = 0;
tm->tm_hour = 0;
tm->tm_isdst = -1;
time_t midnight = mktime(tm);
// Create object representing now
struct timespec now;
clock_gettime(CLOCK_REALTIME, &now);
// Number of seconds (now) since Epoch
const uint64_t nowSecsSinceEpoch = now.tv_sec;
// Number of seconds (now) since midnight = seconds (now) since Epoch minus seconds (at midnight) since Epoch
const uint64_t nowSecsSinceMidnight = nowSecsSinceEpoch - midnight;
It depends on if you mean time since midnight UTC, or time since midnight local time, or perhaps in some non-local, far away time zone.
This is also made much easier in C++20. But there exists a preview of the C++20 parts of the <chrono> library that can be used with C++11-17.
Time since midnight UTC
#include <chrono>
#include <iostream>
int
main()
{
using namespace std;
using namespace std::chrono;
auto now = system_clock::now();
auto today = floor<days>(now);
auto tod = duration_cast<seconds>(now - today);
}
This simply gets the current time (UTC), truncates it to a days-precision time_point, and then subtracts the two and truncates that difference to seconds precision.
Time since local midnight
#include <chrono>
#include <iostream>
int
main()
{
using namespace std;
using namespace std::chrono;
auto now = current_zone()->to_local(system_clock::now());
auto today = floor<days>(now);
auto tod = duration_cast<seconds>(now - today);
}
This version finds your computer's currently set local time zone, and then gets the current local time via the time_zone's to_local() member function. And then proceeds as before.
Time since some other midnight
#include <chrono>
#include <iostream>
int
main()
{
using namespace std;
using namespace std::chrono;
auto now = locate_zone("Australia/Sydney")->to_local(system_clock::now());
auto today = floor<days>(now);
auto tod = duration_cast<seconds>(now - today);
}
Finally, this version finds the time_zone associated with Sydney Australia, and then uses that time zone and proceeds as before.
The C++20 preview <chrono> library is free and open-source. It puts everything in namespace date, and in two headers (and one source):
date.h: A header-only library that will do the UTC part, but has no time zone support.
tz.h: For the time zone support. This requires some installation.
I have a problem with Visual Studio 2017.
I'm trying to get the current time and date with millisecond resolution. I tried the follwing code in a few compilers:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <ctime>
#include <chrono>
using namespace std;
using namespace chrono;
int main()
{
high_resolution_clock::time_point p = high_resolution_clock::now();
milliseconds ms = duration_cast<milliseconds>(p.time_since_epoch());
seconds s = duration_cast<seconds>(ms);
time_t t = s.count();
cout << ctime(&t) << "\n";
cin.ignore(1);
}
Every compiler except Visual Studio 2017 prints the correct time. The output of Visual Studio is:
Tue Jan 6 07:28:21 1970
the MinGW Output:
Sun Feb 03 18:01:38 2019
Is there any way to fix the code so that it works in all compilers correctly? I need high_resolution_clock to have access to milliseconds.
high_resolution_clock is an alias for the clock with the highest resoultion availavle:
Class std::chrono::high_resolution_clock represents the clock with the smallest tick period provided by the implementation. It may be an alias of std::chrono::system_clock or std::chrono::steady_clock, or a third, independent clock.
This could explain the different times you get on different compilers.
steady_clock Does not guarantee to give a time that makes sense, but is good for keeping track time:
This clock is not related to wall clock time (for example, it can be time since last reboot), and is most suitable for measuring intervals.
Is there any way to fix the code so that it works in all compilers correctly? I need high_resolution_clock to have access to milliseconds.
system_clock represents the clock of your OS:
Class std::chrono::system_clock represents the system-wide real time wall clock.
It may not be monotonic: on most systems, the system time can be adjusted at any moment. It is the only C++ clock that has the ability to map its time points to C-style time, and, therefore, to be displayed (until C++20).
If you need the milliseconds of a date or timepoint then use std::chrono::system_clock but if you just need to keep track of passed time, use std::chrono::high_resolution_clock.
To get the number of milliseconds since the start of system_clock:
auto timePoint = std::chrono::system_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>
(timePoint.time_since_epoch());
std::cout << "since epoch: " << ms.count() << " ms";
above snippet should work across most operating systems and compilers, although it is not guaranteed that time_since_epoch returns the time since 1970 but only to return the time since the clocks epoch, which in most cases is your desired behaviour.
The code assumes that time_since_epoch() returns the number of seconds since January 1, 1970 – so the value would be assignable to a variable time_t.
That assumption is wrong. time_since_epoch() can return any unit. In fact, high_resolution_clock is not designed to retrieve an absolute time and date. It's meant for performance measurements in the micro and nano seconds range.
In order to retrieve an absolute time / date, use system_clock. The class has a static method to create a time_t value:
#include <iostream>
#include <chrono>
#include <ctime>
using namespace std;
using namespace chrono;
int main()
{
time_point<system_clock> now = system_clock::now();
time_t now_time = system_clock::to_time_t(now);
cout << ctime(&now_time) << "\n"
}
Update
To get the milliseconds since Jan 1, 1970:
#include <iostream>
#include <chrono>
#include <ctime>
using namespace std;
using namespace chrono;
int main()
{
system_clock::time_point epochStart = system_clock::from_time_t(0);
long long epochStartMs = duration_cast<milliseconds>(epochStart.time_since_epoch()).count();
system_clock::time_point timePoint = system_clock::now();
long long timePointMs = duration_cast<milliseconds>(timePoint.time_since_epoch()).count();
long long durMs = timePointMs - epochStartMs;
cout << "Since 1st Jan 1970: " << durMs << " ms" << "\n";
}
For most systems, epochStartMs will probably be 0. But I think the standard doesn't guarantee that system_clock has it's epoch start on Jan 1, 1970.
I'm trying to get the current year stored in a date from before 1970 using an std::chrono::time_point<std::chrono::system_clock>, however I've run into an issue regarding the reading from its contents into a std::tm struct.
I convert the time_point to a time_t first, after which I read its values to get the tm_year value. However, when trying to do so, the code fails when using localtime_s, however it succeeds when I'm using gmtime_s. This is only for dates before 1-1-1970, dates after that work fine using both functions.
The code below reproduces the error. If terstGmTimeVsLocalTime is called with utc=true it works, if it is called with utc=false it doesn't produce the correct output.
#include <iomanip>
#include <time.h>
#include <iostream>
void testGmTimeVsLocaltime(const bool& utc) {
// Create time
std::tm timeInfoWrite = std::tm();
timeInfoWrite.tm_year = 1969 - 1900; // Year to parse, here it is 1969
timeInfoWrite.tm_mon = 0;
timeInfoWrite.tm_mday = 1;
timeInfoWrite.tm_hour = 1;
timeInfoWrite.tm_min = 0;
timeInfoWrite.tm_sec = 0;
timeInfoWrite.tm_isdst = -1;
std::chrono::time_point<std::chrono::system_clock> timePoint = std::chrono::system_clock::from_time_t(utc ? _mkgmtime(&timeInfoWrite) : std::mktime(&timeInfoWrite));
// Convert to time_t
std::time_t timeT = std::chrono::system_clock::to_time_t(timePoint);
// Read values
std::tm timeInfoRead;
if (utc) {
gmtime_s(&timeInfoRead, &timeT);
} else {
localtime_s(&timeInfoRead, &timeT);
}
// Output result
std::cout << (timeInfoRead.tm_year + 1900) << '\n';
// Wait for input
std::getchar();
}
int main() {
testGmTimeVsLocaltime(true); // Set to false to show bug
return 0;
}
utc=true outputs 1969, as would be expected. However, utc=false outputs 1899 (presumably since an error occurs and tm_year gets set to -1).
Is there anything I'm missing? The documentation doesn't specifically specify that localtime_s should fail for dates before 1-1-1970.
I'm on Windows 10 x64 if it makes a difference.
Using Howard Hinnant's free, open-source date lib, you can completely side-step the clumsy, error and bug-prone C api, and work directly with a modern <chrono>-based system:
#include "chrono_io.h"
#include "date.h"
#include <iostream>
void
testGmTimeVsLocaltime()
{
using namespace date;
// Create time
auto timeInfoWrite = 1969_y/jan/1;
sys_days timePoint = timeInfoWrite; // this is a chrono::time_point
std::cout << timePoint.time_since_epoch() << '\n'; // -365 days
// Convert to time_t
// no need
// Read values
year_month_day timeInfoRead = timePoint;
// Output result
std::cout << timeInfoRead.year() << '\n';
}
int
main()
{
testGmTimeVsLocaltime();
}
Output:
-365[86400]s
1969
There are literals to make it easy to fill in a year_month_day struct which is the analog to the year, month and day parts of a tm. You can easily convert this to a std::chrono::time_point<system_clock, days> (sys_days). This is the same as a system_clock::time_point, but with a precision of days instead. It itself will implicitly convert to a seconds-precision time_point (typedef'd to sys_seconds), or to a system_clock::time_point.
Above I just output its time_since_epoch() which shows that it is -365 days prior to the epoch.
There's never really any need to convert to C API data structures, but it is easy if you want to. For example, assuming time_t is seconds since 1970-01-01:
std::time_t timeT = sys_seconds{timePoint}.time_since_epoch().count();
std::cout << timeT << '\n';
which outputs:
-31536000
The reverse conversion (back to year_month_day) is just as easy. If you want to convert from timeT it is just slightly more involved:
year_month_day timeInfoRead = floor<days>(sys_seconds{seconds{timeT}});
This first converts time_t to chrono::seconds, and then to a seconds-precsion time_point, and then to a days-precsion time_point, finally to the year_month_day field type (tm-like).
Finally year_month_day has a year() getter member function which is streamable. You can explicitly convert year to int if desired:
int{timeInfoRead.year()}
But I think it best to keep things like years, months and days as distinct types so that the compiler can help you catch when you accidentally mix them up.
Finally, if you really meant that you wanted 1969-01-01 00:00:00 in your computer's local timezone, there's a library to do that as well. And it is just a minor modification of the simple program above.
#include "tz.h"
#include <iostream>
void
testGmTimeVsLocaltime()
{
using namespace date;
using namespace std::chrono;
// Create time
auto timeInfoWrite = 1969_y/jan/1;
auto timePoint = make_zoned(current_zone(), local_days{timeInfoWrite});
// Convert to time_t
std::time_t timeT = timePoint.get_sys_time().time_since_epoch().count();
std::cout << timeT << '\n';
// Read values
timePoint = sys_seconds{seconds{timeT}};
year_month_day timeInfoRead{floor<days>(timePoint.get_local_time())};
// Output result
std::cout << timeInfoRead.year() << '\n';
}
int
main()
{
testGmTimeVsLocaltime();
}
Output:
-31518000
1969
Now you create a zoned_seconds using the computer's current_zone() timezone, and converting your timeInfoWrite to local_days instead of to sys_days.
You can get the local time or the system time out of timePoint. For converting to time_t, system time makes the most sense:
std::time_t timeT = timePoint.get_sys_time().time_since_epoch().count();
And now the output (for me) is 5h later (18000s).
-31518000
You can get back either the local year, or the system (UTC) year, by either using .get_local_time() or .get_sys_time(). For me it makes no difference ("America/New_York"). But if you're in "Australia/Sydney", you'll get 1968 if you request the UTC year instead of 1969. And that's all very easy to simulate by simply substituting "Australia/Sydney" or "America/New_York" for current_zone() in the program above.
Yes, it works on Windows, VS-2013 and later. There is some installation required for the timezone lib: https://howardhinnant.github.io/date/tz.html#Installation
I have tried this and other codes I found online but they did not work. My IDE is Xcode.
Edit: When I tried the code on the link, the variable long long microseconds always returned 0.
I would like to print the timestamp in this manner: (hour:minute:microseconds). For example, 15:17:09:134613464312.
The method you use is correct.
If you the code between the two now() calls lasts less than a microseconds, microseconds will always be zero, since the number is not a floating point. If you have always zero, that means you need higher resolution (try nanoseconds).
Btw, if you simply want timestamp, you don't want to use this code since it is done to compute elapsed time between two time points. You can try something like this:
auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>
(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
Which is really a timestamp and not a duration.
EDIT: To have the current microseconds count, you can do something like this:
#include <iostream>
#include <chrono>
#include <ctime>
using namespace std;
using namespace std::chrono;
using days = duration<int, ratio_multiply<hours::period, ratio<24> >::type>;
int main() {
system_clock::time_point now = system_clock::now();
system_clock::duration tp = now.time_since_epoch();
days d = duration_cast<days>(tp);
tp -= d;
hours h = duration_cast<hours>(tp);
tp -= h;
minutes m = duration_cast<minutes>(tp);
tp -= m;
seconds s = duration_cast<seconds>(tp);
tp -= s;
cout << tp.count() << "\n";
return 0;
}
This will print the current microseconds count.
Hours:Minutes:Seconds is pretty easy.
I've got a problem with getting actual system time with milliseconds. The only one good method I found is in Windows.h, but I can't use it. I'm supposed to use std::chrono. How can I do this?
I spent a lot of time trying to google it, but I found only second-precision examples.
I'm trying to get string like this:
[2014-11-25 22:15:38:449]
Using code from this answer:
#include <chrono>
#include <ctime>
#include <iostream>
template <typename Duration>
void print_time(tm t, Duration fraction) {
using namespace std::chrono;
std::printf("[%04u-%02u-%02u %02u:%02u:%02u.%03u]\n", t.tm_year + 1900,
t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,
static_cast<unsigned>(fraction / milliseconds(1)));
// VS2013's library has a bug which may require you to replace
// "fraction / milliseconds(1)" with
// "duration_cast<milliseconds>(fraction).count()"
}
int main() {
using namespace std;
using namespace std::chrono;
system_clock::time_point now = system_clock::now();
system_clock::duration tp = now.time_since_epoch();
tp -= duration_cast<seconds>(tp);
time_t tt = system_clock::to_time_t(now);
print_time(*gmtime(&tt), tp);
print_time(*localtime(&tt), tp);
}
One thing to keep in mind is that the fact that the timer returns values of sub-millisecond denominations does not necessarily indicate that the timer has sub-millisecond resolution. I think Windows' implementation in VS2015 may finally be fixed, but the timer they've been using to back their chrono implementation so far has been sensitive to the OS timeBeginPeriod() setting, displaying varying resolution, and the default setting is I think 16 milliseconds.
Also the above code assumes that neither UTC nor your local timezone are offset from the epoch of std::chrono::system_clock by a fractional second value.
Example of using Howard's date functions to avoid ctime: http://coliru.stacked-crooked.com/a/98db840b238d3ce7
This answer still uses a bit of C API but is only used in the function, so you can forget about it:
template<typename T>
void print_time(std::chrono::time_point<T> time) {
using namespace std;
using namespace std::chrono;
time_t curr_time = T::to_time_t(time);
char sRep[100];
strftime(sRep,sizeof(sRep),"%Y-%m-%d %H:%M:%S",localtime(&curr_time));
typename T::duration since_epoch = time.time_since_epoch();
seconds s = duration_cast<seconds>(since_epoch);
since_epoch -= s;
milliseconds milli = duration_cast<milliseconds>(since_epoch);
cout << '[' << sRep << ":" << milli.count() << "]\n";
}
This is merely a rewrite of the code that bames53, but using strftime to shorten the code a bit.
std::chrono give you utilities to represent a point in time or the elapsed duration between two points in time. It allows you to get information about these time intervals.
It does not provide any calendar information. Unfortunately, at this time there are no tools in the C++ standard for these. boost::date_time may be helpful here.
Did anybody notice that to_time_t rounds the seconds, instead of truncating
auto now = system_clock::now();
time_t secs = system_clock::to_time_t(now);
now {_MyDur={_MyRep=15107091978759765 } }
secs = 1510709198
so when you tack on the milliseconds
auto tse = now.time_since_epoch();
auto now_ms = duration_cast<milliseconds>(tse);
auto now_s = duration_cast<seconds>(tse);
auto jst_ms = now_ms - now_s;
DWORD msecs = jst_ms.count();
msecs = 875
secs should be 1510709197, but look at now_s, it's right
now_s {_MyRep=1510709197 }