C++ 如何将一天添加到从 time() 获得的时间
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/310363/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to add one day to a time obtained from time()
提问by Andrew Stein
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?
我有一个时间表示为自 UTC 1970 年 1 月 1 日午夜起经过的秒数(较早调用 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.
在大多数情况下,添加 24 * 60 * 60 有效,但如果夏令时在两者之间开启或关闭,则失败。换句话说,我主要想添加 24 小时,但有时会添加 23 或 25 小时。
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.
我希望 3 月 12 日、13 日...的时间也是上午 8 点。
The answer provided by FigBug pointed me in the right direction. But I had to use localtime instead of gmtime.
FigBug 提供的答案为我指明了正确的方向。但我不得不使用 localtime 而不是 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
这就是我想要的。使用 gmtime 给了我 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:
但是,请注意,所有日子都是星期六。此外,它会持续到 3 月 32 日、33 日等。如果我加入 mktime 函数,我就会回到我开始的地方:
#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:
好的,我已经尝试了 FigBug 的最新建议,即使用:
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:
而不是 asctime,但我得到了相同的结果。所以我猜我的库和/或编译器搞砸了。我在 cygwin 上使用 g++ 3.4.4。我将文件复制到 Solaris 5.8 并在那里使用 g++ 3.3 进行编译。我在那里得到了正确的结果!事实上,无论我使用 ctime 还是 asctime 进行输出,我都能得到正确的结果:
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.
我还在使用 g++ 3.4.6 的 Red Hut Linux 上得到了正确的结果(带有两个输出函数)。
So I guess that I have come across a Cygwin bug.
所以我想我遇到了一个 Cygwin 错误。
Thank you for all your help and advice....
谢谢大家的帮助和建议......
回答by Roland Rabien
use gmtime()to convert the time_tto a struct tm
使用gmtime()将time_t转换为struct tm
add one to the day (tm_mday)
给一天加一个 ( tm_mday)
use mktime()to convert the struct tmback to a time_t
使用mktime()将struct tm转换回time_t
see time.hfor more info
查看time.h了解更多信息
Edit:
编辑:
I just tried it, this works:
我刚试过,这有效:
int main()
{
time_t base = 1142085600;
for(int i = 0; i < 4; ++i) {
struct tm* tm = localtime(&base);
tm->tm_mday += i;
time_t next = mktime(tm);
std::cout << ctime(&next);
}
return 0;
}
回答by Andrew Selivanov
FigBug's solution will work almostevery time, but it needs DST fix: tm->tm_isdst = -1
FigBug 的解决方案几乎每次都有效,但需要修正 DST:tm->tm_isdst = -1
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.
tm_isdst 的正值或 0 值会导致 mktime() 最初分别假定夏令时在指定时间有效或无效。tm_isdst 的负值会导致 mktime() 尝试确定夏令时是否在指定时间生效。
(quoted from mktime spec)
(引用自mktime 规范)
int main()
{
time_t base = 1142085600;
for(int i = 0; i < 4; ++i) {
struct tm* tm = localtime(&base);
tm->tm_mday += i;
tm->tm_isdst = -1; // don't know if DST is in effect, please determine
// this for me
time_t next = mktime(tm);
std::cout << ctime(&next);
}
return 0;
}
Otherwise there will be a bug (example for Moscow Daylight Saving Time which starts 29 March 2009 01:59:59):
否则会出现错误(例如,莫斯科夏令时从 2009 年 3 月 29 日 01:59:59 开始):
int main()
{
// 28 March 2009 05:00:00 GMT ( local - 08:00 (MSK) )
time_t base = 1238216400;
std::time_t start_date_t = base;
std::time_t end_date_t = base;
std::tm start_date = *std::localtime(&start_date_t);
std::tm end_date = *std::localtime(&end_date_t);
end_date.tm_mday += 1;
// end_date.tm_isdst = -1;
std::time_t b = mktime(&start_date);
std::time_t e = mktime(&end_date);
std::string start_date_str(ctime(&b));
std::string stop_date_str(ctime(&e));
cout << " begin (MSK) (DST is not active): " << start_date_str;
cout << " end (MSD) (DST is active): " << stop_date_str;
}
Output:
输出:
begin (MSK) (DST is not active): Sat Mar 28 08:00:00 2009
end (MSD) (DST is active): Sun Mar 29 09:00:00 2009
回答by Pyrolistical
Just add 24*60*60. It shouldn't fail during DST, since UTC won't ever use DST.
只需添加 24*60*60。它不应该在 DST 期间失败,因为 UTC 永远不会使用 DST。
If it is failing, then you are not using UTC somewhere in your code. Remove the timezone dependence.
如果失败,则说明您没有在代码中的某处使用 UTC。删除时区依赖。
回答by Toon Krijthe
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.
我总是在保持时间戳为 UTC 并将它们转换为指定的时区(包括夏令时)时获得最佳结果。
This saves a lot of hassle like this (and makes your program independent of time zones.
这样可以省去很多麻烦(并使您的程序独立于时区。
回答by Howard Hinnant
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.
新答案需要 C++11/14<chrono>
和这个免费、开源的时区库。
Here's the code:
这是代码:
#include "tz.h"
#include <iostream>
int
main()
{
using namespace std::chrono;
using namespace date;
auto base = make_zoned("Pacific/Easter", sys_seconds{1142085600s});
for (int i = 0; i < 4; ++i)
{
std::cout << format("%a %b %d %T %Y %Z", base) << '\n';
base = base.get_local_time() + days{1};
}
}
The starts off by creating a zoned_time
by pairing whatever is the desired time zone with the Unix Time timestamp.
首先通过zoned_time
将所需的时区与 Unix 时间时间戳配对来创建一个。
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:
并且在时区的本地时间系统中添加 1 天,这将考虑夏令时。输出是:
Sat Mar 11 09:00:00 2006 -05
Sun Mar 12 09:00:00 2006 -06
Mon Mar 13 09:00:00 2006 -06
Tue Mar 14 09:00:00 2006 -06
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 backan hour, not forward. This is the time zone used for Chile, in the southern hemisphere, where one fallsback in the March time frame.
事实证明,这个输出并不完全是 OP 所说的他想要的(请求的输出是每天 08:00:00)。然而,我使用这个库来全面调查这个日期整个星球的时间转变。只有一个时区在这一天发生了变化:太平洋/复活节。那个过渡是向后移动一个小时,而不是向前移动。这是用于智利的时区,在南半球,其中一个落在后面在3月的时间框架。
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:
这可以通过以 UTC 而不是本地时间进行算术来证明。这是在一行中对上述程序的微小调整:
base = base.get_sys_time() + days{1};
Using base.get_sys_time()
, as opposed to base.get_local_time()
, causes the arithmetic to be done in "system time" which is UTC neglecting leap seconds. And now the output changes to:
使用base.get_sys_time()
,而不是base.get_local_time()
,会导致算术在“系统时间”中完成,即 UTC 忽略闰秒。现在输出更改为:
Sat Mar 11 09:00:00 2006 -05
Sun Mar 12 08:00:00 2006 -06
Mon Mar 13 08:00:00 2006 -06
Tue Mar 14 08:00:00 2006 -06