#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
Related
I'm looking for how to declare a time for a configurable number of minutes before 1 pm east coast time on the day of running the program. I've found ways to get a fixed time of the timezone such as:
chrono::zoned_time onePmEastCoastTime ("New York/New York", chrono::sys_days{ 2022y / chrono::April/ 15d } + 13h );
How can I declare a configurable time that will match a specific timezone?
It sounds like you want to specify the time in terms of local time as opposed to UTC. The key to this is in the use of local_days vs sys_days.
sys_days is a count of days in UTC.
local_days is a count of days in some local time that can be subsequently paired with a timezone.
Maybe you are looking for:
chrono::minutes m = ...
chrono::zoned_time onePmEastCoastTime{"America/New_York",
chrono::local_days{ 2022y / chrono::April/ 15d } + 13h - m};
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.
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...)
I need an accurate conversion in my class from UTC time to local time of a given timezone, with or without DST in effect. My problem is, that when I use struct tm I have to provide the tm_isdst member, or leave it -1 to be determined automatically.
from mktime(3) - linux man page:
"The value specified in the tm_isdst field informs mktime() whether or not daylight saving time (DST) is in effect for the time supplied in the tm structure:
a positive value means DST is in effect;
zero means that DST is not in effect;
and a negative value means that mktime() should (use timezone information and system databases to) attempt to determine whether DST is in effect at the specified time.
Now here's my problem. I'm working with exchanges from all over the globe (from Chicago, New York, Sao Paolo, Melbourne, Buenos Aires, Johannesburg, Shanghai, Seoul ...). I have a table with the name of each timezone for each of the exchanges: for example Africa/Johannesburg, America/Chicago, America/Winnipeg.
The data I'm working on is expiration for some given futures and options financial instruments. The data I'm receiving is always in UTC, and I need to convert to the local time of the exchange.
Long story short, my current implementation is adding 1 extra hour to the expiration time of those assets that should not have the DST in effect (for example an instrument that expires in December and local time is America/Chicago, should add -360 minutes offset and DST 0, while another one which expires in June in the same timezone should have -360 timezone offset +60 DST offset, which would be -300 offset to the UTC timestamp. What I'm currently having the problem with, for example for the month of December I get 9:30 AM instead of 8:30 AM as the UTC timestamp contains the dst offset already.
Here is my function for doing the conversion, which is obviously broken:
#ifdef WIN32
#define timegm _mkgmtime
#endif
SimpleDateTime BusinessDateCalculator::UTC2TZ(const SimpleDateTime& utcDateTime, const int tz_utc_offset, const int tz_dst)
{
struct tm stm;
memset(&stm, 0, sizeof(stm));
stm.tm_year = utcDateTime.getYear() - 1900;
stm.tm_mon = utcDateTime.getMonth() - 1;
stm.tm_mday = utcDateTime.getDay();
stm.tm_hour = utcDateTime.getHour();
stm.tm_min = utcDateTime.getMinute();
stm.tm_sec = utcDateTime.getSecond();
stm.tm_isdst = -1; //see note at the top of this file
time_t tt = timegm( &stm );
tt += (tz_utc_offset + tz_dst) * 60;
struct tm ntm;
memset(&ntm, 0, sizeof(ntm));
gmtime_r( &tt, &ntm );
return SimpleDateTime(ntm.tm_year + 1900, ntm.tm_mon + 1, ntm.tm_mday, ntm.tm_hour, ntm.tm_min, ntm.tm_sec, utcDateTime.getMillisecond());
}
Where SimpleDateTime is a date-time class with additional functionality, like conversion from different date/time formats (SQL, FIX, Timeonly, DateOnly).
I have the timezone information of a certain exchange available at all time. My question can I provide the timezone name somehow, and let the timegm perform a database search and determine whether in the America/Chicago timezone the DST is or is not in effect on 2014-12-19 and accordingly not add the extra 60 minutes to the UTC time, and on the same date for example in the southern hemisphere timezone America/Sao_Paulo it is in effect until 16 Feb 2015, and for this timestamp it should add 60 minutes to get the correct local time for the given date.
When you refer to a time zone by it's IANA identifier (eg "America/Chicago") - that already includes all of the DST information and full history of the time zone. At least, it does in the original source data in the IANA time zone database.
You mentioned Boost (in comments). While Boost does have support for these types of identifiers, it makes the mistake of assuming that they are permanently fixed in time. That is not true, as time zones of the world change their offsets and DST rules all the time. Consider that the USA changed its DST rules in 2007, and that Russia is changing its time zones significantly later this year (Oct. 2014). If you look at the Boost time zone data file, you'll see that its format strips away all of the history and just maps each identifier to a single set of rules. For this reason, I recommend you do not use Boost for local time zone conversions.
Instead, consider using ICU. Among other things, it includes time zone conversion functions, and uses the full copy of the IANA time zone database. You can read more here, and see sample code here. I'm not particularly skilled in C++, but it would appear that you can use ICU's Calendar class to project a UTC time to a local time in a particular time zone.
Another option would be to use the time zone functions built in to the GNU C library. It also uses the full time zone database. There's a simple example of converting UTC tor local time using an IANA/Olson identifier on this site, which I have also posted below:
/*
C source code example: Convert UTC to local time zone, considering daylight
savings. Uses mktime(), gmtime() and localtime(). Works for dates between
years 1902 and 2037. Should compile and run with any recent GNU C if your
tzdata is healthy. Written by Robert Larsson http://rl.se
Code put in public domain; do what you want with it.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define DESTZONE "TZ=Europe/Stockholm" // Our destination time zone
int main(void)
{
struct tm i;
time_t stamp; // Can be negative, so works before 1970
putenv("TZ=UTC"); // Begin work in Greenwich …
i.tm_year = 2009-1900; // Populate struct members with
i.tm_mon = 8-1; // the UTC time details, we use
i.tm_mday = 29; // 29th August, 2009 12:34:56
i.tm_hour = 12; // in this example
i.tm_min = 34;
i.tm_sec = 56;
stamp = mktime(&i); // Convert the struct to a Unix timestamp
putenv(DESTZONE); // Switch to destination time zone
printf("UTC : %s", asctime(gmtime(&stamp)));
printf("Local: %s", asctime(localtime(&stamp)));
return 0; // That’s it, folks.
}
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.