I have a time represented as the number of seconds elapsed since midnight, January 1, 1970, UTC (the results of an earlier call to time()). How do I add one day to this time?
Adding 24 * 60 * 60 works in most cases, but fails if the daylight saving time comes on or off in between. In other words, I mostly want to add 24 hours, but sometimes 23 or 25 hours.
To illustrate - the program:
#include <time.h>
#include <iostream>
int main()
{
time_t base = 1142085600;
for(int i = 0; i < 4; ++i) {
time_t time = base + i * 24 * 60 * 60;
std::cout << ctime(&time);
}
return 0;
}
Produces:
Sat Mar 11 08:00:00 2006
Sun Mar 12 09:00:00 2006
Mon Mar 13 09:00:00 2006
Tue Mar 14 09:00:00 2006
I want the times for March 12, 13, ... to also be 8 AM.
The answer provided by FigBug pointed me in the right direction. But I had to use localtime instead of gmtime.
int main()
{
time_t base = 1142085600;
for(int i = 0; i < 4; ++i) {
struct tm* tm = localtime(&base);
tm->tm_mday += i;
std::cout << asctime(tm);
}
return 0;
}
Give me:
Sat Mar 11 08:00:00 2006
Sat Mar 12 08:00:00 2006
Sat Mar 13 08:00:00 2006
Sat Mar 14 08:00:00 2006
Which is what I want. Using gmtime gives me the times at 14:00:00
However, note that all days are Sat. Also, it goes to March 32, 33, etc. If I throw in the mktime function I am back where I started:
#include <time.h>
#include <iostream>
int main()
{
time_t base = 1142085600;
for(int i = 0; i < 4; ++i) {
struct tm* tm = localtime(&base);
tm->tm_mday += i;
time_t time = mktime(tm);
std::cout << asctime(tm);
}
return 0;
}
Gives me:
Sat Mar 11 08:00:00 2006
Sun Mar 12 09:00:00 2006
Mon Mar 13 09:00:00 2006
Tue Mar 14 09:00:00 2006
What am I missing???
OK, I have tried out FigBug's latest suggestion that is to use:
std::cout << ctime(&time);
instead of asctime, but I get the same results. So I guess that my library and/or compiler is messed up. I am using g++ 3.4.4 on cygwin. I copied the files over to Solaris 5.8 and used g++ 3.3 there to compile. I get the correct results there! In fact I get the correct results whether I use ctime or asctime for output:
Sat Mar 11 08:00:00 2006
Sun Mar 12 08:00:00 2006
Mon Mar 13 08:00:00 2006
Tue Mar 14 08:00:00 2006
I also get the correct results (with both output functions) on Red Hut Linux with g++ 3.4.6.
So I guess that I have come across a Cygwin bug.
Thank you for all your help and advice....
use gmtime() to convert the time_t to a struct tm
add one to the day (tm_mday)
use mktime() to convert the struct tm back to a time_t
see time.h for more info
Edit:
I just tried it, this works:
I always had the best result with keeping the timestamps UTC and convert them to the specified timezone (including daylight saving) when you want to display the values.
This saves a lot of hassle like this (and makes your program independent of time zones.
New answer for a very old question.
Rationale for the new answer: There are now better tools to solve this problem, making the result less error-prone, easier to read, and actually more efficient by minimizing serial <-> field conversions.
The new answer requires C++11/14,
<chrono>
, and this free, open source, timezone library.Here's the code:
The starts off by creating a
zoned_time
by pairing whatever is the desired time zone with the Unix Time timestamp.That is formatted out in whatever the desired format.
And the addition of 1 day is done in the time zone's local time system, which will take daylight savings into account. The output is:
As it turns out, this output is not exactly what the OP stated he desired (the requested output is at 08:00:00 every day). However I used this library to fully investigate the entire planet's time transitions on this date. And there is only one time zone that had a transition on this date: Pacific/Easter. And that transition was to move back an hour, not forward. This is the time zone used for Chile, in the southern hemisphere, where one falls back in the March time frame.
This can be demonstrated by doing the arithmetic in UTC instead of in local time. This is a tiny adjustment to the above program in one line:
Using
base.get_sys_time()
, as opposed tobase.get_local_time()
, causes the arithmetic to be done in "system time" which is UTC neglecting leap seconds. And now the output changes to:FigBug's solution will work almost every time, but it needs DST fix: tm->tm_isdst = -1
(quoted from mktime spec)
Otherwise there will be a bug (example for Moscow Daylight Saving Time which starts 29 March 2009 01:59:59):
Output:
Just add 24*60*60. It shouldn't fail during DST, since UTC won't ever use DST.
If it is failing, then you are not using UTC somewhere in your code. Remove the timezone dependence.