Using time_t filttering - c++

I'd like to understand better time_t since i've never dealt with it before.
I want to make a filter_by_time function that gets a time window (lets say, 24 hours) and sends me back a vector of objects with a lower time gap of the said time window.
So since the function is getting a integer (from what i googled i understand i might need long-int) how can i convert the current time and the time_t field of an object into a long int ?
I was thinking to check if the current time (now) minus object's time_t < 24 hours then i'd put object into the array
hope i could be clear enough with my ambitions

Actually the time_t is almost always an integer counting the seconds since 00:00, Jan 1 1970 UTC (POSIX time).
However, this is not defined by the standard and might not be 100% reliable everywhere.
You can try to use from_time_t to convert your time_t to a time_point and use the constructors of time_point and duration to construct another time point from your integer. Then you can compare those time points.
This would be the most reliable way of solving the problem without assuming any particular format for time time_t.
But if it is acceptable for you to assume that the time_t is always POSIX time, you might also be able to just substract the integers as you have already suggested.

Related

How to get the local current time in seconds since epoch in C++ (MSVS)?

I need the local (with timezone offset) current time in seconds since epoch. The following code looks a bit clumzy because it creates an intermediate temporary structure tm which is superfluous. Why do I have to get time_t then convert it to tm in order to return to time_t? Is there a better way?
time_t ct = time(0);
tm lct = tm();
localtime_s(&lct, &ct);
ct = _mkgmtime(&lct);
If you want to get the local time (with time zone and DST applied) in portable C, then yes, it's generally a two-step procedure: starting with your time-since-the-epoch, first call localtime, then do something with the resulting broken-down struct tm. (Usually what I do next is call strftime.)
You can also call ctime to get a local time string directly.
The reason there are a lot of different function calls involved is that, unfortunately, there are several different time formats in use. (And the reason for that is that dates and times are complicated!) You can represent time as seconds-since-1970. You can represent it as a struct tm. You can represent it as a string (in one of several zillion formats). In Unix and Linux, you can represent it as a struct timeval or a struct timespec.
But one thing there isn't a straightforward or standard way to do, as you've discovered, is get local time as seconds-since-1970. But the reason for that is that it's not a very useful representation. In general, there are two things you might want to do with a date/time value: (1) perform computations on it or (2) display it to the user. If you want to display it to the user, you probably want to display it in local time, so there are lots of ways of converting to local time in human-readable format in any format you want. (As I said, the usual way is to call localtime, then strftime.) But if you want to perform computations, really the only way to do those is using seconds-since-1970 in UTC, because that makes all the other hairy problems go away. How many days are there in the month? Is it a leap year? What time zone are we in? Is daylight saving time in effect?
If you try to represent local time as seconds-since-1970, though, you're probably fibbing. For example, right now, the time is 1460383736, which is 14:08:56 UTC. Where I'm sitting, that's 10:08:56 EDT (U.S. Eastern time, DST in effect). So I suppose I could say that's 1460369336 seconds since 1970, local time. But, again where I'm sitting, 1460369336 seconds ago was not midnight on January 1, 1970 -- it was actually 11 pm on December 31, 1969. It's off by an hour, and the reason is that DST was not in effect on January 1, 1970.
So, bottom line, I would encourage you to rethink the way you're handling local times, because while it's possible to compute this "seconds-since-1970 as local time" value, it's an odd thing to do, and it's likely to cause you various problems which will be much harder to work around than if you used a more straightforward scheme.
But, if you really want to, here are two ways you might be able to determine the offset between UTC and local time, without calling gmtime or _mkgmtime:
Call localtime, and look at the tm_gmtoff field. (Unfortunately, this field is nonstandard, and not present on all systems.)
Call the obsolete ftime function, and look at the timezone field of struct timeb. (Here there are several gotchas: not only is ftime obsolete and nonstandard, but the timezone field is in minutes, and it's positive for zones west of Greenwich, while tm_gmtoff is negative.)
But, anyway, those would more or less directly give you the number to add to or subtract from your UTC seconds-since-1970 value to get "local" seconds-since-1970.
Here is a way to do this computation using the C++11/14 <chrono> library plus this free, open-source timezone library to do the conversion to local time.
#include "tz.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std;
using namespace std::chrono;
auto now = floor<seconds>(system_clock::now());
auto s = current_zone()->to_local(now) - local_days{1970_y/jan/1};
cout << s.count() << '\n';
}
You first discover your current IANA timezone with current_zone(). Then you get the current time with system_clock::now() and truncate it to seconds. Next you can convert that to your local time, and then subtract the result from any epoch you desire (1970-01-01 in this example).
The result is of type std::chrono::seconds.
All this being said, I share the same reservations about doing this as described in Steve Summit's answer.
If you instead decide to represent the timestamp as a string, that is also easily done:
auto now = make_zoned(current_zone(), floor<seconds>(system_clock::now()));
auto str = format("%F %T %z", now);
str has type std::string. This just output for me:
2016-04-11 11:42:50 -0400
which is my current local time (truncated to seconds), and my current local UTC offset.
If in the future you decide that seconds-precision is too coarse, you can easily change the above code to any other precision by just changing one line:
floor<milliseconds>(system_clock::now());
and now the contents of str would look like:
2016-04-11 11:42:50.368 -0400

Convert number of seconds to time

Is there a way to convert the number of seconds (e.g. 3056144 sec, this is time delta not a time) to time in format YYYY-mm-dd HH:MM:SS?
I've tried to convert number of seconds to struct tm using localtime and then substract UNIX start time (1970-01-01), but this is not working as expected.
Thanks in advance.
P.S. I have to use C++03, not C++11.
If using Boost.Date_Time is an option for you, this might be what you're looking for:
#include <boost/date_time.hpp>
using boost::posix_time::seconds;
using boost::posix_time::to_simple_string;
std::cout << to_simple_string(seconds(3056144)) << std::endl;
This will print:
848:55:44
However, as you can see in the output above, it will not tell you how many years have passed. This is for good reason, because a year has not always 365 days.
If you're converting a time delta to ISO 8601-like time, you just need to offset your timedelta by the number of seconds since 1907-01-01 that corresponds to your 0 (start) time, then use localtime to convert to a struct tm.
Due to the fact that the number of days per month depends on which month and year it is, trying to convert delta seconds to any larger time units than days without considering where the start and end times are on the actual calendar is going to be fraught with errors.
Like Bathsheba mentions, it depends on how accurate you need to be.
I've seen some algorithms duck the issue that simply assuming a month is 30 days (and therefore a year is only 360 days). If that's what you want to do, then trying to use localtime ill be more trouble than it's worth.
If you want to do it "exactly" right, you have to convert your start and end times to actual aligned-to-the-epoch time_t values, and use some kind of calendar-aware date computation to work out the time between the two. localtime isn't going to cut it (and that's not even considering how it would be an hour off id the timedelta crosses a DST boundary).

C++11 number of days since date

I need to store date in flat file. Is there any simple metod to get number of days since particular date (for example since 1 AD) using standard libary in C++11? The only one I know is to:
obtain std::tm structure, set all time values to 0
convert it to std::time_t (I do not know proper method yet)
divide time_t to get the resolution of one day
Can I perform it easier?
What you said sounds reasonable to start with. You can convert the struct tm to time_t using mktime. Note that mktime interprets its input as local time according to the system/environment settings, and there is no UTC counterpart that's as widely available without relying on "extra" libraries, but maybe that's not a problem for you.

Given a Date/Time as a string, what is the best way to know if it was DST at that time?

Let's say I'm given a string such as this: "2009-4-9", meaning April 9th, 2009. Assuming for starters, that I am only concerned with local time (I have concerns about other time zones as well, but I'll tackle the easy stuff first). What is the best way to know if Daylight Savings was in effect at that time?
You can assume that the system has the properly updated timezone files such as /etc/localtime and I am interested in portable solutions. Either c or c++ are acceptable as well.
You can also assume that I only care about past or present dates, never the future.
Currently I have a "hack" which looks like this (I know localtime_r is a library extension, but it's close enough to the same functionality that I can make it portable)
struct tm tm;
// convert the time string to a broken down structure in localtime
if(strptime("2009-4-9", "%Y-%m-%d", &tm)) {
// convert the broken down structure into seconds since epoch
const time_t t = mktime(&tm);
// convert it back to a broken down structure, this seems pointless at first...
// but libc will fill out fields such as tm_isdst
localtime_r(&t, &tm);
printf("DST : %d\n", tm.tm_isdst);
}
While this works (and seems to be a pretty effective way), I feel like it's silly to be converting back and forth. Is there a better way?
You do not need to call localtime_r() at all. mktime() normalises the struct tm that you pass it, including setting tm_isdst to a nonnegative value if it was passed in set to -1. So all you need is:
struct tm tm = { 0 };
// convert the time string to a broken down structure in localtime
if(strptime("2009-4-9", "%Y-%m-%d", &tm)) {
tm.tm_isdst = -1;
// normalise the broken down structure - this calculates tm_isdst
mktime(&tm);
printf("DST : %d\n", tm.tm_isdst);
}
This behaviour of mktime() is required by the C standard; for example, C99 says:
The mktime function converts the broken-down time, expressed as
local time, in the structure pointed to by timeptr into a calendar
time value with the same encoding as that of the values returned by
the time function. The original values of the tm_wday and
tm_yday components of the structure are ignored, and the original
values of the other components are not restricted to the ranges
indicated above.276 On successful completion, the values of
the tm_wday and tm_yday components of the structure are set
appropriately, and the other components are set to represent the
specified calendar time, but with their values forced to the ranges
indicated above; the final value of tm_mday is not set until
tm_mon and tm_year are determined.
with footnote 276 explicitly addressing the tm_isdst member:
276) Thus, a positive or zero value for tm_isdst causes the mktime
function to presume initially that Daylight Saving Time, respectively,
is or is not in effect for the specified time. A negative value causes
it to attempt to determine whether Daylight Saving Time is in effect
for the specified time.
The conversion from UTC to local time is not a reversible function. For example, in the autumn when the clocks jump back an hour, the local times between 02:00 and 03:00 occur twice. Given a time in this interval, it's not possible to determine whether the local time happened at a specific UTC time in local daylight time, or one hour later in local standard time.
I have done many time conversions before in C and I think you pretty much have it the way I would have done it too. As far as I know, localtime_r and its relatives may be your only option (unless there is some third party date library.) Of course, Greg Hewgill is correct for the "gray hour" between time switches.

how to find next date when PST switches to PDT next and vice versa

My program runs on a Windows computer on which timezone is not PST/PDT. But it needs to operate according to PST/PDT time rules.
Wrt to summer/winter time, the program needs to know
the next date when PDT changes to PST or vice versa.
How can I program in C++ finding the next summertime<->wintertime switch ?
Since the start and end of Daylight Savings Time have changed due to various acts of Congress, the information of the next savings transition is not fixed. I don't know if you need to reboot to apply DST changes, but if you do, you might want to update your estimate of the next transition more frequently than once.
The native API to get this information is GetTimeZoneInformationForYear. You can pass in a specific time zone and year. That function fills out a TIME_ZONE_INFORMATION struct; the relevant information you want is TIME_ZONE_INFORMATION::DaylightDate and TIME_ZONE_INFORMATION::StandardDate
If you are on Windows, use a C# class to do this and return the results to your C++ program via your interop of choice. Otherise, you'll likely wind up rebuilding the .Net code that does this in C+, and in the process miss all the edge cases that .Net will handle for you.
You can use TimeZoneInfo.Local and then get the adjustment rules for it.
Ugly brute force method:
Call time(NULL) to get the current time as a time_t value.
Use localtime() to convert this value to a struct tm. (Consider adjusting the tm_hour member to 12, so you're checking noon every day.)
Repeatedly add 1 day to the tm_day member of your struct tm, then use mktime() to convert back to time_t.
Use difftime() to compare each incremented time_t value to the previous one. When `difftime() gives you a value that's not close to 86400.0 (the number of seconds in 1 day), you've found a DST transition. If you do this 365 times without finding a transition, something is wrong.
You can probably take some shortcuts if you're willing to make some assumptions about the representation of time_t.
Obviously this is only an outline of a solution -- and I haven't tried it myself.
And I've just re-read the question and realized that I've completely ignored the part where you said that the computer isn't on PST or PDT. (Can you set the timezone for the program?)