difference seen in difftime and strftime values - c++

I'm seeing a difference in time functions and was wondering what was the reason.
currently, I'm using localtime, mktime, strftime and difftime:
time_t ltime;
ltime = time(NULL);
StartTM = localtime(&ltime);
time_t time1 = mktime(StartTM );
char startbuffer [128];
strftime( start_buffer, 128, "%H:%M:%S", StartTM );
<<Do some stuff, take some time >>>
time_t ttime;
ttime = time(NULL);
StopTM = localtime(&ttime);
time_t time2 = mktime(StopTM );
char stop_buffer [128];
strftime( stop_buffer, 128, "%H:%M:%S:", StopTM );
double wtinsec = difftime(time2, time1);
Executed, the output looks like this:
Stop buffer=08:46:18
Start buffer=08:44:11
wtinsec=129
Subtracting start from stop by hand, the length of time is 2:07, however the total number of seconds (difftime) says 2:09. As both times are using the same raw data (time1, time2) for both calculations, my initial thoughts was combination of lack of precision in the strftime conversion and difftime is the cause of this.
But the difference is not constant. If the time between the 2 local calls is small (like 10 seconds) there is no difference. However, as the time between the 2 time calls gets longer, the difference in time totals becomes larger. At 2 mins, its 2 seconds at 5 mins its 4 seconds and so on...
Any reason why this is happening and is there anything more accurate (in C++) preferably in micro/milliseconds that can track time of day and subtract one from another?
Thanks.

The values in ltime and time1 should be identical; the round trip through localtime() and mktime() should give you the answer you started with. Similarly, of course, for ttime and time2.
This C code demonstrates the expected behaviour. You need to look hard at your code to find out what is going wrong.
#include <stdio.h>
#include <time.h>
#include <unistd.h>
int main(void)
{
time_t ltime = time(NULL);
struct tm *start = localtime(&ltime);
time_t time1 = mktime(start);
char startbuffer[128];
strftime(startbuffer, sizeof(startbuffer), "%H:%M:%S", start);
printf("lt = %10lu, t1 = %10lu, time = %s\n",
(unsigned long)ltime, (unsigned long)time1, startbuffer);
sleep(10);
time_t ttime = time(NULL);
struct tm *finis = localtime(&ttime);
time_t time2 = mktime(finis);
strftime(startbuffer, sizeof(startbuffer), "%H:%M:%S", finis);
printf("lt = %10lu, t1 = %10lu, time = %s\n",
(unsigned long)ttime, (unsigned long)time2, startbuffer);
printf("diff time = %.2f\n", difftime(time2, time1));
return(0);
}
Sample output (from Mac OS X 10.7.5):
lt = 1358284665, t1 = 1358284665, time = 13:17:45
lt = 1358284675, t1 = 1358284675, time = 13:17:55
diff time = 10.00
I recommend looking at the values in your code, similar to the way I did. You might (or might not) print out the contents of the struct tm structures. It would be worth making a function to handle the 7-line block of repeated code; you'll need it to return time1 and time2, of course, so you can do the difference in the 'main' code. Also remember that localtime() may return the same pointer twice; you can't reliably use the start time structure after you've called localtime() with the finish time.

Related

Convert a time (UTC ) given as a string to local time

I have a time string like this "132233" (Time only no date) and i want to convert it into local time.
So, in order to use the function localtime(), I first converted my string into time_t using mktime() (thanks to How to convert a string variable containing time to time_t type in c++? )and then printed the time after conversion using strftime as shown in (http://www.cplusplus.com/reference/ctime/strftime/)
I am getting a serious run time error. Can any one please tell me whats wrong. Thanks in advance
int main()
{
string time_sample="132233";
std::string s_hrs (time_sample.begin(), time_sample.begin()+2);
std::string s_mins (time_sample.begin()+2,time_sample.begin()+4);
std::string s_secs (time_sample.begin()+4,time_sample.begin()+6);
int hrs = atoi(s_hrs.c_str());
int mins = atoi(s_mins.c_str());
int secs = atoi(s_secs.c_str());
struct tm time_sample_struct = {0};
time_sample_struct.tm_hour = hrs;
time_sample_struct.tm_min = mins;
time_sample_struct.tm_sec = secs;
time_t converted_time;
converted_time = mktime(&time_sample_struct);
struct tm * timeinfo;
char buffer[80];
timeinfo = localtime(&converted_time);
strftime(buffer,80,"%I:%M:%S",timeinfo);
puts(buffer);
cout<<endl;
getch();
return 0;
}
Your problem is that if time_t is a 32 bit value, the earliest possible date it's capable of encoding (given a 1970-1-1 epoch) is 1901-12-13.
However you're not setting the date fields of your tm struct, which means it is defaulting to 0-0-0 which represents 1900-1-0 (since tm_day is 1-based, you actually end up with an invalid day-of-month).
Since this isn't representable by a 32-bit time_t the mktime function is failing and returning -1, a situation you're not checking for.
Simplest fix is to initialise the date fields of the tm struct to something a time_t can represent:
time_sample_struct.tm_year = 114;
time_sample_struct.tm_mday = 1;

fully separated date with milliseconds from std::chrono::system_clock

My current pattern (for unix) is to call gettimeofday, cast the tv_sec field to a time_t, pass that through localtime, and combine the results with tv_usec. That gives me a full date (year, month, day, hour, minute, second, nanoseconds).
I'm trying to update my code to C++11 for portability and general good practice. I'm able to do the following:
auto currentTime = std::chrono::system_clock::now( );
const time_t time = std::chrono::system_clock::to_time_t( currentTime );
const tm *values = localtime( &time );
// read values->tm_year, etc.
But I'm stuck on the milliseconds/nanoseconds. For one thing, to_time_t claims that rounding is implementation defined (!) so I don't know if a final reading of 22.6 seconds should actually be 21.6, and for another I don't know how to get the number of milliseconds since the previous second (are seconds guaranteed by the standard to be regular? i.e. could I get the total milliseconds since the epoch and just modulo it? Even if that is OK it feels ugly).
How should I get the current date from std::chrono::system_clock with milliseconds?
I realised that I can use from_time_t to get a "rounded" value, and check which type of rounding occurred. This also doesn't rely on every second being exactly 1000 milliseconds, and works with out-of-the-box C++11:
const auto currentTime = std::chrono::system_clock::now( );
time_t time = std::chrono::system_clock::to_time_t( currentTime );
auto currentTimeRounded = std::chrono::system_clock::from_time_t( time );
if( currentTimeRounded > currentTime ) {
-- time;
currentTimeRounded -= std::chrono::seconds( 1 );
}
const tm *values = localtime( &time );
int year = values->tm_year + 1900;
// etc.
int milliseconds = std::chrono::duration_cast<std::chrono::duration<int,std::milli> >( currentTime - currentTimeRounded ).count( );
Using this free, open-source library you can get the local time with millisecond precision like this:
#include "tz.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << make_zoned(current_zone(),
floor<milliseconds>(system_clock::now())) << '\n';
}
This just output for me:
2016-09-06 12:35:09.102 EDT
make_zoned is a factory function that creates a zoned_time<milliseconds>. The factory function deduces the desired precision for you. A zoned_time is a pairing of a time_zone and a local_time. You can get the local time out with:
local_time<milliseconds> lt = zt.get_local_time();
local_time is a chrono::time_point. You can break this down into date and time field types if you want like this:
auto zt = make_zoned(current_zone(), floor<milliseconds>(system_clock::now()));
auto lt = zt.get_local_time();
local_days ld = floor<days>(lt); // local time truncated to days
year_month_day ymd{ld}; // {year, month, day}
time_of_day<milliseconds> time{lt - ld}; // {hours, minutes, seconds, milliseconds}
// auto time = make_time(lt - ld); // another way to create time_of_day
auto y = ymd.year(); // 2016_y
auto m = ymd.month(); // sep
auto d = ymd.day(); // 6_d
auto h = time.hours(); // 12h
auto min = time.minutes(); // 35min
auto s = time.seconds(); // 9s
auto ms = time.subseconds(); // 102ms
Instead of using to_time_t which rounds off you can instead do like this
auto tp = std::system_clock::now();
auto s = std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch());
auto t = (time_t)(s.count());
That way you get the seconds without the round-off. It is more effective than checking difference between to_time_t and from_time_t.
I read the standard like this:
It is implementation defined whether the value is rounder or truncated, but naturally the rounding or truncation only occurs on the most detailed part of the resulting time_t. That is: the combined information you get from time_t is never more wrong than 0.5 of its granularity.
If time_t on your system only supported seconds, you would be right that there could be 0.5 seconds systematic uncertainty (unless you find out how things were implemented).
tv_usec is not standard C++, but an accessor of time_t on posix. To conclude, you should not expect any rounding effects bigger than half of the smallest time value difference your system supports, so certainly not more than 0.5 micro seconds.
The most straight forward way is to use boost ptime. It has methods such as fractional_seconds()
http://www.boost.org/doc/libs/1_53_0/doc/html/date_time/posix_time.html#date_time.posix_time.ptime_class
For interop with std::chrono, you can convert as described here: https://stackoverflow.com/a/4918873/1149664
Or, have a look at this question: How to convert std::chrono::time_point to calendar datetime string with fractional seconds?

See if a timestamp is between a specific hour

I have a lot of timestamps, and data associated with it. I want to retrieve data that came from say 0800 - 0900.. What is the way to check if a timestamp falls between that?
How should i write a function that inputs two hours and returns a list of timestamps that falls inside those hours, regardless of what day it is?
like
std::list<uint32_t> getTimestampsBetween(uint16_t min_hour, uint16_t max_hour)
{
if(timestamp from list of timestamp is between min_hour and max_hour)
add it to list;
return list;
}
use localtime to convert timestamp to struct tm and check if the tm_hour attribute of the structure falls within the specified window.
Look into time.h for more information.
It depends on the format of the timestamps, but if they're time_t, you
can use mktime to convert a given tm to a time_t, and difftime
to compare two time_t. Something along the lines of:
bool
timeIsInInterval( time_t toTest, int minHour, int maxHour )
{
time_t now = time( NULL );
tm scratch = *localtime( &now );
scratch.tm_sec = scratch.tm_min = 0;
scratch.tm_hour = minHour;
time_t start = mktime( &scratch );
scratch.tm_hour = maxHour;
time_t finish = mktime( &scratch );
return difftime( toTest, start ) >= 0.0
&& difftime( toTest, finish ) < 0.0;
}
(In practice, toTest >= start && toTest < finish is probably
sufficient. Although the standard allows much more, I don't know of any
implementations where time_t is not an integral type containing the
number of seconds since some magic date.)
This supposes, of course, that you're looking for the times between the
two hours today. If you want some arbitrary date, it's easy to modify.
If you want any date, you need to do the reverse: convert the timestamps
to a tm, and compare the tm_hour fields.

C++ time_t problem

I'm having trouble with dates management in C++ (VS 2008).
According to MSDN specifications, time_t represents:
The number of seconds since January 1, 1970, 0:00 UTC
therefore, I've written this piece of code:
#include <stdio.h>
#include <time.h>
time_t GetDate(int year, int month, int day, int hour, int min, int sec)
{
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = gmtime ( &rawtime );
timeinfo->tm_year = year - 1900;
timeinfo->tm_mon = month - 1;
timeinfo->tm_mday = day;
timeinfo->tm_hour = hour;
timeinfo->tm_min = min;
timeinfo->tm_sec = sec;
timeinfo->tm_isdst = 0; // disable daylight saving time
time_t ret = mktime ( timeinfo );
return ret;
}
int main ()
{
time_t time_0 = GetDate(1970,1,1,0,0,0);
// time_0 == -1 !!!
time_t time_1 = GetDate(1970,1,1,1,0,0);
// time_1 == 0 !!!
return 0;
}
It seems to be shifted by 1 hour (i.e. zero time is January 1, 1970, 1:00 UTC).
Initially, I thought the problem could come from the DayLightSaving flag, but it doesn't change by changing it.
Am I doing something wrong ?
Thanks in advance
P.S.
In theory, I might not mind the zero time value, because it's only a reference time.
But I need to be sure about the value, because I'm porting the code to another language and I need to get exactly the same results.
EDIT:
here's the solution, thanks to Josh Kelley Answer
time_t mktimeUTC(struct tm* timeinfo)
{
// *** enter in UTC mode
char* oldTZ = getenv("TZ");
putenv("TZ=UTC");
_tzset();
// ***
time_t ret = mktime ( timeinfo );
// *** Restore previous TZ
if(oldTZ == NULL)
{
putenv("TZ=");
}
else
{
char buff[255];
sprintf(buff,"TZ=%s",oldTZ);
putenv(buff);
}
_tzset();
// ***
return ret;
}
mktime takes a struct tm giving a local time and returns the number of seconds since January 1, 1970, 0:00 UTC. Therefore, your GetDate(1970,1,1,0,0,0); call will return 0 if your local time zone is UTC but may return other values for other time zones.
Edit: For a UTC version of mktime or your GetDate, try the following (untested):
Call getenv to save the current value of the TZ environment variable (if any).
Call putenv to change the TZ environment variable to "UTC".
Call _tzset to make your changes active.
Call mktime.
Restore the old value of TZ, then call _tzset again.
Just a WAG but try the following:
timeinfo->tm_year = year - (unsigned long)1900;
timeinfo->tm_mon = month - (unsigned long)1;

Converting epoch time to "real" date/time

What I want to do is convert an epoch time (seconds since midnight 1/1/1970) to "real" time (m/d/y h:m:s)
So far, I have the following algorithm, which to me feels a bit ugly:
void DateTime::splitTicks(time_t time) {
seconds = time % 60;
time /= 60;
minutes = time % 60;
time /= 60;
hours = time % 24;
time /= 24;
year = DateTime::reduceDaysToYear(time);
month = DateTime::reduceDaysToMonths(time,year);
day = int(time);
}
int DateTime::reduceDaysToYear(time_t &days) {
int year;
for (year=1970;days>daysInYear(year);year++) {
days -= daysInYear(year);
}
return year;
}
int DateTime::reduceDaysToMonths(time_t &days,int year) {
int month;
for (month=0;days>daysInMonth(month,year);month++)
days -= daysInMonth(month,year);
return month;
}
you can assume that the members seconds, minutes, hours, month, day, and year all exist.
Using the for loops to modify the original time feels a little off, and I was wondering if there is a "better" solution to this.
Be careful about leap years in your daysInMonth function.
If you want very high performance, you can precompute the pair to get to month+year in one step, and then calculate the day/hour/min/sec.
A good solution is the one in the gmtime source code:
/*
* gmtime - convert the calendar time into broken down time
*/
/* $Header: gmtime.c,v 1.4 91/04/22 13:20:27 ceriel Exp $ */
#include <time.h>
#include <limits.h>
#include "loc_time.h"
struct tm *
gmtime(register const time_t *timer)
{
static struct tm br_time;
register struct tm *timep = &br_time;
time_t time = *timer;
register unsigned long dayclock, dayno;
int year = EPOCH_YR;
dayclock = (unsigned long)time % SECS_DAY;
dayno = (unsigned long)time / SECS_DAY;
timep->tm_sec = dayclock % 60;
timep->tm_min = (dayclock % 3600) / 60;
timep->tm_hour = dayclock / 3600;
timep->tm_wday = (dayno + 4) % 7; /* day 0 was a thursday */
while (dayno >= YEARSIZE(year)) {
dayno -= YEARSIZE(year);
year++;
}
timep->tm_year = year - YEAR0;
timep->tm_yday = dayno;
timep->tm_mon = 0;
while (dayno >= _ytab[LEAPYEAR(year)][timep->tm_mon]) {
dayno -= _ytab[LEAPYEAR(year)][timep->tm_mon];
timep->tm_mon++;
}
timep->tm_mday = dayno + 1;
timep->tm_isdst = 0;
return timep;
}
The standard library provides functions for doing this. gmtime() or localtime() will convert a time_t (seconds since the epoch, i.e.- Jan 1 1970 00:00:00) into a struct tm. strftime() can then be used to convert a struct tm into a string (char*) based on the format you specify.
see: http://www.cplusplus.com/reference/clibrary/ctime/
Date/time calculations can get tricky. You are much better off using an existing solution rather than trying to roll your own, unless you have a really good reason.
An easy way (though different than the format you wanted):
std::time_t result = std::time(nullptr);
std::cout << std::asctime(std::localtime(&result));
Output:
Wed Sep 21 10:27:52 2011
Notice that the returned result will be automatically concatenated with "\n".. you can remove it using:
std::string::size_type i = res.find("\n");
if (i != std::string::npos)
res.erase(i, res.length());
Taken from: http://en.cppreference.com/w/cpp/chrono/c/time
time_t t = unixTime;
cout << ctime(&t) << endl;
This code might help you.
#include <iostream>
#include <ctime>
using namespace std;
int main() {
// current date/time based on current system
time_t now = time(0);
// convert now to string form
char* dt = ctime(&now);
cout << "The local date and time is: " << dt << endl;
// convert now to tm struct for UTC
tm *gmtm = gmtime(&now);
dt = asctime(gmtm);
cout << "The UTC date and time is:"<< dt << endl;
}
To convert a epoch string to UTC
string epoch_to_utc(string epoch) {
long temp = stol(epoch);
const time_t old = (time_t)temp;
struct tm *oldt = gmtime(&old);
return asctime(oldt);
}
and then it can be called as
string temp = "245446047";
cout << epoch_to_utc(temp);
outputs:
Tue Oct 11 19:27:27 1977
If your original time type is time_t, you have to use functions from time.h i.e. gmtime etc. to get portable code. The C/C++ standards do not specify internal format (or even exact type) for the time_t, so you cannot directly convert or manipulate time_t values.
All that is known is that time_t is "arithmetic type", but results of arithmetic operations are not specified - you cannot even add/subtract reliably. In practice, many systems use integer type for time_t with internal format of seconds since epoch, but this is not enforced by standards.
In short, use gmtime (and time.h functionality in general).