I have one struct tm.
And I need to add some fixed interval (given in xx years, xx months, xx days)
to the tm struct.
Is there any standard function to do this?
The compiler I use is MSVC 2005 on Windows XP.
There are two functions which convert time formats:
mktime()
which convertsstruct tm
(representing local time) totime_t
.localtime()
which convertstime_t
to local time instruct tm
.
Interesing is the first one, which accepts out-of-range struct member values and as a side-product of conversion set them (and all others) appropriately. This may be used to correct field data values after arithmetic operations. However type of fields is int, so there may be an overflow (on 16 bit system), if e. g. you add number of seconds in the year.
So if you want to have actual dates this code would help (modified copy of answer from @pmg):
struct tm addinterval(struct tm x, int y, int m, int d) {
x.tm_year += y;
x.tm_mon += m;
x.tm_mday += d;
mktime(&x);
return x;
}
Also note about tm_isdst
member, care about it. Its value may cause time to shift forth and back when you jump over daylight time switch dates.
The standard addition operator works.
struct tm x;
/* add 2 years and 3 days to x */
x.tm_year += 2;
x.tm_mday += 3;
Edit: you can easily make a function
struct tm addinterval(struct tm x, int y, int m, int d) {
x.tm_year += y;
x.tm_mon += m;
x.tm_mday += d;
mktime(&x); /* normalize result */
return x;
}
EDIT: added mktime
to normalize result
I suggest to convert the date at hand to a number of days first. Adding an interval is trivial then. Afterwards, convert the number back to a date.
You can find algorithms for convernig a date to a number of days and back at e.g. http://alcor.concordia.ca/~gpkatch/gdate-algorithm.html
The other answers lead to highly unstable results depending on how your system initializes struct tm and whether mid-day time values were initialized properly.
If all you are interested in is changes in the date, while the time remains the same, then set tm_isdst
, tm_hour
, tm_sec
all to 0 before passing to mktime
. Better yet, grab their values before and reset them after for consistency (and if they were inconsistent before, they'll consistently remain so). Reusing code from other answers:
tm addinterval(tm t, int y, int m, int d)
{
auto hour = t.tm_hour;
auto min = t.tm_min;
auto sec = t.tm_sec;
// First we discover the DST Flag. By setting hour to 12
// we can assure the mktime does not shift the date
// because it will shift the hour!
t.tm_isdst = 0;
t.tm_hour = 12;
t.tm_min = 0;
t.tm_sec = 0;
mktime(&t);
// Now we can add the interval
t.tm_year += y;
t.tm_mon += m;
t.tm_mday += d;
mktime(&t);
// Now reset the mid-day time values
t.tm_hour = hour;
t.tm_min = min;
t.tm_sec = sec;
// Return struct tm while keeping mid-day time the same
// while the only values that changed are the date and perhaps isdst.
return t;
}
I wish it was simpler, but that's just how it has to be.
来源:https://stackoverflow.com/questions/4214429/addition-some-interval-to-tm-structs