Confusing behaviour of mktime() function : increasing tm_hour count by one - c++

I am executing below code.
int main()
{
struct tm storage={0,0,0,0,0,0,0,0,0};
char *p = NULL;
p = (char *)strptime("2012-08-25 12:23:12","%Y-%m-%d %H:%M:%S",&storage);
char buff[1024]={0};
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage);
cout << buff << endl;
storage.tm_sec += 20;
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage);
cout << buff << endl;
mktime(&storage);
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage);
cout << buff << endl;
return 0;
}
If above Program executed, It prints ' 2012-08-25 13:23:32' instead of '2012-08-25 12:23:32'. Please Help, why it is increasing tm_hour value.
This works correctly if I put input date as '2012-02-25 12:23:32' in program, which is confusing.
OUtput ->
[user#rtpkvm55-vm2 root]$ ./a.out
2012-08-25 12:23:12
2012-08-25 12:23:32
2012-08-25 13:23:32
[user#rtpkvm55-vm2 root]$
Date Info on my system, -->
[user#rtpkvm55-vm2 root]$ date
Sat Aug 25 08:28:26 EDT 2012

What happens
The date you specified has daylight savings in effect but when calling mktime, storage.tm_isdst is zero. mktime sees this and thinks "hey, they gave me a date with an incorrect daylight savings flag, lets fix it". Then it sets tm_isdst to 1 and changes tm_hour.
See also this answer.
To fix it
use timegm instead of mktime
set the timezone to UTC before calling mktime (see also example from timegm) :
setenv("TZ", "", 1);
tzset();
mktime();
use a good date-time library (like boost::locale::date_time/boost::date_time, but read the Q&A section on the boost::locale::date_time page before picking one)

Wow, there just is no way around it. It must be a bug in your system's implementation of mktime(3). mktime(3) should not alter the struct tm * passed to it.
I would suggest checking the value of storage.tm_isdst. Try setting it to 0 to ensure it's not confused about DST. If that doesn't work, try setting it to -1 to let it auto determine the proper value.
mktime - convert broken-down time into time since the Epoch
A positive or 0 value for tm_isdst causes mktime() to presume initially that Daylight Savings Time, respectively, is or is not in effect for the specified time. A negative value for tm_isdst causes mktime() to attempt to determine whether Daylight Saving Time is in effect for the specified time.
I was wrong about mktime(3) not modifying struct tm *. It is the correct behavior to normalize the value.

You have to set tm_isdst in the tm struct otherwise it is uninitialised, and thus gets set to a random garbage value. Then, when you call mktime depending on which random garbage is in tm_isdst variable, it either applies daylight saving time or it doesn't, seemingly unpredictably.
However, if you set it to -1, you tell mktime that you don't know whether daylight saving time is in effect, so the first call to mktime will fix it.
Therefore, the simplest way to fix this issue is adding:
storage.tm_isdst = -1;
before calling mktime.

Here is a trick to fix your code:
int main()
{
// Need to know if daylight saving is on or off, use the following trick
// Get the current time in seconds since epoch, convert it to local time,
// tm_isdst(is daylight saving) value, in the tm variable returned by the localtime(), will be set accordingly
time_t now = time(0);
struct tm *tm2= localtime(&now);
struct tm storage={0,0,0,0,0,0,0,0,tm2->tm_isdst}; // Note: used the is daylight saving on flag fetched above
char *p = NULL;
p = (char *)strptime("2012-08-25 12:23:12","%Y-%m-%d %H:%M:%S",&storage);
char buff[1024]={0};
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage);
cout << buff << endl;
storage.tm_sec += 20;
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage);
cout << buff << endl;
mktime(&storage);
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage);
cout << buff << endl;
return 0;
}

Related

Have mktime() ignore DST and local time zone in C++

Our system receives data from a vendor in ASCII format "20210715083015". This time is US Eastern time, and is already adjusted for Daylight Savings.
Our backend needs this time in nanoseconds since Epoch. I'm trying to use mktime() to do the conversion, but mktime() insists on adding an hour for DST, even when I force tm_isdst to 0.
Here's the code snippet:
std::tm tmstr{};
<breakdown ASCII time into tm structure>
tmstr.tm_isdst = 0;
cout << "isdst before: " tmstr.tm_isdst;
time_t seconds = std::mktime(&tmstr);
cout << ", isdst after: " tmstr.tm_isdst << endl;
Here's the output:
isdst before: 0, isdst after: 1
It's ignoring the set value of 0, and applying its own conversion.
How do I use mktime(), or something equivalent, without it trying to adjust the time to my timezone? I'd rather not have to internally set timezones, I just want it to do a straight conversion from a tm structure to seconds.
This is g++ version 7.3.1, under Redhat version 6.10.
It's ignoring the set value of 0
No, it is not ignoring that member.
mktime() takes .tm_isdst into account and then adjusts all the struct tm members to their usual values for that date, thus a change to .tm_isdst and .tm_hour is expected in OP's case as the tmstr is in daylight time for "20210715" July 15th.
How do I use mktime(), or something equivalent, without it trying to adjust the time to my timezone?
mktime() is a local time conversion. The usual approach is let mktime() deduce the daylight flag.
tmstr.tm_isdst = -1;
This time is US Eastern time, and is already adjusted for Daylight Savings.
No, you are asserting it is US standard Eastern time (EST). US Eastern time (ET) has daylight adjustments.
Change your time zone from one with daylight and standard periods to a zone with only standard. Research setenv(). Perhaps as simple as:
// Implementation dependent code.
setenv("TZ", "EST5", 1);
tzset();
time_t seconds = mktime(&tmstr);
Key issue missing: was the time_t result correct?
Ignore tmstr for a moment. What time_t value was reported? What time_t value was expected?
I suspect OP did get the right time_t value, just not the expected result in struct tm.
Hopefully, you could use the timegm() function (not to confound with the gmtime() function... see below for more info).
The mktime() function has a state. If the last time it was used with isdst set to 0, then using isdst = -1 will use 0. If the last time you used it with isdst set to 1, then using isdst = -1 will use 1. This is true only if the function is called with a time when the time change happens (within that 1h window). Other functions are not unlikely to change that variable too (i.e. the localtime() may also affect that state, I haven't tested that).
// a date when the time change happened (Sun Oct 26 01:08:48 PST 1980)
time_t et = 341399328;
struct tm t = {};
localtime_r(&et, &t);
struct tm ot = {};
ot.tm_year = t.tm_year;
ot.tm_mon = t.tm_mon;
ot.tm_mday = t.tm_mday;
ot.tm_hour = t.tm_hour;
ot.tm_min = t.tm_min;
ot.tm_sec = t.tm_sec;
ot.tm_isdst = 1;
std::cerr << " +--> " << mktime(&ot) << " (1)\n";
ot.tm_isdst = 0;
std::cerr << " +--> " << mktime(&ot) << " (0)\n";
ot.tm_isdst = -1;
std::cerr << " +--> " << mktime(&ot) << " (-1)\n"; // same as 0
ot.tm_isdst = 0;
std::cerr << " +--> " << mktime(&ot) << " (0)\n";
ot.tm_isdst = 1;
std::cerr << " +--> " << mktime(&ot) << " (1)\n";
ot.tm_isdst = -1;
std::cerr << " +--> " << mktime(&ot) << " (-1)\n"; // same as 1
The output should always be the same as the input (i.e. convert from time_t to struct tm and vice versa). Instead I get:
341399328 -> 1980/10/26 1:8:48
+--> 341395728 (1)
+--> 341399328 (0)
+--> 341399328 (-1)
+--> 341399328 (0)
+--> 341395728 (1)
+--> 341395728 (-1)
So, more or less, you can't trust the mktime() conversions.
There are now two new functions: timegm() and timelocal(). The timelocal() function is the same as the mktime(). The timegm() totally ignores the locale timezone, so you can convert UTC time back and forth properly. The converse being gmtime().
In other words:
time_t to struct tm with gmtime()
struct tm to time_t with timegm()
and the input time_t in (1) will always equal the output time_t in (2).
Easier to post here...
From the mktime() man page, you're not reading what is written...
The mktime() function converts a broken-down time structure, expressed as local time, to calendar time representation. The function ignores the values supplied by the caller in the tm_wday and tm_yday fields. 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.
The mktime() function modifies the fields of the tm structure as follows: tm_wday and tm_yday are set to values determined from the contents of the other fields; if structure members are outside their valid interval, they will be normalized (so that, for example, 40 October is changed into 9 November); tm_isdst is set (regardless of its initial value) to a positive value or to 0, respectively, to indicate whether DST is or is not in effect at the specified time. Calling mktime() also sets the external variable tzname with information about the current timezone.

Making two time_t values the same day using gmtime and mktime, 'function may be unsafe' error

I am trying to use a time_t from the past, and a new time, and using gmtime, make them both a structure to which I can change the new time to the same day of the week, after this I wish to make the new changed time back into a time_t and return it.
So my issues are, as a new programmer, I wish to know if the below code the right way to go about it, and if so, why do I get a:
""Error 3 error C4996: 'gmtime': This function or variable may be unsafe. Consider using gmtime_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details." Error?
Code:
time_t copyStartTime(time_t &startTime,time_t eventTime ) //finds exact time of startTime and returns it
{
cout << eventTime << "\n";
cout << startTime << "\n";
cin.get();
tm* then = gmtime(&startTime);
cout << (then->tm_hour);
tm* now = gmtime(&eventTime);
cout << (now->tm_hour);
cin.get();
then->tm_hour = now->tm_hour;
time_t newTime = _mkgmtime(then);
cout << newTime << "\n";
cin.get();
return newTime;
}
From gmtime documentation:
The return value points to a statically allocated struct which might be overwritten by subsequent calls to any of the date and time functions.
OK, this was linux documentation, but the behaviour is the same on windows.
And you are running into exactly the problem with:
tm* then = gmtime(&startTime);
cout << (then->tm_hour);
tm* now = gmtime(&eventTime);
then and now both point to the same object! So you lose the information from first call go gmtime, which is overwritten by second call!
MSVC tries to save you from this kind of error by just not allowing usage of gmtime by default. To switch the warning/error off, you need to use the macro that is shown in the error: _CRT_SECURE_NO_WARNINGS. Either #define it right at the start before including the header or add it as pre-processor definition in IDE's project settings.
Side note: Correctly resolving your bug:
tm then = *gmtime(&startTime);
tm now = *gmtime(&eventTime);

Incorrect time calculation with mktime to get UTC+8

I want to get the current time in Hong Kong (UTC+8), and my local time is UTC-5.
Using and running the following in VS2012:
#pragma warning(disable : 4996)
char buffer[10];
time_t rawtime;
time(&rawtime);
strftime(buffer, 10, "%H:%M:%S", localtime(&rawtime));
cout << "LocalTime=" << buffer << endl;
strftime(buffer, 10, "%H:%M:%S", gmtime(&rawtime));
cout << "GMTime=" << buffer << endl;
tm* r = gmtime(&rawtime);
r->tm_hour += 8; // Hong Kong time
mktime(r); // Normalize the struct
strftime(buffer, 10, "%H:%M:%S", r);
cout << "HongKongTime=" << buffer << endl;
Produces the following output:
LocalTime=22:51:47
GMTime=02:51:47
HongKongTime=11:51:47
So it's computing UTC correctly, but then adding 8 hours to that is actually producing a time that is UTC +9. What's going wrong?
And is there a more elegant/reliable way of getting UTC+8 than this kludge?
You could use localtime after changing the TZ environment variable to your desired timezone:
#include <iostream>
#include <stdlib.h>
#include <time.h>
int main(){
_putenv_s( "TZ", "GMT-08:00" );
time_t mytime = time( NULL );
struct tm* mytm = localtime( &mytime );
std::cout << "Current local time and date: " << asctime(mytm);
return 0;
}
The object mytime will receive as a result of the function time() the amount of seconds since 00:00 hours, Jan 1, 1970 UTC, which is the current Unix timestamp. localtime() will use the value pointed by mytime to fill a tm structure with the values that represent the corresponding time, expressed for the local timezone.
By default, the timezone used by localtime() is generally the one used in your computer. However, you can change it with the function _putenv_s(), in which I manipulated the TZ variable and added a new definition to it GMT-08:00 which is the timezone for Hong Kong.
In POSIX systems, a user can specify the time zone by means of the TZ
environment variable.
Note that however a more standard way of manipulating TZ variable is by using the function int setenv (const char *name, const char *value, int replace) but it wasn't defined in this sample, so I used an alternative.
You can read more about TZ environment variable here

c++, getting milliseconds since midnight in local time

It's unbelievable how difficult the above is to accomplish in C++. I'm looking for a way to do this as efficiently as possible while still maintaining millisecond precision.
The solutions I have so far have either required a lot of code and function calls making the implementation slow, or they require me to change the code twice a year to account for daylight savings time.
The computer this will be running on is synced using ntp and should have direct access to the local time adjusted for DST. Can somebody with expertise on this share some solutions?
My platform is CentOS5, g++ 4.1.2, Boost 1.45, solution doesn't need to be portable, can be platform specific. It just needs to be quick and avoid twice a year code changing.
New answer for old question.
Rationale for new answer: We have better tools now.
I'm assuming the desired result is "actual" milliseconds since the local midnight (getting the correct answer when there has been a UTC offset change since midnight).
A modern answer based on <chrono> and using this free, open-source library is very easy. This library has been ported to VS-2013, VS-2015, clang/libc++, macOS, and linux/gcc.
In order to make the code testable, I'm going to enable an API to get the time since midnight (in milliseconds) from any std::chrono::system_clock::time_point in any IANA time zone.
std::chrono::milliseconds
since_local_midnight(std::chrono::system_clock::time_point t,
const date::time_zone* zone);
And then to get the current time since midnight in the local time zone is easy to write on top of this testable primitive:
inline
std::chrono::milliseconds
since_local_midnight()
{
return since_local_midnight(std::chrono::system_clock::now(),
date::current_zone());
}
Writing the meat of the matter is relatively straight-forward:
std::chrono::milliseconds
since_local_midnight(std::chrono::system_clock::time_point t,
const date::time_zone* zone)
{
using namespace date;
using namespace std::chrono;
auto zt = make_zoned(zone, t);
zt = floor<days>(zt.get_local_time());
return floor<milliseconds>(t - zt.get_sys_time());
}
The first thing to do is create a zoned_time which really does nothing at all but pair zone and t. This pairing is mainly just to make the syntax nicer. It actually doesn't do any computation.
The next step is to get the local time associated with t. That is what zt.get_local_time() does. This will have whatever precision t has, unless t is coarser than seconds, in which case the local time will have a precision of seconds.
The call to floor<days> truncates the local time to a precision of days. This effectively creates a local_time equal to the local midnight. By assigning this local_time back to zt, we don't change the time zone of zt at all, but we change the local_time of zt to midnight (and thus change its sys_time as well).
We can get the corresponding sys_time out of zt with zt.get_sys_time(). This is the UTC time which corresponds to the local midnight. It is then an easy process to subtract this from the input t and truncate the results to the desired precision.
If the local midnight is non-existent, or ambiguous (there are two of them), this code will throw an exception derived from std::exception with a very informative what().
The current time since the local midnight can be printed out with simply:
std::cout << since_local_midnight().count() << "ms\n";
To ensure that our function is working, it is worthwhile to output a few example dates. This is most easily done by specifying a time zone (I'll use "America/New_York"), and some local date/times where I know the right answer. To facilitate nice syntax in the test, another since_local_midnight helps:
inline
std::chrono::milliseconds
since_local_midnight(const date::zoned_seconds& zt)
{
return since_local_midnight(zt.get_sys_time(), zt.get_time_zone());
}
This simply extracts the system_clock::time_point and time zone from a zoned_time (with seconds precision), and forwards it on to our implementation.
auto zt = make_zoned(locate_zone("America/New_York"), local_days{jan/15/2016} + 3h);
std::cout << zt << " is "
<< since_local_midnight(zt).count() << "ms after midnight\n";
This is 3am in the middle of the Winter which outputs:
2016-01-15 03:00:00 EST is 10800000ms after midnight
and is correct (10800000ms == 3h).
I can run the test again just by assigning a new local time to zt. The following is 3am just after the "spring forward" daylight saving transition (2nd Sunday in March):
zt = local_days{sun[2]/mar/2016} + 3h;
std::cout << zt << " is "
<< since_local_midnight(zt).count() << "ms after midnight\n";
This outputs:
2016-03-13 03:00:00 EDT is 7200000ms after midnight
Because the local time from 2am to 3am was skipped, this correctly outputs 2 hours since midnight.
An example from the middle of Summer gets us back to 3 hours after midnight:
zt = local_days{jul/15/2016} + 3h;
std::cout << zt << " is "
<< since_local_midnight(zt).count() << "ms after midnight\n";
2016-07-15 03:00:00 EDT is 10800000ms after midnight
And finally an example just after the Fall transition from daylight saving back to standard gives us 4 hours:
zt = local_days{sun[1]/nov/2016} + 3h;
std::cout << zt << " is "
<< since_local_midnight(zt).count() << "ms after midnight\n";
2016-11-06 03:00:00 EST is 14400000ms after midnight
If you want, you can avoid an exception in the case that midnight is non-existent or ambiguous. You have to decide before hand in the ambiguous case: Do you want to measure from the first midnight or the second?
Here is how you would measure from the first:
std::chrono::milliseconds
since_local_midnight(std::chrono::system_clock::time_point t,
const date::time_zone* zone)
{
using namespace date;
using namespace std::chrono;
auto zt = make_zoned(zone, t);
zt = make_zoned(zt.get_time_zone(), floor<days>(zt.get_local_time()),
choose::earliest);
return floor<milliseconds>(t - zt.get_sys_time());
}
If you want to measure from the second midnight, use choose::latest instead. If midnight is non-existent, you can use either choose, and it will measure from the single UTC time point that borders the local time gap that midnight is in. This can all be very confusing, and that's why the default behavior is to just throw an exception with a very informative what():
zt = make_zoned(locate_zone("America/Asuncion"), local_days{sun[1]/oct/2016} + 3h);
std::cout << zt << " is "
<< since_local_midnight(zt).count() << "ms after midnight\n";
what():
2016-10-02 00:00:00.000000 is in a gap between
2016-10-02 00:00:00 PYT and
2016-10-02 01:00:00 PYST which are both equivalent to
2016-10-02 04:00:00 UTC
If you use the choose::earliest/latest formula, instead of an exception with the above what(), you get:
2016-10-02 03:00:00 PYST is 7200000ms after midnight
If you want to do something really tricky like use choose for non-existent midnights, but throw an exception for ambiguous midnights, that too is possible:
auto zt = make_zoned(zone, t);
try
{
zt = floor<days>(zt.get_local_time());
}
catch (const date::nonexistent_local_time&)
{
zt = make_zoned(zt.get_time_zone(), floor<days>(zt.get_local_time()),
choose::latest);
}
return floor<milliseconds>(t - zt.get_sys_time());
Because hitting such a condition is truly rare (exceptional), the use of try/catch is justified. However if you want to do it without throwing at all, there exists a low-level API within this library to achieve that.
Finally note that this long winded answer is really about 3 lines of code, and everything else is about testing, and taking care of rare exceptional cases.
It really depends on why you need "milliseconds since midnight" and what you plan to use it for.
Having said that, you need to take into account the fact that 3am doesn't really mean 3 hours since midnight, when DST is involved. If you really need "milliseconds since midnight" for some reason, you can get one Epoch time at midnight, another at 3am, and subtract the two.
But again, the notion of "midnight" may not be that stable in some cases; if a region's rule is to fall back from 1am to midnight when DST ends, you have two midnights within a day.
So I'm really doubtful of your dependence on "midnight". Typically, those broken-down times are for display and human understanding only, and all internal timekeeping is done with Epoch times.
If you're on Linux, gettimeofday gives the number of seconds/microseconds since the Epoch, which may help. But this really doesn't have anything to do with DST, since DST matters only with broken-down times (i.e. year, month, day, hour, minute, second).
To get the broken-down time, use gmtime or localtime with the "seconds" part of the result of gettimeofday:
struct timeval tv;
gettimeofday(&tv, 0);
struct tm *t = localtime(&tv.tv_sec); // t points to a statically allocated struct
localtime gives the broken-down time in your local timezone, but it may be susceptible to DST. gmtime gives the broken-down time in UTC, which is immune to DST.
None of the answers provided really does what I need it to do. I've come up with something standalone that I think should work. If anybody spots any errors or can think of a faster method, please let me know. Present code takes 15 microseconds to run. I challenge SO to make something quicker (and I really hope SO succeeds =P)
inline int ms_since_midnight()
{
//get high precision time
timespec now;
clock_gettime(CLOCK_REALTIME,&now);
//get low precision local time
time_t now_local = time(NULL);
struct tm* lt = localtime(&now_local);
//compute time shift utc->est
int sec_local = lt->tm_hour*3600+lt->tm_min*60+lt->tm_sec;
int sec_utc = static_cast<long>(now.tv_sec) % 86400;
int diff_sec; //account for fact utc might be 1 day ahead
if(sec_local<sec_utc) diff_sec = sec_utc-sec_local;
else diff_sec = sec_utc+86400-sec_local;
int diff_hour = (int)((double)diff_sec/3600.0+0.5); //round to nearest hour
//adjust utc to est, round ns to ms, add
return (sec_utc-(diff_hour*3600))*1000+(int)((static_cast<double>(now.tv_nsec)/1000000.0)+0.5);
}
You can run localtime_r, and mktime after adjusting the result of localtime_r to compute the value of "midnight" relative to the Epoch.
Edit: Pass now into the routine to avoid an unnecessary call to time.
time_t global_midnight;
bool checked_2am;
void update_global_midnight (time_t now, bool dst_check) {
struct tm tmv;
localtime_r(&now, &tmv);
tmv.tm_sec = tmv.tm_min = tmv.tm_hour = 0;
global_midnight = mktime(&tmv);
checked_2am = dst_check || (now >= (global_midnight + 2*3600));
}
Assume global_midnight is initially 0. Then, you would adjust it's value at 2am, and the next day, so that it stays in sync with DST. When you call clock_gettime, you can compute the difference against global_midnight.
Edit: Since the OP wants to benchmark the routine, tweaking code for compilers that assume true to be the fast path, and round to nearest msec.
unsigned msecs_since_midnight () {
struct timespec tsv;
clock_gettime(CLOCK_REALTIME, &tsv);
bool within_a_day = (tsv.tv_sec < (global_midnight + 24*3600));
if (within_a_day)
if (checked_2am || (tsv.tv_sec < (global_midnight + 2*3600))
return ((tsv.tv_sec - global_midnight)*1000
+ (tsv.tv_nsec + 500000)/1000000);
update_global_midnight(tsv.tv_sec, within_a_day);
return ((tsv.tv_sec - global_midnight)*1000
+ (tsv.tv_nsec + 500000)/1000000);
}
I have referred to the post [here] and made a change so that the below function can return the milliseconds since midnight in GMT time.
int GetMsSinceMidnightGmt(std::chrono::system_clock::time_point tpNow) {
time_t tnow = std::chrono::system_clock::to_time_t(tpNow);
tm * tmDate = std::localtime(&tnow);
int gmtoff = tmDate->tm_gmtoff;
std::chrono::duration<int> durTimezone(gmtoff); // 28800 for HKT
// because mktime assumes local timezone, we shift the time now to GMT, then fid mid
time_t tmid = std::chrono::system_clock::to_time_t(tpNow-durTimezone);
tm * tmMid = std::localtime(&tmid);
tmMid->tm_hour = 0;
tmMid->tm_min = 0;
tmMid->tm_sec = 0;
auto tpMid = std::chrono::system_clock::from_time_t(std::mktime(tmMid));
auto durSince = tpNow - durTimezone - tpMid;
auto durMs = std::chrono::duration_cast<std::chrono::milliseconds>(durSince);
return durMs.count();
}
If you want to have local time, it is much more easier.

Calculating minutes from now until something is due

I have a project that needs me to accept an input for when (during the same day, I assume) an assignment is due. I was trying to follow some code from a similar question but it's giving me an error, which I assume has to do with time_t and int values. Here's my code:
#include <iostream>
#include <ctime>
using namespace std;
int main() {
int hour_input,min_input;
cout << "What hour is your assignment due?\n";
cin >> hour_input;
cout << "What minute is your assignmnet due?\n";
cin >> min_input;
struct tm* tm;
time_t ts = time(NULL);
long int delta;
tm->tm_hour = hour_input;
tm->tm_min = min_input;
delta = mktime(tm) - ts;
delta += 24*60*60;
cout << "There are "<< delta << " minutes until your assignment is due!\n";
return 0;
}
What I'm looking for is some guidance on how to use the functions within the <ctime> header properly, thanks for your help!
double deltaMinutes = difftime(later,earlier) / 60.0;
I'd initialize each time struct to the current date. Note, that 1970 is designated by 70 in member tm::tm_year.
http://www.cplusplus.com/reference/clibrary/ctime/difftime/
The first error is you creating a pointer to struct tm but not pointing it to anything. You don't need a pointer:
struct tm tm;
/* set fields */
time_t timestamp = mktime(&tm);
The second error is that mktime expects a complete data/time in the structure. If the year, month and day all is zero then the returned time will be the first year, month and day. The call may actually fail because date must be between 1 and 31.
This means it's not easy to use struct tm for differences. Instead use difftime as suggested by Sam.
Removing the salient bits from your code (and your declarations are in a very strange order)
struct tm* tm;
tm->tm_hour = hour_input;
tm->tm_min = min_input;
delta = mktime(tm) - ts;
So, tm is uninitialised and pointing to a random location. Moreover, you don't fill the structure in properly, and you have a random (probably invalid) year, month, day and seconds.
mktime will try to make this valid, but if seconds is sufficiently large it'll cause real havoc with your hours and minutes. Assuming the program doesn't crash before it gets that far. You didn't say what error you were getting.