Convert std::chrono::time_point to unix timestamp - c++

How can I get an std::chrono::duration since a fixed date? I need this to convert a std::chrono::time_point to an unix timestamp.
Insert code into XXX
auto unix_epoch_start = XXX;
auto time = std::chrono::system_clock::now();
auto delta = time - unix_epoc_start;
auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(delta).count();
I know time_point has a method time_since_epoch() but it's not guaranteed that this is the same as the unix epoch (00:00:00 UTC on 1 January 1970).

A unix time stamp is defined as the number of seconds since January 1, 1970 UTC, except not counting all the seconds. This is somewhat ridiculous and one has to wonder what the point of it is, so I agree that this is a silly question.
Anyway, lets look at some platform documentation for time_t and time().
Linux:
time() returns the time as the number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).
POSIX.1 defines seconds since the Epoch using a formula that approximates the number of seconds between a specified time and the Epoch. This formula takes account of the facts that all years that are evenly divisible by 4 are leap years, but years that are evenly divisible by 100 are not leap years unless they are also evenly divisible by 400, in which case they are leap years. This value is not the same as the actual number of seconds between the time and the Epoch, because of leap seconds and because system clocks are not required to be synchronized to a standard reference. The intention is that the interpretation of seconds since the Epoch values be consistent; see POSIX.1-2008 Rationale A.4.15 for further rationale.
Windows:
The time function returns the number of seconds elapsed since midnight (00:00:00), January 1, 1970, Coordinated Universal Time (UTC), according to the system clock.
Mac OS X:
The functions ctime(), gmtime(), and localtime() all take as an argument
a time value representing the time in seconds since the Epoch (00:00:00
UTC, January 1, 1970;
The asctime(), ctime(), difftime(), gmtime(), localtime(), and mktime()
functions conform to ISO/IEC 9899:1990 (ISO C90''), and conform to
ISO/IEC 9945-1:1996 (POSIX.1'') provided the selected local timezone
does not contain a leap-second table (see zic(8)).
Similar documentation can be found for other systems, such as AIX, HP-UX, Solaris, etc.
So although not specified in C++ there is an easy and widely portable way to get a Unix timestamp:
auto unix_timestamp = std::chrono::seconds(std::time(NULL));
And if you want a number of milliseconds since 1 Jan 1970 UTC (similarly not counting all of them) then you can do this:
int unix_timestamp_x_1000 = std::chrono::milliseconds(unix_timestamp).count();
Just remember that these values aren't real times, so you can't in general use unix timestamps in arithmetic. For example subtracting unix timestamps does not give you an accurate count of seconds between the times. Or if you did something like:
std::chrono::steady_clock::now() - unix_timestamp;
you would not get a time point actually corresponding to 1970-01-01 00:00:00+0000.
As Andy Prowl suggests you could do something silly like:
// 1 Jan 1970 (no time zone)
std::tm c = { 0, 0, 0, 1, 0, 70, 0, 0, -1};
// treat it as 1 Jan 1970 (your system's time zone) and get the
// number of seconds since your system's epoch (leap seconds may
// or may not be included)
std::time_t l = std::mktime(&c);
// get a calender time for that time_point in UTC. When interpreted
// as UTC this represents the same calendar date and time as the
// original, but if we change the timezone to the system TZ then it
// represents a time offset from the original calendar time by as
// much as UTC differs from the local timezone.
std::tm m = *std::gmtime(&l);
// Treat the new calendar time as offset time in the local TZ. Get
// the number of seconds since the system epoch (again, leap seconds
// may or may not be counted).
std::time_t n = std::mktime(&m);
l -= (n-l); // subtract the difference
l should now represent the (wrong) number of seconds since 1 Jan 1970 UTC. As long as there are no leap seconds between the system epoch and 1 Jan 1970 (system time zone), or within an equal amount of time in the other direction from the system epoch, then any counted leap seconds should cancel out and l will be wrong in just the way that unix timestamps are wrong.
Another option is to use a decent date library such as Howard Hinnant's chrono::date. (Howard Hinnant was one of the guys that worked on the C++11 <chrono> library.)
auto now = system_clock::now();
sys_days today = time_point_cast<days>(now);
system_clock::time_point this_morning = today;
sys_days unix_epoch = day(1)/jan/1970;
days days_since_epoch = today - unix_epoch;
auto s = now - this_morning;
auto tz_offset = hours(0);
int unix_timestamp = (days_since_epoch + s + tz_offset) / seconds(1);
If you want to handle leap seconds Howard Hinnant also provides a library that includes facilities for handling them as well as for parsing time zone databases as the source for leap second data.

what about this C++11 implementation
auto microsecondsUTC = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();

Long story short, here is the function I use to get Unix timestamp (seconds count since Jan 1, 1970 UTC):
static uint64_t getUnixTimeStamp(const std::time_t* t = nullptr)
{
//if specific time is not passed then get current time
std::time_t st = t == nullptr ? std::time(nullptr) : *t;
auto secs = static_cast<std::chrono::seconds>(st).count();
return static_cast<uint64_t>(secs);
}
The advantage of this function is that the default parameter value just gives you current time. However if you wanted to convert some specific time to unix timestamp than you can do so as well.

You could use mktime() to convert the desired date encoded in a tm structure into a local-time time_t value.
If you need a UTC time, then use gmttime() to convert that time_t value into a UTC tm structure, and figure out from the output you get which tm structure yields the desired UTC time_t when given in input to mktime().
A bit elaborate, but hopefully it will work or at least provide a hint.

I know time_point has a method time_since_epoch() but it's not
guaranteed that this is the same as the unix epoch (00:00:00 UTC on 1
January 1970).
As of C++20 and P0355R7, std::chrono::time_point::time_since_epoch can be guaranteed to be the UNIX epoch when the std::chrono::time_point is a std::chrono::system_clock.

Related

How do I get the current Unix timestamp in milliseconds, in D?

How can I get the current unix timestamp (milliseconds since January 1st, 1970) as a long variable?
In other words, how would I implement this function?
long getUnixTimestampMillis() {
}
Updated answer!
There are two functions in std.datetime.systime: stdTimeToUnixTime and unixTimeToStdTime, which convert between unix time (seconds since 1970-1-1) and stdTime (hecto-nanoseconds since Proleptic Gregorian Calendar epoch) See the docs for unixTimeToStdTime
If your intent is to pass the value into a function that accepts a typical unix time (in seconds, not milliseconds), then you can the following function:
time_t getUnixTimestamp() {
import std.datetime;
return Clock.currTime().stdTime().stdTimeToUnixTime();
}
However, if your goal truly is milliseconds since the unix epoch, the OP's code is correct. But here is a condensed version that doesn't rely on the unix epoch knowledge (this is how stdTimeToUnixTime works internally). The key is that SysTime(unixTimeToStdTime(0)) gives a SysTime that is set at the unix epoch. From there you can do whatever math you like.
long getUnixTimestampMillis() {
import std.datetime;
return (Clock.currTime() - SysTime(unixTimeToStdTime(0)))
.total!"msecs";
}
I did some experimentation on my own, and I came up with the following solution:
long getUnixTimestampMillis() {
import std.datetime;
SysTime now = Clock.currTime();
SysTime unixEpoch = SysTime(DateTime(1970, 1, 1), UTC());
Duration diff = now - unixEpoch;
return diff.total!"msecs";
}
However, I'm open to suggestions for how to improve this!

How can I convert a UTC timestamp to local time, seconds past the hour?

I have a large data set with timestamps that are in UTC time in milliseconds. I'm synchronizing this data set with another's who has timestamps of microseconds past the hour, so I need to convert the first to local time, in seconds past the hour.
Most of the similar questions I've read on this subject get UTC time from the time() function which gets the current time.
I've tried implementing the following which was pulled from C++ Reference.
The timestamp I'm trying to convert is a double, but I'm not sure how to actually use this value.
An example ts from my data set: 1512695257869
int main ()
{
double my_utc_ts; //value acquired from the data set
time_t rawtime;
struct tm * ptm;
time ( &rawtime ); //getting current time
//rawtime = my_utc_ts; //this is what I tried and is wrong, and results in a nullptr
ptm = gmtime ( &rawtime );
puts ("Current time around the World:");
printf ("Phoenix, AZ (U.S.) : %2d:%02d\n", (ptm->tm_hour+MST)%24, ptm->tm_min);
return 0;
}
After I'm able to convert it to a usable gmtime object or whatever, I need to get seconds past the hour... I think I'll be able to figure this part out if I can get the UTC timestamps to successfully convert, but I haven't thought this far ahead.
Guidance would be much appreciated. Thanks in advance.
After I'm able to convert it to a usable gmtime object or whatever, I need to get seconds past the hour...
Here is how you can convert a double representing milliseconds since 1970-01-01 00:00:00 UTC to seconds past the local hour using Howard Hinnant's, free, open-source, C++11/14/17 timezone library which is based on <chrono>:
#include "date/tz.h"
#include <iostream>
int
main()
{
using namespace std::chrono;
using namespace date;
double my_utc_ts = 1512695257869;
using ms = duration<double, std::milli>;
sys_time<milliseconds> utc_ms{round<milliseconds>(ms{my_utc_ts})};
auto loc_s = make_zoned(current_zone(), floor<seconds>(utc_ms)).get_local_time();
auto sec_past_hour = loc_s - floor<hours>(loc_s);
std::cout << utc_ms << " UTC\n";
std::cout << sec_past_hour << " past the local hour\n";
}
This outputs for me:
2017-12-08 01:07:37.869 UTC
457s past the local hour
If your local time zone is not an integral number of hours offset from UTC, the second line of output will be different for you.
Explanation of code:
We start with your input my_utc_ts.
The next line creates a custom std::chrono::duration that has double as the representation and milliseconds as the precision. This type-alias is named ms.
The next line constructs utc_ms which is a std::chrono::time_point<system_clock, milliseconds> holding 1512695257869, and represents the time point 2017-12-08 01:07:37.869 UTC. So far, no actual computation has been performed. Simply the double 1512695257869 has been cast into a type which represents an integral number of milliseconds since 1970-01-01 00:00:00 UTC.
This line starts the computation:
auto loc_s = make_zoned(current_zone(), floor<seconds>(utc_ms)).get_local_time();
This creates a {time_zone, system_time} pair capable of mapping between UTC and a local time, using time_zone as that map. It uses current_zone() to find the computer's current time zone, and truncates the time point utc_ms from a precision of milliseconds to a precision of seconds. Finally the trailing .get_local_time() extracts the local time from this mapping, with a precision of seconds, and mapped into the current time zone. That is, loc_s is a count of seconds since 1970-01-01 00:00:00 UTC, offset by your-local-time-zone's UTC offset that was in effect at 2017-12-08 01:07:37 UTC.
Now if you truncate loc_s to a precision of hours, and subtract that truncated time point from loc_s, you'll get the seconds past the local hour:
auto sec_past_hour = loc_s - floor<hours>(loc_s);
The entire computation is just the two lines of code above. The next two lines simply stream out utc_ms and sec_past_hour.
Assuming that your local time zone was offset from UTC by an integral number of hours at 2017-12-08 01:07:37 UTC, you can double-check that:
457 == 7*60 + 37
Indeed, if you can assume that your local time zone is always offset from UTC by an integral number of hours, the above program can be simplified by not mapping into local time at all:
sys_time<milliseconds> utc_ms{round<milliseconds>(ms{my_utc_ts})};
auto utc_s = floor<seconds>(utc_ms);
auto sec_past_hour = utc_s - floor<hours>(utc_s);
The results will be identical.
(Warning: Not all time zones are offset from UTC by an integral number of hours)
And if your database is known to be generated with a time zone that is not the computer's current local time zone, that can be taken into account by replacing current_zone() with the IANA time zone identifier that your database was generated with, for example:
auto loc_s = make_zoned("America/New_York", floor<seconds>(utc_ms)).get_local_time();
Update
This entire library is based on the std <chrono> library introduced with C++11. The types above utc_ms and loc_s are instantiations of std::chrono::time_point, and sec_past_hour has type std::chrono::seconds (which is itself an instantiation of std::chrono::duration).
durations can be converted to their "representation" type using the .count() member function. For seconds, this representation type will be a signed 64 bit integer.
For a more detailed video tutorial on <chrono>, please see this Cppcon 2016 presentation. This presentation will encourage you to avoid using the .count() member function as much as humanly possible.
For example instead of converting sec_past_hour to a long so that you can compare it to other values of your dataset, convert other values of your dataset to std::chrono::durations so that you can compare them to sec_past_hour.
For example:
long other_data = 123456789; // past the hour in microseconds
if (microseconds{other_data} < sec_past_hour)
// ...
This snippet shows how <chrono> will take care of units conversions for you. This means you won't make mistakes like dividing by 1,000,000 when you should have multiplied, or spelling "million" with the wrong number of zeroes.
I'd start by converting the floating point number to a time_t. A time_t is normally a count of seconds since an epoch (most often the POSIX epoch--midnight, 1 Jan 1970), so it sounds like that's going to take little more than a bit of fairly simple math.
So let's assume for the sake of argument that your input uses a different epoch. Just for the sake of argument let's assume it's using an epoch of midnight, 1 jan 1900 instead (and, as noted, it's in milliseconds instead of seconds).
So, to convert that to a time_t, you'd start by dividing by 1000 to convert from milliseconds to seconds. Then you'd subtract off the number of seconds between midnight 1 jan 1900 and midnight 1 jan 1970. Now you have a value you can treat as a time_t that the standard library can deal with1.
Then use localtime to get that same time as a struct tm.
Then zero out the minutes and seconds from that tm, and use mktime to get a time_t representing that time.
Finally, use difftime to get the difference between the two.
1. For the moment, I'm assuming your standard library is based around a standard POSIX epoch, but that's a pretty safe assumption.

std::localtime one second leads to 30 mins gap

#include <iostream>
int main(){
std::time_t t = 893665799;
std::tm * tm = std::localtime(&t);
printf("local time duration =>year:%d, month:%d, day:%d, hour:%d, min:%d, sec:%d\n",tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
t = 893665800;
tm = std::localtime(&t);
printf("local time duration =>year:%d, month:%d, day:%d, hour:%d, min:%d, sec:%d\n",tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
}
893665799 is a magic utc.
When u change ur timezone to Pitcairn Islands.
The log shows below
local time duration =>year:98, month:3, day:26, hour:23, min:59, sec:59
local time duration =>year:98, month:3, day:27, hour:0, min:30, sec:0
what's going on ? why 1 sec leads to 30 mins gap??
Given that the time_t given is exactly one second prior to rolling into a new hour, it's almost certainly to do with daylight savings time or some other adjustment.
And, with a bit of Google-fu, here it is:
27 Apr 1998 - Time Zone Change (PNT → PST)
When local standard time was about to reach Monday, 27 April 1998, 12:00:00, midnight clocks were turned forward 0:30 hours to Monday, 27 April 1998, 12:30:00 am local standard time instead.
This actually happens quite often, with various countries around the world moving their local times willy-nilly all over the place :-)
As mentioned by another answer, local times change around all the time, what with the daylight savings and whatnots.
To "portably" represent one instant in time became almost impossible and so UTC is invented, which is a magical timezone* that is the standard way to represent time, only taking into account leap seconds.
To correctly handle all these cases is incredibly tedious, but thankfully Howard Hinnant has this amazing library that does everything for you :)
* UTC is not really a timezone

What's the most efficient way to programmatically check if the year is changed

I am trying to capture packets from the NIC and save part of the packet payload as a string.
On part of packet that must be stored is its Log Time known as SysLog. Each packets has a SysLog with the following Format:
Nov 01 03 14:50:25 TCP...[other parts of packet Payload]
As it can be seen, the packet SysLog has no Year Number. My program must be running all over the year, so I need to add Year Number to the packet SysLog and convert SysLog to epoch time. The final string that I have to store is like this:
1478175389-TCP, ….
I use the following peace of code to convert Syslog to EpochTime.
tm* tm_date = new tm();
Std ::string time = Current_Year;
time += " ";
time += packet.substr(0,18);
strptime(time.c_str(), "%Y %b %d %T", tm_date);
EpochTime = timegm(tm_date);
The currentYear Method:
std::string currentYear() {
std::stringstream now;
auto tp = std::chrono::system_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch());
size_t modulo = ms.count() % 1000;
time_t seconds = std::chrono::duration_cast<std::chrono::seconds>(ms).count();
#if HAS_STD_PUT_TIME
#else
char buffer[25]; // holds "2013-12-01 21:31:42"
if (strftime(buffer, 25, "%Y", localtime(&seconds))) {
now << buffer;
}
#endif // HAS_STD_PUT_TIME
return now.str();
}
The above operations are what i have to do for every packets. The packet rate is 100000-1000000 pps and the above peace of code is very time consuming specially on currentYear().
One possible optimization is to remove currentYear() Method and save the
Year number as a constant value. As said earlier my program must be run all over the year and as you know 2017 is comming. We can not change our binary at 31/12/2016 23:59:00 and also we don’t want to waste our time for calculating Year Number!!
I need a more efficient way to calculate the current year number without running it for each packet.
Is it possible? What is your suggestion for me?
Once you have obtained the current date and time, based on this it shouldn't be too difficult to calculate what the epoch time will be for midnight of next January 1st.
After calculating the expected epoch time for when the year rolls around, going forward all you have to do is compare it to the current time, when making a log entry. If it hasn't reached the precalculated Jan 1 midnight time, you know that the year hasn't rolled around yet.
So, you don't need to calculate the year for every packet at all. Just need to check the current time against the precalculated January 1st midnight time, which shouldn't change unless the politicians decide to change your timezone, while all of this is running...
The year is changed for log entries beginning with Jan, and only those log entries.
Log entries sometimes come out of order, or carry a timestamp saved during previous processing.
Attaching the year from the PC clock will give bad results, such as
2016 Dec 31 23:59:58 normal
2016 Jan 01 00:01:01 printing time placed in packet by remote device, remote clock is running a bit fast
2017 Dec 31 23:59:59 printing timestamp saved locally two seconds before logging occurred
2017 Jan 01 00:00:03 back to normal
You can't just concatenate the year of local clock with the month...second of the log message. You have to assign the year that avoids large clock jumps.
Since you're trying to produce Unix time (seconds since epoch) anyway, start by turning the log message time into Julian (seconds since start of year) and test whether the Julian is less than or greater than say 10 million (roughly 4 months).
You can "cache" the string you generate and only change it when the year changes. It may be though just a "little" improvement depending on what operations take the most time.
//somewhere
static int currentYear = 0;
static std::string yearStr = "";
//in your function
auto now = std::chrono::system_clock::now();
auto tnow = system_clock::to_time_t(now);
auto lt = localtime(&tnow); //or gmtime depends on your needs.
if(currentYear != lt.tm_year)
{
yearStr = std::to_string(lt.tm_year + 1900);
currentYear = t.tm_year;
}
return yearStr;
I am not sure if static has any negative/positive aspects on the performance of reading the string or a member variable may be better here due to cache locality. You have to test this.
If you use this in multiple threads you have to use a mutex here which probably will reduce performance though (again you have to measure this).
First, you might consider currentYear() returning an int (e.g. 2016), probably with time(2), localtime_r(3), the tm_year field.... You'll then avoid making C++ strings.
Then, you speak of high packet rate, so you probably have some event loop. You don't explain how it is done (hopefully you use some library à la libevent, or at least your own loop around poll(2)....), but you might compute the current year only once every tenth of second in that event loop. Or have some other thread computing the current year once in a while (you'll probably need a mutex, or use std::atomic<int> as the type of current year...)

Time Converter - time(NULL) to WINDOWS time

Is there a tool that converts the time(NULL) value to the WINDOWS time.
The time(NULL) will give time in seconds since Jan 1, 1970. Now if i enter that value to this tool it must give me the time in date and hours, minutes and seconds.
In C++ we use the time(NULL) object a lot to send time.
See this KB from Microsoft, and chain with this function.
If by Windows time you mean the 64-bit time used in NTFS, you can use the conversion:
int64 wintime = 100000000uL * time(NULL) + 0x19db1ded53e8000uLL
where
int64 is the type used by your compiler for 64-bit integers.
NT time is based on the origin at 1601-01-01 00:00:00 utc and counts ten million units per second—a timing precision of 100 ns. It assumes a simple leap year sequence and ignores the calendar complexities around 1752.
So, by multiplying the Unix time by ten million, and adding 116444736000000000 (decimal) or 0x19DB1DED53E8000, which is the difference between 1970-01-01 and 1601-01-01, one can easily convert from one to the other.